globalCompositeOperation和同心,空心,动人的形状

时间:2014-04-09 19:29:23

标签: javascript html5 canvas globalcompositeoperation

我试图实现以下目标:

在画布上绘制了许多同心圆(或环)。每个圆圈都有一个"孔"在其中,因此在其后面绘制的较小圆圈是部分可见的。每个框架(我们使用window.requestAnimationFrame渲染)每个圆/形状/环的半径略有增加。

图像here中描述了具有两个响铃的场景。

Example image

代码:

function draw() {
    drawBgr();
    for (var i = 0, len = rings.length; i < len; i++) {
        rings[i].draw();
    }
}

function drawBgr() {
    context.globalCompositeOperation = "source-over";
    context.clearRect(0, 0, WIDTH, HEIGHT);
    context.rect(0, 0, WIDTH, HEIGHT);
    context.fillStyle = '#FFFFFF';
    context.fill();
}

function squareRing(ring) { //called by rings[i].draw();
    context.globalCompositeOperation = "source-over";

    context.fillRect(ring.centerX - ring.radius / 2, ring.centerY - ring.radius / 2, ring.radius, ring.radius);
    context.globalCompositeOperation = "source-out";

    context.beginPath();
    context.arc(CENTER_X, CENTER_Y, ring.radius, 0, 2 * Math.PI, false);
    //context.lineWidth = RING_MAX_LINE_WIDTH * (ring.radius / MAX_SIDE);
    context.fillStyle = '#000000';
    context.fill();
    context.globalCompositeOperation = "source-over";

}
  1. 这究竟是什么问题?我在绘制圆圈之前调用clearRect。请参阅&#34;我实际得到的内容&#34;图片。这是在多个帧上绘制单环的结果。我不应该得到任何不同于中间有空心方形的黑色圆圈。 (请注意,每帧的半径都在增加。)

  2. 我确实意识到切换globalCompositeOperation可能不足以达到我想要的效果。我怎样画一个洞?#34;在画布上绘制的对象中,没有删除&#34;&#34;中的所有内容。在我试图修改的对象下面?

  3. This是我用作globalCompositeOperation值的参考的教程。

    我使用的是Firefox 28.0。

1 个答案:

答案 0 :(得分:0)

我不会尝试使用globalCompositeOperation,因为我发现很难弄清楚几次迭代后会发生什么,如果之前没有清除画布则更难。

我更喜欢使用剪辑,这让我知道:

http://jsbin.com/guzubeze/1/edit?js,output

enter image description here

那么,要在平局中建立一个'洞',如何使用剪辑? - &GT;&GT;定义一个正剪切子路径,并在此区域内切断负面部分,使用此时间为顺时针子路径:

enter image description here

剪切必须用一个路径完成,因此不能使用rect():它每次都会开始一个路径,并且不允许选择clockwisity(:-)),所以你必须定义那两个函数将只创建所需的子路径:

// clockwise sub-path of a rect
function rectPath(x,y,w,h) {
  ctx.moveTo(x,y);
  ctx.lineTo(x+w,y);
  ctx.lineTo(x+w,y+h);
  ctx.lineTo(x,y+h);
}

// counter-clockwise sub-path of a rect
function revRectPath(x,y,w,h) {
  ctx.moveTo(x,y);
  ctx.lineTo(x,y+h);
  ctx.lineTo(x+w,y+h);
  ctx.lineTo(x+w,y);  
}

然后你可以写下你的绘图代码:

function drawShape(cx, cy, d, scale, rotation) {
  ctx.save();
  ctx.translate(cx,cy);
  scale = scale || 1;
  if (scale !=1) ctx.scale(scale, scale);
  rotation = rotation || 0;
  if (rotation) ctx.rotate(rotation);
  // clip with rectangular hole
  ctx.beginPath();
  var r=d/2; 
  rectPath(-r,-r, d, d);
  revRectPath(-0.25*r,-0.8*r, 0.5*r, 1.6*r);
  ctx.closePath();
  ctx.clip();
  ctx.beginPath();
  // we're clipped !
  ctx.arc(0,0, r, 0, 2*Math.PI);
  ctx.closePath();
  ctx.fill();
  ctx.restore();
}

编辑:

为了记录,有一种更简单的方法来绘制问题方案:只绘制一个圆圈,然后逆时针绘制一个矩形。你填充的将是在rect之外的圆圈里面的部分,这就是你想要的:

function drawTheThing(x,y,r) {
   ctx.beginPath();
   ctx.arc(x ,y, r, 0, 2*Math.PI);
   revRectPath(x-0.25*r, y-0.8*r, 0.5*r, 1.6*r);
   ctx.fill();
   ctx.closePath();
}

(我不发布图片:它是一样的。)

根据您的需要,如果您更改抽奖,或者如果您想引入某种通用性,请使用第一个或第二个。 如果您以后不更改方案,则第二种解决方案更简单=&gt;更好。