代码之家  ›  专栏  ›  技术社区  ›  slacktracer

如何在画布元素中正确绘制带有间隙的圆?

  •  1
  • slacktracer  · 技术社区  · 11 年前

    我想画一个圆。但是,不是真的。我想要一系列圆弧(线段),这意味着一个完整的圆。它会旋转,会很棒。但我显然做错了什么。 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();
    

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

    3 回复  |  直到 11 年前
        1
  •  3
  •   user1693593 user1693593    11 年前

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

    /**
     * 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

    使用偏移参数可以轻松旋转:

    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

        2
  •  1
  •   jing3142    11 年前

    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();
        }
    }
    
        3
  •  1
  •   Skwal user3423801    11 年前

    避免复杂数学的最简单方法是调用 .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/