HTML5 canvas arcs not rendering correctly in Google Chrome

笑着哭i 提交于 2019-12-11 02:14:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!