Html 5 canvas arc issue - arc gets distorted - html

I am using the following code to draw a arc using html5 canvas.
This is my code
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="1000" height="550" style="padding-top:20px;border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(293.5, 183.4375, 186.70352183177323, 4.71238898038469, 6.8067840827778845);
ctx.arc(293.5, 190.4375, 93.40238454336179, 6.8067840827778845, 4.71238898038469, true);
ctx.closePath();
ctx.strokeStyle = "white";
ctx.lineWidth = 1;
ctx.fillStyle = "red";
ctx.fill();
ctx.stroke();
</script>
</body>
</html>
This is how the arc looks. IF observed closely, the top left end of the outer arc has a slight flat surface. Could anyone please tell me why this occurs? Why isnt the arc smooth?

The second arc has a rayon greater than the center y position. It's out of the canvas element.
You can see the change here : https://jsfiddle.net/o1rdkj8u/
ctx.arc(293.5, 183.4375, 183.43753/*186.70352183177323*/, 4.71238898038469, 6.8067840827778845);
ctx.arc(293.5, 183.4375/*190.4375*/, 93.40238454336179, 6.8067840827778845, 4.71238898038469, true);
Furthermore, your arcq don't have the same center. If it's not what you want, have a look at it.

Strokes are drawn half-inside and half-outside your arc.
The half-outside part of your arc is being cut off by the top of the canvas.
So if you want the stroke to fully fit inside the canvas then be sure you subtract half the context's linewidth.
radius = radius - context.lineWidth/2;
So for your arc:
ctx.arc(
293.5, 183.4375,
186.70352183177323 - ctx.lineWidth/2, // subtract half linewidth
4.71238898038469, 6.8067840827778845
);

Related

how to apply border radius to canvas element like div to make it circle?

i want to make canvas element circle like other any div but its not working. here is my code . please have a loot at code. what am doing wrong with border-radius propoerty ?
<canvas id="myCanvas" width="200" height="200" style="background-color:red;border:1px solid;border-radius:50%">
border-radius property is not working like i apply on div. actually, i want to create rectangle , square and circle of canvas. please anyone can help me
`
Your code looks fine. Border radius should do it however if you are using JavaScript this method might help:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(100, 75, 50, 0, 2 * Math.PI);
ctx.stroke();

Why are artifacts visible in a scaled html5 canvas?

I've seen this and this discussion about removing antialiasing in canvases, but I don't think this is the same thing.
After scaling an html5 canvas by an arbitrary value (i.e., making it responsive), I've noticed that if I draw two rectangles of the same size and in the same location, the edges of the scaled side of the first rectangle remain visible.
I've included an example snippet where I draw a grey rectangle, then draw an red rectangle on top of it. There's a one-pixel red vertical line on the left and right edges of the grey rectangle. I know it may seem trivial, but it's very noticeable in my situation.
How do I fix this? Thanks!
var example = document.getElementById("example");
var ctx = example.getContext('2d');
ctx.scale(1.13,1);
ctx.fillStyle = "LightGrey";
ctx.fillRect(10,10,50,30);
ctx.fillStyle = "Black";
ctx.font = "20px Arial";
ctx.fillText("< Looks good.",70,30);
ctx.fillStyle = "Red";
ctx.fillRect(10,50,50,30);
// This light grey rectangle should completely cover the previous red one, but it doesn't!
ctx.fillStyle = "LightGrey";
ctx.fillRect(10,50,50,30);
ctx.fillStyle = "Black";
ctx.font = "20px Arial";
ctx.fillText("< Do you see red?",70,70);
<canvas id="example"></canvas>
You are scaling the transform matrix by a factor of 1.13 on the X axis.
So your coordinate 10, will actually end up on at coordinate 11.3 on the real pixels matrix.
You can't draw on fraction of pixels, so indeed antialiasing will kick in here.
So why does the first one looks better?
Because the mix between grey and white* is more neutral than the one between red grey and white. But even your first rect is antialiased.
Just zoom in your canvas and you'll see it, there is a one pixel band on both sides that is actually semi-transparent.
* "White" here is the one of the page's background
var example = document.createElement("canvas");
var ctx = example.getContext('2d');
ctx.scale(1.13,1);
ctx.fillStyle = "LightGrey";
ctx.fillRect(10,10,50,30);
ctx.fillStyle = "Red";
ctx.fillRect(10,50,50,30);
ctx.fillStyle = "LightGrey";
ctx.fillRect(10,50,50,30);
// draw bigger with no antialiasing
var z_ctx = zoomed.getContext('2d');
zoomed.width = example.width * 10;
zoomed.height = example.height * 10;
z_ctx.imageSmoothingEnabled = false;
z_ctx.drawImage(example, 0,0, zoomed.width, zoomed.height);
<canvas id="zoomed"></canvas>
So how to avoid this?
Well simply avoid filling at non integer pixel coordinates. This means you have to be constantly aware of your context transformation matrix too, not only of the values you pass to the drawing functions.
(Ps: also remember that stroke is an even eviler beast since it start drawing from the middle of the line, so in this case, you even have to take into considerations the lineWidth, see this Q/A on the matter).

How can I draw a line with lineTo in HTML5 that has angles to match the Unit Circle?

If I have this,
var canvas = document.getElementById("my-canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = '#f00';
ctx.beginPath();
ctx.moveTo(25, 25);
ctx.lineTo(150, 25);
ctx.rotate(Math.PI*7/4); //315 degrees
ctx.lineTo(150,90);
ctx.stroke();
It does not draw the line (the ctx.lineTo(150,90);) at the angle I thought it would which is from the end of the first lineTo at 25,25 to a 150,90 at a 45 degree angle. If I use -Math.PI*7/4 I get what looks like a 45 degree angle, but it points the wrong way. Math.PI*5/4 goes the wrong way or rotation.
My question asks about the Unit Circle. I don't really need them all at once, just the ability to know how to draw them if I need them.
The canvas is rotating this way:
Consider the following example, without the y offset:
Given by the code:
var canvas = document.getElementById("my-canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = '#f00';
ctx.beginPath();
ctx.moveTo(25, 0);
ctx.lineTo(250, 0);
ctx.rotate(45*Math.PI/180); //45 degrees
ctx.lineTo(150,0);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0,0);
ctx.strokeStyle = '#ff0000';
ctx.lineTo(350,0);
ctx.font = "30px Arial";
ctx.fillText("New x axis",100,50);
ctx.stroke();
The red line is the new x axis, and the black line touches it exactly at a distance of 150 from the origin.
Now overlaying the same red line with your coordinates (and rotating by 45 degrees, so that it doesn't go off screen), we get
The black line ends at a point which is indeed (150,90), however at the new coordinate system. JSFiddle here
If you want the angle between the two line segments to be exactly what you pass in rotate(...), then keep drawing "horizontal" lines, but translate the origin to the end of each line segment, so you rotate about this point, not the top-left corner, using ctx.translate(<current point>). For example: https://jsfiddle.net/Douma37/65z1p38z/ (this goes off canvas, but has minimal interferance with your code).
Hope that helps!

Canvas inner stroke

I studied strokeStyle a bit but I cant find how to control the position of the stroke from inner/center/outer. It seems all stroke is outside the rectangle I draw. Is there anyway make the stroke be inner? (or even centered on the rectangle bounds)?
Thanks
Hope this helps!
Instead of doing:
ctx.fill();
ctx.stroke();
DO:
ctx.save();
ctx.clip();
ctx.lineWidth *= 2;
ctx.fill();
ctx.stroke();
ctx.restore();
Edit
For me I believe this works because the clip method removes any fill and stroke around the already present fill area, meaning the only place the stroke can go is on the inside because else it would be clipped off.
The default stroke do use centered stroke but there is unfortunately no parameter to control the alignment of the stroke so you would either have to calculate an offset value for the rectangle's position and size, or combine two rectangles and use for example the fill-rule evenodd:
var ctx = c.getContext("2d");
// default centered
ctx.lineWidth = 10;
ctx.strokeRect(10, 10, 100, 100);
ctx.lineWidth = 1;
ctx.strokeStyle = "red";
ctx.strokeRect(10, 10, 100, 100); // show main path
// inner
ctx.rect(150, 10, 100, 100);
ctx.rect(150+10, 10+10, 100-20, 100-20); // offset position and size
ctx.fill("evenodd"); // !important
ctx.strokeRect(150, 10, 100, 100);
<canvas id=c></canvas>
This answer "Draw outer and inner border around any canvas shape" shows how to use masking and compositing to precisely control the offset, both inwards and outwards of a stroke without the need to manipulate paths. It can be used for any canvas path no matter how complex.

HTML5 canvas adding dots/circles to canvas line - can i combine lines and circles to 'join the dots'?

I've made 2 Line paths with 'lineTo' which change direction at various points - these have plotted fine. These lines are rendered by canvas, not svg.
I need to add circles at the points in the lines where they change direction, namely at the lineTo points e.g: context.lineTo(149, 50). This would look like joining dots.
I don't know how to add these dots to the lines or if it is possible - can anyone advise please?
Thanks in advance. See below for the markup:
<div class="wrapper">
<canvas id="myCanvas" width="300" height="300"></canvas>
</div>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// attributes
context.lineWidth = 2;
context.lineJoin = 'round';
// left line
context.beginPath();
context.moveTo(10, 20);
context.lineTo(149, 50);
context.lineTo(50, 100);
context.lineTo(149, 150);
context.lineTo(109, 200);
context.strokeStyle = "red";
context.stroke();
// right line
context.beginPath();
context.moveTo(10, 20);
context.lineTo(109, 50);
context.lineTo(60, 110);
context.lineTo(109, 150);
context.lineTo(85, 200);
context.strokeStyle = "blue";
context.stroke();
</script>
I don't know if there is a specific function for drawing dots at turning points of a path, but why not drawing circles where you want them by yourself?
You can simply draw circles on the direction-changin-points by using the arc() method (here well explained). As you already know the coordinates from the lineTo() points, this should be a piece of cake ;)