问题
The code below renders a broken ring nicely in IE9 and FireFox, but fails part way round the circle in Chrome. Any ideas why, or what I can do to make it render in all browsers?
Cheers
(Chrome version 15.0.874.121)
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas1" width="201" height="201">No canvas in your browser...sorry...</canvas>
<script>
var canv = document.getElementById('canvas1');
var ctx = canv.getContext('2d');
var size = 201;
var centerX = size / 2;
var centerY = centerX;
var i;
var PI_180 = Math.PI / 180;
var fill = true;
size = size / 2;
ctx.translate(centerX, centerY);
// broken ring
for (i = 0; i < 360; i += 15) {
fill = !fill;
ctx.beginPath();
ctx.arc(0, 0, size * 0.86, i * PI_180, (i + 15) * PI_180, false);
ctx.arc(0, 0, size * 0.75, (i + 15) * PI_180, i * PI_180, true);
ctx.closePath();
if (fill) {
ctx.fill();
}
ctx.stroke();
}
ctx.translate(-centerX, -centerY);
</script>
</body>
</html>
回答1:
It works perfectly in Chrome 16, 17, and 18.
Chrome's canvas development is very fast paced and they've been breaking various things on and off for the past year. Problems of anti-aliasing, text distortion, and paths not showing up at all in some scales have all made it into the stable version of Chrome, where they might leave the (major) bugs for a week or two.
Whenever you suspect a bug in Chrome its always worth looking at how the dev and canary versions react. For these reasons I develop with both of them open, switching from one to the other if something is obviously broken. The funny thing is that you'll see bugs get made and fixed, and then one month later people will be complaining about the bug in the stable version!
回答2:
Here is a work-around. It's an alternative implementation of the arc method that I've made. It also approximates using quadratic beziers, but is much more precise in Chrome. The aberration is hardly noticeable for circles I've tried (up to twice the screen size):
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
if (is_chrome) {
CanvasRenderingContext2D.prototype.arc = function(x, y, radius, startAngle, endAngle, anticlockwise) {
// Signed length of curve
var signedLength;
var tau = 2 * Math.PI;
if (!anticlockwise && (endAngle - startAngle) >= tau) {
signedLength = tau;
} else if (anticlockwise && (startAngle - endAngle) >= tau) {
signedLength = -tau;
} else {
var delta = endAngle - startAngle;
signedLength = delta - tau * Math.floor(delta / tau);
// If very close to a full number of revolutions, make it full
if (Math.abs(delta) > 1e-12 && signedLength < 1e-12)
signedLength = tau;
// Adjust if anti-clockwise
if (anticlockwise && signedLength > 0)
signedLength = signedLength - tau;
}
// Minimum number of curves; 1 per quadrant.
var minCurves = Math.ceil(Math.abs(signedLength)/(Math.PI/2));
// Number of curves; square-root of radius (or minimum)
var numCurves = Math.ceil(Math.max(minCurves, Math.sqrt(radius)));
// "Radius" of control points to ensure that the middle point
// of the curve is exactly on the circle radius.
var cpRadius = radius * (2 - Math.cos(signedLength / (numCurves * 2)));
// Angle step per curve
var step = signedLength / numCurves;
// Draw the circle
this.lineTo(x + radius * Math.cos(startAngle), y + radius * Math.sin(startAngle));
for (var i = 0, a = startAngle + step, a2 = startAngle + step/2; i < numCurves; ++i, a += step, a2 += step)
this.quadraticCurveTo(x + cpRadius * Math.cos(a2), y + cpRadius * Math.sin(a2), x + radius * Math.cos(a), y + radius * Math.sin(a));
}
}
Edit: Made whatwg conformant (like Firefox, Safari). Chrome also seem to get circles wrong for certain angles.
回答3:
We can fix it with ctx.clip().
For ex:
ctx.save();
// clipping
ctx.beginPath()
ctx.arc(x, y, radius, 0, 6.28, true);
ctx.clip();
// drawing
ctx.beginPath();
ctx.arc(x, y, radius, 0, 6.28, true);
ctx.fill();
ctx.restore();
ctx.stroke();
Yours Keyten / Newcomer :)
来源:https://stackoverflow.com/questions/8603656/html5-canvas-arcs-not-rendering-correctly-in-google-chrome