【问题标题】:How to draw segment of a donut with HTML5 canvas?如何使用 HTML5 画布绘制甜甜圈的一部分?
【发布时间】:2016-12-19 22:54:46
【问题描述】:

如标题所述。这可能吗?

编辑:当我说甜甜圈时,我指的是顶部的 2D 视图

唯一的选择是绘制一段圆,然后在顶部绘制一个具有相同原点和较小半径的较小圆的一段,并使用背景颜色?如果是这样,那将是废话:(

【问题讨论】:

    标签: html canvas


    【解决方案1】:

    您可以通过使用两条弧线制作一条路径来做到这一点。

    你顺时针画一个圆圈,然后逆时针画第二个圆圈。我不会详细介绍它,但是构建路径的方式知道以此为理由来取消填充路径的那部分。有关它的作用的更多详细信息,您可以this wiki article

    如果您正在绘制“带框”矩形,则同样适用。您以一种方式(顺时针)绘制一个盒子,然后以另一种方式(逆时针)绘制内部盒子以获得效果。

    这是甜甜圈的代码:

    var can = document.getElementById('canvas1');
    var ctx = can.getContext('2d');
    
    // Pay attention to my last argument!
    //ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);  
    
    ctx.beginPath()
    ctx.arc(100,100,100,0,Math.PI*2, false); // outer (filled)
    ctx.arc(100,100,55,0,Math.PI*2, true); // inner (unfills it)
    ctx.fill();
    

    例子:

    http://jsfiddle.net/Hnw6a/

    可以通过缩小路径(您可能需要使用贝塞尔曲线而不是弧线)或使用剪切区域来仅绘制它的“段”。这真的取决于你到底想要一个“段”

    这是一个例子:http://jsfiddle.net/Hnw6a/8/

    // half doughnut
    ctx.beginPath()
    ctx.arc(100,100,100,0,Math.PI, false); // outer (filled)
    ctx.arc(100,100,55,Math.PI,Math.PI*2, true); // outer (unfills it)
    ctx.fill();
    

    【讨论】:

    • 不填充和不填充,为什么不直接用粗笔画?
    • @Phrogz 您可能希望边框和填充颜色不同。
    • @JustinY 您可以设置不同的strokeStylefillStyle
    【解决方案2】:

    您可以通过抚摸弧线来制作“顶视图甜甜圈”(带空心的圆形)。你可以在这里看到一个例子:http://phrogz.net/tmp/connections.html

    圆圈(带笔尖)由第 239-245 行绘制:

    ctx.lineWidth = half*0.2;          // set a nice fat line width
    var r = half*0.65;                 // calculate the radius
    ctx.arc(0,0,r,0,Math.PI*2,false);  // create the circle part of the path
    // ... some commands for the nib
    ctx.stroke();                      // actually draw the path
    

    【讨论】:

      【解决方案3】:

      是的,我知道这个问题有多老了:)

      这是我的两分钱:

      (function(){
       var annulus = function(centerX, centerY,
                             innerRadius, outerRadius,
                             startAngle, endAngle,
                             anticlockwise) {
        var th1 = startAngle*Math.PI/180;
        var th2 = endAngle*Math.PI/180;
        var startOfOuterArcX = outerRadius*Math.cos(th2) + centerX;
        var startOfOuterArcY = outerRadius*Math.sin(th2) + centerY;
      
        this.beginPath();
        this.arc(centerX, centerY, innerRadius, th1, th2, anticlockwise);
        this.lineTo(startOfOuterArcX, startOfOuterArcY);
        this.arc(centerX, centerY, outerRadius, th2, th1, !anticlockwise);
        this.closePath();
       }
       CanvasRenderingContext2D.prototype.annulus = annulus;
      })();
      

      这将在 CanvasRenderingContext2D 原型中添加一个类似于“arc()”的函数“annulus()”。如果您想检查点是否包含,制作封闭路径会派上用场。

      使用此功能,您可以执行以下操作:

      var canvas = document.getElementById("canvas1");
      var ctx = canvas.getContext("2d");
      ctx.annulus(0, 0, 100, 200, 15, 45);
      ctx.fill();
      

      或者看看这个:https://jsfiddle.net/rj2r0k1z/10/

      谢谢!

      【讨论】:

      • 谢谢。我今天会经常使用这个:)
      【解决方案4】:

      【讨论】:

      • 澄清的问题,我的意思是在 2D 中抱歉。你的答案仍然适用吗?
      • @AndrewBullock 它应用了“一点”——您也可以将 WebGL 与 2D 一起使用,这应该为您想要绘制的内容提供更多选项...对于 WebGL 中的简单 2D 示例,请参阅developer.mozilla.org/en/WebGL/…
      【解决方案5】:

      鉴于要求,@SimonSarris 所说的可以满足问题。但是,假设您像我一样,而是想“清除”可能部分超出您要清除的形状范围的形状的一部分。如果你有这个要求,他的解决方案不会让你想要你想要的。它看起来像下图中的“xor”。

      解决方法是使用context.globalCompositeOperation = 'destination-out',蓝色是第一个形状,红色是第二个形状。如您所见,destination-out 从第一个形状中删除了该部分。下面是一些示例代码:

        explosionCanvasCtx.fillStyle = "red"
        drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
        explosionCanvasCtx.fill()
      
        explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
        drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
        explosionCanvasCtx.fill()
      

      这是潜在的问题:第二个fill() 将清除它下面的所有内容,包括背景。有时您只想清除第一个形状,但仍想查看其下方的图层。

      解决方案是将其绘制在临时画布上,然后 drawImage 将临时画布绘制到主画布上。代码将如下所示:

        diameter = projectile.radius * 2
        console.log "<canvas width='" + diameter + "' height='" + diameter + "'></canvas>"
        explosionCanvas = $("<canvas width='" + diameter + "' height='" + diameter + "'></canvas>")
        explosionCanvasCtx = explosionCanvas[0].getContext("2d")
      
        explosionCanvasCtx.fillStyle = "red"
        drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
        explosionCanvasCtx.fill()
      
        explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
        durationPercent = (projectile.startDuration - projectile.duration) / projectile.startDuration
        drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
        explosionCanvasCtx.fill()
        explosionCanvasCtx.globalCompositeOperation = 'source-over' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
      
        ctx.drawImage(explosionCanvas[0], projectile.pos.x - projectile.radius, projectile.pos.y - projectile.radius) #center
      

      【讨论】:

        【解决方案6】:

        调整/简化@Simon Sarris 的回答以轻松处理任何角度给出了以下内容:

        要创建弧段,您可以在一个方向上绘制一个外弧(n 弧度),然后在较小的半径处绘制一个相反的弧(具有相同弧度)并填充生成的区域。

        var can = document.getElementById('canvas1');
        var ctx = can.getContext('2d');
         
        var angle = (Math.PI*2)/8;
        
        var outer_arc_radius = 100;
        var inner_arc_radius = 50.;
        
        ctx.beginPath()
        
        //ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise); 
        ctx.arc(100,100,outer_arc_radius,0,angle, false); // outer (filled)
        // the tip of the "pen is now at 0,100
        ctx.arc(100,100,inner_arc_radius,angle,0, true); // outer (unfills it)
        ctx.fill();
        &lt;canvas id="canvas1" width="200" height="200"&gt;&lt;/canvas&gt;

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-10-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多