EDIT: This bug was fixed in version 38.
A recent version of Chrome introduced an issue in an application I maintain. I'm not sure if this is one of those weird "seems wrong but is actually correct" issues or if it's an honest-to-god bug, but it only presents in recent versions of Chrome (it started happening about a month ago, I'm not sure exactly which version introduced it)
The bug presents when using the context fill() method on certain paths that are drawn using the context arc() method. Rather than drawing a filled arc, what is filled is an oddly-shaped polygon.
Here's a demonstration of what I mean -- the shape in the upper right should be a filled arc:
var ctx = document.getElementById('cvs').getContext('2d');
// draw stroked arc
ctx.beginPath();
ctx.arc(75, 75, 50, 0, Math.PI/2);
ctx.lineTo(125, 125);
ctx.closePath();
ctx.stroke();
// draw filled arc
ctx.beginPath();
ctx.arc(225, 75, 50, 0, Math.PI/2);
ctx.lineTo(275, 125);
ctx.closePath();
ctx.fill();
// draw stroked triangle
ctx.beginPath();
ctx.moveTo(125, 225);
ctx.lineTo(75, 275);
ctx.lineTo(125, 275);
ctx.closePath();
ctx.stroke();
// draw filled triangle
ctx.beginPath();
ctx.moveTo(275, 225);
ctx.lineTo(225, 275);
ctx.lineTo(275, 275);
ctx.closePath();
ctx.fill();
<div><canvas id="cvs" width="300" height="300" style="border: solid black 1px"></canvas></div>
My question is this: is there a workaround for this issue? Preferably one that doesn't require me to write my own filled-arc renderer.
I do see this bug on Chrome 37.0.2062.124 on OS X. This may or may not be related to the bug described here, which is supposedly to be fixed in Chrome 38.
As a workaround, rotating a few degrees and immediately rotating it back before filling the arc seems to work.
// draw filled arc
ctx.beginPath();
ctx.arc(225, 75, 50, 0, Math.PI/2);
ctx.lineTo(275, 125);
ctx.closePath();
ctx.rotate(1*Math.PI/180); // Rotate 1 degree
ctx.rotate(-1*Math.PI/180); // Reverse rotation
ctx.fill();
Here's a fiddle demonstrating the workaround: http://jsfiddle.net/ejacpd1w/1/
Related
I'm trying to do a canvas where you can draw a line with your mouse and this line is being mirrored while drawing. So at the end you got a symmetry drawing effect. I wrote a draw function and included the transform and scale attribute. Sadly now the line has small little gaps and is not fluent anymore.
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.translate(canvas.width, 0);
ctx.scale(-1, 1);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
See screenshot here
Without the translate() and scale() attribute the line is clear, as you can see here. Do you have any idea why the line is dotted and how I can fix that?
This is because every time you move the mouse, you are only drawing one line, either "normal" or "mirrored" but not both. You can see that your "dots" actually correspond to the dashes of the other side.
The switching happens because you apply the canvas transform once per draw call, but don't reset it, so at first mouse move, you mirror the context and at second one you'll finally draw mirrored and then switch back for the next move.
To do what you want, you could keep all your points in an Array, clear your context at the beginning of every frame and redraw the lines completely twice, once normal, and once mirrored.
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
// trace in normal mode
points.forEach(({x, y}) => ctx.lineTo(x, y));
// mirror
ctx.translate(canvas.width, 0);
ctx.scale(-1, 1);
// move to first point so we can paint in a single path
ctx.moveTo(points[0].x, points[0].y);
// trace all the points mirrored
points.forEach(({x, y}) => ctx.lineTo(x, y));
// paint
ctx.stroke();
// reset the context transform
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
I am playing around with multiple clipped shapes on a canvas like this:
But (only in Chrome), if you increase the width or height of that canvas element by even 1px, it doesn't render all the shapes.
Any ideas? Have a look at the jsfiddle:
https://jsfiddle.net/entozoon/6fqq0567/
The code is pretty straight forward:
for (i=1;i<=5;i++) {
ctx.save();
// clipping mask
ctx.beginPath();
ctx.arc(50 * i, 50, 20, 0, Math.PI * 2, true);
ctx.closePath();
ctx.clip();
// shape to be clipped
ctx.beginPath();
ctx.fillStyle = "red";
ctx.arc(50 * i, 70, 20, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
ctx.restore();
}
-- UPDATE --
It turns out that the problem is to do with 2D canvas acceleration. If I disable
'Accelerated 2D canvas' in chrome://flags that fixes it.
This is definitely NOT a solution though!
Must be a graphics issue..? (yes I have up-to-date drivers, chrome, etc.)
I have the same issue on Win10, chrome 50.0.2661.75 m. The issue started when I updated from 49, and is not reproducible in all computers with the same OS and Chrome version configurations, so probably it has to do with graphics hardware, I got an AMD Radeon HD6570. But on latest canary chrome 52.0.2713.0, the issue is not reproducible, so I can deduce that is a hardware handling issue brought on chrome 50 version. (I can't comment the question, so I wrote here some extra info that can be useful)
I am trying to draw a circle on canvas. With Firefox it looks like a circle, but with Chrome it looks deformed. Here is my JavaScript code:
ctx.fillStyle = "brown";
ctx.beginPath();
ctx.arc(480,250,100, 0, 2*Math.PI);
ctx.closePath();
ctx.fill();
Does anyone know how to fix it? I have latest version of Chrome.
So I have a rotating canvas element which has an arc drawn inside it (the smaller planet):
http://jsfiddle.net/neuroflux/9L689/4/ (updated)
But I can't seem to get the anti-aliasing on the edges of the smaller planet smoother - any ideas?
Cheers!
edit: is there a way to increase the number of iterations used within an arc?
Your problem is not that the arc doesn't have enough points, but that in Chrome the .clip() operation doesn't use anti-aliasing to produce the clipping path.
See Chromium Issues 7508 and 132442
To see this in action, look at http://jsfiddle.net/alnitak/YMtdZ/ in Chrome.
markup:
<canvas id="c" width="600" height="300" />
code:
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'black';
ctx.save();
ctx.beginPath();
ctx.arc(150, 150, 140, 0, 2 * Math.PI);
ctx.clip();
ctx.fillRect(0, 0, 600, 300);
ctx.restore();
ctx.beginPath();
ctx.arc(450, 150, 140, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
The left-hand circle is drawn with clipping, and is aliased. The right-hand circle is drawn "normally", and is anti-aliased.
FWIW, in Firefox and Safari both images look the same. I can't test it on IE.
The only work around I can imagine (until Chrome gets fixed) would be to render the image off-screen into a canvas 3 or 4 times larger, and then copy that with down-sampling into the displayed canvas.
I have found similar questions out there, but no answer. I have sketched a circle like so
ctx.strokeStyle='rgb(0,0,0)';
ctx.lineWidth=10;
ctx.beginPath();
ctx.arc(100,100,45,0,Math.PI*2,true);
ctx.closePath();
ctx.stroke();
which gives a circle situated at (100,100) with radius 45, plus 5 for the linewidth, making it a circle of radius 50. Now, I want to sketch the exact same circle, but another color, and only 1/4 of the original circumfrance (think the XBOX 360 red ring of doom). So I tried this
ctx.strokeStyle='rgb(0,250,0)';
ctx.lineWidth=10;
ctx.beginPath();
ctx.arc(100,100,45,0,Math.PI/2,true); //use 1/4 of original angle
ctx.closePath();
ctx.stroke();
But that has the really annoying aspect of connecting the first and last points (sometimes I wonder who created the canvas element, like when embedding text, but don't get me started on that...)
I've commented out the line you don't want. By calling closePath(), you are closing the path of your arc.
Example
JavaScript
ctx.strokeStyle='rgb(0,250,0)';
ctx.lineWidth=10;
ctx.beginPath();
ctx.arc(100,100,45,0,Math.PI/2,true); //use 1/4 of original angle
//ctx.closePath();
ctx.stroke();
jsFiddle.