Is there an easy way to draw stroke inside a circle (without drawing 2 circles and similar workarounds)? If I do it this way:
context.beginPath();
context.arc(200, 200, 93, Math.PI / 2, Math.PI, true);
context.fillStyle = '#FF6A6A';
context.fill();
context.lineWidth = 20;
context.strokeStyle = '#FF0000';
context.stroke();
I get this:
The stroke is partially drawn outside the figure (marked by green circles) while I need it inside.
You should change the radius to compensate for the line width:
context.beginPath();
context.arc(200, 200, 93, Math.PI / 2, Math.PI, true);
context.fillStyle = '#FF6A6A';
context.fill();
context.lineWidth = 20;
context.strokeStyle = '#FF0000';
context.beginPath();
// the radius of 93 - half the line width
context.arc(200, 200, 93-10, Math.PI / 2, Math.PI, true);
context.stroke();
JS Bin: http://jsbin.com/qamuwumiri/edit?html,js,output
Related
This question already has an answer here:
All html canvas shapes are given the color of the last object added
(1 answer)
Closed 2 years ago.
I am drawing a filled ellipse (using arc()) on the javascript canvas:
ctx.arc(centerX, centerY, dotDiameter / 2, 0, 2 * Math.PI, false);
ctx.fillStyle = color1;
ctx.fill();
I then want to draw a line, that is clipped to this ellipse, in a different color.
ctx.clip(); // Clip to the ellipse
ctx.strokeStyle = color2;
ctx.moveTo(centerX - dotRadius, centerY);
ctx.lineTo(centerX + dotRadius, centerY);
ctx.stroke();
However, the ellipse is also stroked with color2.
How can I clip lines to my ellipse, but not have the ellipse stroked? Is there a way to remove the ellipse (aka arc) from the canvas after I call clip()?
Thanks!
(FYI, this is an oversimplification of my code. The lines that stroked are more complicated than a single horizontal line and the lines do need to be clipped.)
We can calculate a point on the perimeter of an ellipsis with some basic trigonometry...
ctx.moveTo(x, y);
x += radiusX * Math.cos(lineangle)
y += radiusY * Math.sin(lineangle)
ctx.lineTo(x, y);
See code snippet below, I'm drawing an ellipse and a line from center to edge.
ctx = document.getElementById('c').getContext('2d');
ctx.lineWidth = 2;
function draw(x, y, radiusX, radiusY, lineangle, color1, color2) {
ctx.beginPath()
ctx.ellipse(x, y, radiusX, radiusY, 0, 0, 2 * Math.PI, false);
ctx.fillStyle = color1;
ctx.fill();
ctx.beginPath()
ctx.strokeStyle = color2;
ctx.moveTo(x, y);
x += radiusX * Math.cos(lineangle)
y += radiusY * Math.sin(lineangle)
ctx.lineTo(x, y);
ctx.stroke();
}
angle = 0
function loop() {
ctx.clearRect(0,0, 500, 500);
draw(80, 80, 70, 50, angle, "red", "lime")
draw(240, 60, 80, 30, angle*0.7, "black", "cyan")
draw(360, 80, 30, 70, angle*2, "white", "black")
angle += 0.05
}
setInterval(loop, 100)
<canvas height="160" width="500" id="c">
I would like to animate a circle into a line with the radius equaling the width, and I am wondering how I can do this with an Arc? Or perhaps there is a better way?
From
To
Here's my arc:
function drawStar(x,y,size,scale,opacity,ctx){
ctx.save();
ctx.beginPath();
ctx.arc(x,y,size+scale,0,size+scale * Math.PI,false);
ctx.globalAlpha = opacity
ctx.closePath();
setFillStyle('rgb(255,237,219)',ctx);
ctx.fill()
ctx.restore();
}
I tried using ctx.scale(n,1), however it does not keep the same radius(width) and it scales the collection of arcs as a whole (zoom in effect).
Use instead a wide line-width value with "round" lineCap and stroke():
var ctx = c.getContext("2d");
ctx.lineWidth = 50;
ctx.lineCap = "round";
ctx.moveTo(45 , 25);
ctx.lineTo(45.5, 25); // in IE11 this must be slightly offset
ctx.moveTo( 45, 100);
ctx.lineTo(150, 100);
ctx.stroke();
<canvas id=c></canvas>
Remember beginPath() for animation.
You can use Bezier Curves to 'transform' your arc.
There's some math involved in calculating the perfect ends of your stretched circle but I guessed and tweaked my numbers.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(40, 20);
ctx.lineTo(100, 20);
ctx.bezierCurveTo(130, 20, 130, 60, 100, 60);
ctx.lineTo(40, 60);
ctx.bezierCurveTo(10, 60, 10, 20, 40, 20);
ctx.stroke();
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.moveTo(40, 80);
ctx.bezierCurveTo(68, 80, 68, 120, 40, 120);
ctx.bezierCurveTo(12, 120, 12, 80, 40, 80);
ctx.fill();
ctx.stroke();
<canvas id="myCanvas"></canvas>
You could draw the left and right halves of a circle using arc, then do a fillRect in between to connect them.
Edit: To elaborate on what I said earlier:
function init() {
let canvas = document.getElementById('myCanvas');
canvas.width = 400;
canvas.height = 400;
canvas.style.width = "400px";
canvas.style.height = "400px";
let ctx = canvas.getContext("2d");
function fillArc(ctx, cx, cy, r, startDeg, endDeg) {
ctx.beginPath();
ctx.arc(cx, cy, r, startDeg * Math.PI / 180, endDeg * Math.PI / 180);
ctx.fill();
}
function fillOval(ctx, cx, cy, r, sideLength, skipFirstArc) {
if (!skipFirstArc) {
fillArc(ctx, cx, cy, r, 90, 270);
}
ctx.fillRect(cx, cy - r, sideLength, r * 2);
fillArc(ctx, cx + sideLength, cy, r, 270, 90);
}
let sideLength = 0;
ctx.fillStyle = 'red';
function animateOval() {
if (sideLength === 100) {
ctx.clearRect(0, 0, 400, 400);
}
else {
fillOval(ctx, 30, 30, 25, sideLength, sideLength > 0);
}
++sideLength;
if (sideLength > 100) {
sideLength = 0;
}
}
setInterval(animateOval, 16);
}
Here's a Plunker with the above code running: http://plnkr.co/edit/vNqoUjPKg2lqC7JtYuEb?p=preview
I want to create the logo above using the html5 canvas but at the end of the day, it displayed only a triangle.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Coa</title>
</head>
<body>
<canvas id="logo" width="900" height="80">
<h1>COA</h1>
</canvas>
<script>
//function that draw the logo. I create a JavaScript function for drawing the
var drawLogo = function(){
var canvas = document.getElementById('logo');
var context = canvas.getContext("2d");
//applying gradient
var gradient = context.createLinearGradient(0, 0, 0, 40);
gradient.addColorStop(0, "#aa0000");
gradient.addColorStop(1, "#ff0000");
// use the strokepath,beginPath() and closePath() methods to start drawing a line, stroke and close when finish
context.fillStyle = gradient;
context.strokeStyle = gradient;
context.lineWidth = 2;
context.beginPath();
context.moveTo(0, 40);
context.lineTo(30, 0);
context.lineTo(60, 40);
context.lineTo(285, 40);
context.fill();
context.closePath();
//adding text
context.font = "italic 40px 'Arial'";
context.fillText("Coa", 60,36);
//Moving the Origin so as to fit the square under the triangle
context.save();
context.translate(20, 20);
context.fillRect(0, 0, 20, 20);
//use a path to draw the inner triangle
context.fillStyle("#ffffff");
context.strokeStyle("#ffffff");
context.lineWidth = 2;
context.beginPath();
context.moveTo();
context.lineTo(0, 20);
context.lineTo(10, 0);
context.lineTo(20, 20);
context.lineTo(0, 20);
context.fill();
context.closePath();
context.restore();
};
//Then invoke this method after first checking for the existence of the <canvas> element
var canvas = document.getElementById("logo");
if(canvas.getContext){
drawLogo();
}
</script>
</body>
</html>
I don't know what am doing wrong that makes the the code not working properly.
I have searched the internet and couldn't find anything tangible that solve the problem. Any help will be appreciated.
UPDATE: Try this:
if (document.getElementById('logo')) {
var canvas = document.getElementById("logo");
var context = canvas.getContext("2d");
//applying gradient
var gradient = context.createLinearGradient(0, 0, 0, 40);
gradient.addColorStop(0, "#aa0000");
gradient.addColorStop(1, "#ff0000");
context.strokeStyle = gradient;
context.fillStyle = gradient;
context.lineWidth = 2;
context.beginPath();
context.moveTo(0, 40);
context.lineTo(30, 0);
context.lineTo(60, 40);
context.lineTo(285, 40);
context.stroke();
context.fillRect(20, 20, 20, 20);
context.beginPath();
context.moveTo(30, 20);
context.lineTo(37, 28);
context.lineTo(35, 40);
context.lineTo(25, 40);
context.lineTo(23, 28);
context.lineTo(30, 20);
context.fillStyle="#ffffff";
context.fill();
context.fillStyle="#000000";
context.font = "italic 40px Arial";
context.fillText("coa", 60,36);
}
I moved around some of your code and it works now for me on Firefox. It looks like you haven't put the pentagon in the canvas yet. Here is a JSFillde:
https://jsfiddle.net/o289buyk/
if (document.getElementById('logo')) {
var canvas = document.getElementById("logo");
var context = canvas.getContext("2d");
//applying gradient
var gradient = context.createLinearGradient(0, 0, 0, 40);
gradient.addColorStop(0, "#aa0000");
gradient.addColorStop(1, "#ff0000");
// use the strokepath,beginPath() and closePath() methods to start drawing a line, stroke and close when finish
context.fillStyle = gradient;
context.strokeStyle = gradient;
context.lineWidth = 2;
context.beginPath();
context.moveTo(0, 40);
context.lineTo(30, 0);
context.lineTo(60, 40);
context.lineTo(285, 40);
context.fill();
context.closePath();
//adding text
context.font = "italic 40px 'Arial'";
context.fillText("Coa", 60,36);
//Moving the Origin so as to fit the square under the triangle
context.save();
context.translate(20, 20);
context.fillRect(0, 0, 20, 20);
//use a path to draw the inner triangle
context.fillStyle("#ffffff");
context.strokeStyle("#ffffff");
context.lineWidth = 2;
context.beginPath();
context.moveTo();
context.lineTo(0, 20);
context.lineTo(10, 0);
context.lineTo(20, 20);
context.lineTo(0, 20);
context.fill();
context.closePath();
context.restore();
}
I have a project to do and I cannot do it until I understand how moving object inside canvas work.
I need to move one of the objects below by 50pixels to right.
Anyone willing to help me is greatly appreciated.
Meanwhile thank you very much in advance for your help or suggestions.
function canvasOneShape() {
//refers to the html canvasone id
var canvas = document.getElementById("canvasOne");
this.canvasOne.width = 945;
this.canvasOne.height = 650;
// draws the canvas in 2d
var ctx = canvas.getContext("2d");
// Set the fill colour to blue.
ctx.fillStyle = "blue"; //used like this instead of rgb due personal preference:)
// Create a filled rectangle at co-ordinates (10,10)
// with height and width set to 100.
ctx.fillRect(10, 10, 250, 330); //
// Here I draw the square
// Set the canvas up for drawing in 2D.
// Set the fill colour to blue.
ctx.fillStyle = "rgba(244, 244, 189,.5)";
ctx.fillRect(10, 50, 330, 250);
//draw my first circle
var midXone = canvas.width / 2; //x location
var midXtwo = canvas.height / 2; //y location
var radius = 60; //circle radius
ctx.beginPath();
ctx.arc(midXone, midXtwo, radius, 0, 2 * Math.PI, false);
ctx.fillStyle ="rgba(89, 192, 227,.4)";
ctx.fill();
ctx.lineWidth = 5;
ctx.strokeStyle = '#003300';
ctx.stroke();
//draw the second circle
var midX = canvas.width / 2.35; //x location
var midY = canvas.height / 2.35; //y location
var radius = 50; //circle radius
ctx.beginPath();
ctx.arc(midX, midY, radius, 0, 2 * Math.PI, false);
ctx.fillStyle ="rgba(66, 244, 89,.4)";
ctx.fill();
ctx.lineWidth = 5;
ctx.strokeStyle ="rgba(255, 244, 9,.4)";
ctx.stroke();
//draw Square with circle inside
//square
ctx.fillStyle = "rgb(222, 33, 51)";
ctx.fillRect(550, 20, 300, 300);
//circle
ctx.beginPath();
ctx.arc(700, 170, 150, 0, 2 * Math.PI, false);
ctx.fillStyle ="rgba(66, 244, 89,.4)";
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#f44242';
ctx.stroke();
//The Pacman object
var radius = 100; //circle radius
var x = 100;
var y = 500;
ctx.beginPath();
ctx.arc(120, 500, radius, 1.85 * Math.PI, .15 * Math.PI, true);
//Draw mouth
ctx.lineTo(120, 500);
ctx.closePath();
ctx.fillStyle = "rgb(255, 255, 0)";
ctx.fill();
ctx.lineWidth = 5;
ctx.strokeStyle = 'rgb(0,0,0)';
ctx.stroke();
//draw eye
ctx.beginPath();
ctx.arc(x + 40, y - 40, 10, 0 * Math.PI, 2 * Math.PI, true);
ctx.fillStyle = "rgb(0,0,0)";
ctx.fill();
}
there are no layers or objects on a canvas(it's just a single layer of pixels), so, if you draw something, you overwrite what's underneath it. to move something to the right, you will need to have a function to draw everything behind it, and then variables to store the location (x and y) of the objects you want to move.
then, to move it, you clear the canvas with
ctx.clearRect(0, 0,width of canvas, height height of canvas);,
call the background function to draw everything behind it again, and the redraw your object in a different location.
Let say I have x, y, width and height. I need to draw a inclined/tilted Rectangle at particular angle. I cannot use context.rotate. Because it is changing other shapes of canvas.
You can use context.rotate, you just have to undo the rotation before you draw the other shapes. Like this:
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
context.beginPath();
context.rect(88, 50, 200, 100);
context.fillStyle = "#8ED6FF";
context.fill();
context.lineWidth = 5;
context.strokeStyle = "black";
context.stroke();
context.rotate(0.5);
context.beginPath();
context.rect(138, 120, 200, 100);
context.fillStyle = "#FE8E9D";
context.fill();
context.lineWidth = 5;
context.strokeStyle = "black";
context.stroke();
context.rotate(-0.5);
context.beginPath();
context.rect(188, 190, 200, 100);
context.fillStyle = "#FEEF8E";
context.fill();
context.lineWidth = 5;
context.strokeStyle = "black";
context.stroke();