【问题标题】:How to correctly draw a circle with gaps in a canvas element?如何在画布元素中正确绘制有间隙的圆圈?
【发布时间】:2014-03-07 21:24:46
【问题描述】:

我想画一个圆圈。但是,并非如此。我想要一系列暗示一个完整圆圈的弧(段)。它会旋转,它会很棒。但我显然做错了什么。 Please, check this fiddle: http://jsfiddle.net/utWdM/

function draw() {
    var canvas = document.getElementById("canvas");
    if (canvas.getContext) {
        var ctx = canvas.getContext("2d");
        ctx.lineWidth = 15;
        ctx.strokeStyle = 'hsla(111, 56%, 50%, 0.67)';
        ctx.beginPath();

        ctx.arc(250, 250, 100, 0, Math.PI * 8 / 30);
        ctx.moveTo(250, 250);
        ctx.arc(250, 250, 100, Math.PI * 12 / 30, Math.PI * 20 / 30);
        ctx.moveTo(250, 250);
        ctx.arc(250, 250, 100, Math.PI * 24 / 30, Math.PI * 32 / 30);
        ctx.moveTo(250, 250);
        ctx.arc(250, 250, 100, Math.PI * 36 / 30, Math.PI * 44 / 30);
        ctx.moveTo(250, 250);
        ctx.arc(250, 250, 100, Math.PI * 48 / 30, Math.PI * 56 / 30);

        ctx.stroke();
        ctx.closePath();
    }
}

draw();

我不想要从中心到弧线起点的线(第一个没有它)。 我一直在用画布学习基本的绘图,希望有一天能理解发生了什么,但我迫不及待地想知道在这种情况下出了什么问题。 任何帮助,非常感谢。

【问题讨论】:

    标签: javascript html canvas html5-canvas drawing


    【解决方案1】:

    如果您想要一个灵活的解决方案,即。如果你想改变段数,每个段的大小,那么你可以创建一个通用函数,例如:

    /**
     * ctx      = context
     * x / y    = center
     * radius   = of circle
     * offset   = rotation in angle (radians)
     * segments = How many segments circle should be in
     * size     = size of each segment (of one segment) [0.0, 1.0]
    */
    function dashedCircle(ctx, x, y, radius, offset, segments, size) {
    
        var pi2 = 2 * Math.PI,             /// cache 2*Math.PI = 360 degrees in rads
            segs = pi2 / segments,         /// calc. size of each segment in rads
            len = segs * size,             /// calc. length of segment in rads
            i = 0,
            ax, ay;
    
        ctx.save();
        ctx.translate(x, y);
        ctx.rotate(offset);                /// rotate canvas
        ctx.translate(-x, -y);
    
        for(; i < pi2; i += segs) {
            ax = x + radius * Math.cos(i); /// calculate start position of arc
            ay = y + radius * Math.sin(i);
            ctx.moveTo(ax, ay);            /// make sure to move to beginning of arc
            ctx.arc(x, y, radius, i, i + len); /// draw arc
        }
    
        ctx.restore();                     /// remove rotation
    }
    

    然后在你的代码中你只需调用:

    ctx.beginPath();
    
    dashedCircle(ctx, 250, 250, 100, 0, 5, 0.7);
    
    ctx.lineWidth = 15;
    ctx.strokeStyle = 'hsla(111, 56%, 50%, 0.67)';
    ctx.stroke();
    /// don't closePath here
    

    Modified fiddle here

    使用 offset 参数可以轻而易举地旋转它:

    var offset = 0;
    var step = 0.03;
    var pi2 = 2 * Math.PI;
    
    (function loop() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.beginPath();
    
        dashedCircle(ctx, 250, 250, 100, offset % pi2, 5, 0.7);
        ctx.stroke();
    
        offset += step;
    
        requestAnimationFrame(loop);
    })();
    

    Rotating circle fiddle

    【讨论】:

    • 哇!惊人的!我正在研究你的小提琴以尽可能地理解它们。而且我已经学到了很多!起初,大小根本不清楚。现在我看到它就像一个相对大小。真正应该画出多少弧线。考虑到每条弧线都是整个圆的一部分。它真的很聪明,是我想内化的那种洞察力。
    • 现在我的需求非常具体,但我从你的代码中学到的东西仍然是无价的。非常感谢。 =D 我现在的目标已经完成了!:anzol.biz
    【解决方案2】:

    moveTo 需要位于弧的起点而不是中心。这最容易通过平移到圆心来实现,如下所示。 http://jsfiddle.net/utWdM/1

    function draw() {
        var canvas = document.getElementById("canvas");
        if (canvas.getContext) {
            var ctx = canvas.getContext("2d");
            ctx.lineWidth = 15;
            ctx.strokeStyle = 'hsla(111, 56%, 50%, 0.67)';
            ctx.beginPath();
    
            ctx.translate(250,250);
            ctx.arc(0, 0, 100, 0, Math.PI * 8 / 30);
            ctx.moveTo(100*Math.cos(Math.PI*12/30), 100*Math.sin(Math.PI*12/30));
            ctx.arc(0, 0, 100, Math.PI * 12 / 30, Math.PI * 20 / 30);
            ctx.moveTo(100*Math.cos(Math.PI*24/30), 100*Math.sin(Math.PI*24/30));
            ctx.arc(0, 0, 100, Math.PI * 24 / 30, Math.PI * 32 / 30);
            ctx.moveTo(100*Math.cos(Math.PI*36/30), 100*Math.sin(Math.PI*36/30));
            ctx.arc(0, 0, 100, Math.PI * 36 / 30, Math.PI * 44 / 30);
            ctx.moveTo(100*Math.cos(Math.PI*48/30), 100*Math.sin(Math.PI*48/30));
            ctx.arc(0, 0, 100, Math.PI * 48 / 30, Math.PI * 56 / 30);
    
            ctx.stroke();
            ctx.closePath();
        }
    }
    

    【讨论】:

    • +1 好答案。注意:由于您在 draw() 中进行翻译,因此您可能需要使用 ctx.save/ctx.restore 进行包装。否则,对 draw() 的任何进一步调用都会累积翻译并将绘图从画布上移开。对提问者需要的补充:由于您已经翻译到中心点,您不妨添加 ctx.rotate(radianAngle) 这将使您的圆弧也可旋转。
    • 太棒了!正如小提琴所示,它有效,它帮助我更新了余弦、正弦和单位圆的知识。这现在很有帮助,从长远来看也会很有用。所以,非常感谢!
    • 了解我应该“移动到”哪里以及如何计算它正是我所需要的。我想我主要是在几何上迷路了。 =P 现在,“最终”产品可以在这里看到它的全部荣耀!:anzol.biz
    【解决方案3】:

    避免复杂数学的最简单方法是为每个段调用.beginPath().stroke();。我知道这是非常重复的,但它看起来像这样:

    function draw() {
        var canvas = document.getElementById("canvas");
        if (canvas.getContext) {
            var ctx = canvas.getContext("2d");
            ctx.lineWidth = 15;
            ctx.strokeStyle = 'hsla(111, 56%, 50%, 0.67)';
    
            ctx.beginPath();        
            ctx.arc(250, 250, 100, 0, Math.PI * 8 / 30);
            ctx.stroke();
    
            ctx.beginPath();
            ctx.arc(250, 250, 100, Math.PI * 12 / 30, Math.PI * 20 / 30);
            ctx.stroke();
    
            ctx.beginPath();
            ctx.arc(250, 250, 100, Math.PI * 24 / 30, Math.PI * 32 / 30);
            ctx.stroke();
    
            ctx.beginPath();
            ctx.arc(250, 250, 100, Math.PI * 36 / 30, Math.PI * 44 / 30);
            ctx.stroke();
    
            ctx.beginPath();
            ctx.arc(250, 250, 100, Math.PI * 48 / 30, Math.PI * 56 / 30);
            ctx.stroke();
        }
    }
    
    draw();
    

    这是你的小提琴:http://jsfiddle.net/utWdM/13/

    【讨论】:

    • 起初,我尝试过这样的事情。它确实有效,但我觉得我错过了一些重要的东西。最终,我意识到复杂的数学并没有那么复杂,实际上很有趣。 =D 我以后会反复使用的知识。
    • 还有别的东西。我开始明白closePath 在这里没有必要。不是endPath。它没有做我想象的那样。宝贵的一课。你可以在这个小提琴中自己看到它:jsfiddle.net/utWdM/7.
    • closePath() 连接终点和起点,弧线不需要。此外,在stroke() 之后调用它是没有意义的,因为stroke是光栅化路径(轮廓)的方法。
    • @jaywalking101 酷!很高兴我也能从中学到一些东西。我更新了我的答案。
    猜你喜欢
    • 2020-04-17
    • 1970-01-01
    • 2013-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多