如何用HTML5画布绘制甜甜圈的片段?

时间:2011-11-06 20:14:49

标签: html5 canvas

正如标题所述。这可能吗?

编辑:当我说甜甜圈时,我的意思是顶级的2D视图

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

6 个答案:

答案 0 :(得分:29)

你可以通过制作一个带有两个弧的单一路径来实现。

顺时针绘制一个圆,然后逆时针绘制第二个圆。我不会详细介绍它,但是构建路径的方式知道将其作为解开路径部分的理由。有关其行为的详细信息,请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();

答案 1 :(得分:3)

你可以通过抚摸弧形来制作一个'顶视图甜甜圈'(带有空心的圆圈)。您可以在此处查看此示例:http://phrogz.net/tmp/connections.html

enter image description here

圆圈(带有笔尖)由第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

答案 2 :(得分:2)

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

这是我的两分钱:

(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;
})();

哪个会添加一个功能" annulus()"类似于" arc()"在CanvasRenderingContext2D原型中。如果你想检查包含点,那么制作封闭的路径会派上用场。

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

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/

谢谢!

答案 3 :(得分:1)

答案 4 :(得分:1)

鉴于要求,@ SimonSarris所说的满足了这个问题。但是,让我们说你喜欢我,而你却希望"清楚"形状的一部分,可能部分位于您要清除的形状范围之外。如果你有这个要求,他的解决方案不会让你想要你想要的。它看起来像" xor"在下图中。

enter image description here

解决方案是使用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

答案 5 :(得分:0)

适应/简化@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();
<canvas id="canvas1" width="200" height="200"></canvas>