清除HTML5 Canvas中的圆形区域

Dav*_*ord 32 javascript html5 canvas html5-canvas

看起来从画布中清除区域的唯一方法是使用clearRect()命令 - 我需要清除一个圆圈(我在填充的画布上掩盖区域,在这个特定情况下指向灯光)并尽管所有尝试它似乎不可能.

我尝试绘制一个alpha值为0的圆圈,但除非alpha更高(这与点相反:P),否则不会出现任何内容 - 我假设因为contex.fill()将其绘制为添加而不是替换.

关于我如何能够(快速)清除圆圈以进行掩模的任何建议?

Aln*_*tak 39

使用.arc创建一个圆形行程,然后使用.clip(),使当前裁剪区域.

然后您可以使用.clearRect()擦除整个画布,但只有剪切区域会改变.


Sim*_*ris 16

如果你正在制作游戏或者其他方面需要重视每一点性能,请看看我是如何做出这样的答案的:画布 - 在所有完全透明的区域填充一个矩形

具体来说,编辑导致这个问题的答案:http://jsfiddle.net/a2Age/2/

这里的巨大优势:

  • 没有使用路径(慢)
  • 不使用剪辑(慢)
  • 无需保存/恢复(因为在没有清除所有状态(1)的情况下无法重置剪切区域,这意味着您还必须使用保存/恢复)

(1)我实际上抱怨过这一点,并且resetClip()因为它而被放入官方规范中,但是在浏览器实现它之前还需要一段时间.

var ctx          = document.getElementById('canvas1').getContext('2d'),
    ambientLight = 0.1,
    intensity    = 1,
    radius       = 100,
    amb          = 'rgba(0,0,0,' + (1 - ambientLight) + ')';

addLight(ctx, intensity, amb, 200, 200, 0, 200, 200, radius); // First circle
addLight(ctx, intensity, amb, 250, 270, 0, 250, 270, radius); // Second circle
addLight(ctx, intensity, amb, 50, 370, 0, 50, 370, radius, 50); // Third!

ctx.fillStyle = amb;
ctx.globalCompositeOperation = 'xor';
ctx.fillRect(0, 0, 500, 500);

function addLight(ctx, intsy, amb, xStart, yStart, rStart, xEnd, yEnd, rEnd, xOff, yOff) {
  xOff = xOff || 0;
  yOff = yOff || 0;

  var g = ctx.createRadialGradient(xStart, yStart, rStart, xEnd, yEnd, rEnd);
  g.addColorStop(1, 'rgba(0,0,0,' + (1 - intsy) + ')');
  g.addColorStop(0, amb);
  ctx.fillStyle = g;
  ctx.fillRect(xStart - rEnd + xOff, yStart - rEnd + yOff, xEnd + rEnd, yEnd + rEnd);
}
Run Code Online (Sandbox Code Playgroud)
canvas {
  border: 1px solid black;
  background-image: url('http://placekitten.com/500/500');
}
Run Code Online (Sandbox Code Playgroud)
<canvas id="canvas1" width="500" height="500"></canvas>
Run Code Online (Sandbox Code Playgroud)


Dan*_*lan 9

鉴于要求,这些答案都很好.但是,让我们说你和我一样,你有额外的要求:

  1. 您想要"清除"可能部分超出您正在清除的形状范围的形状的一部分.
  2. 您希望在形状下方看到背景而不是清除背景.

对于第一个要求,解决方案是使用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()
Run Code Online (Sandbox Code Playgroud)

下面是这个潜在的问题:第二个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
Run Code Online (Sandbox Code Playgroud)


Dre*_*kes 8

你有几个选择.

首先,这是我们用来填充圆圈的函数.

var fillCircle = function(x, y, radius)
{
    context.beginPath();
    context.arc(x, y, radius, 0, 2 * Math.PI, false);
    context.fill();
};
Run Code Online (Sandbox Code Playgroud)

clip()

var clearCircle = function(x, y, radius)
{
    context.beginPath();
    context.arc(x, y, radius, 0, 2 * Math.PI, false);
    context.clip();
    context.clearRect(x - radius - 1, y - radius - 1,
                      radius * 2 + 2, radius * 2 + 2);
};
Run Code Online (Sandbox Code Playgroud)

jsFiddle上看到这个.


globalCompositeOperation

var clearCircle = function(x, y, radius)
{
    context.save();
    context.globalCompositeOperation = 'destination-out';
    context.beginPath();
    context.arc(x, y, radius, 0, 2 * Math.PI, false);
    context.fill();
    context.restore();
};
Run Code Online (Sandbox Code Playgroud)

jsFiddle上看到这个.


两者都在屏幕上给出了期望的结果,但是在我的情况下表现不够,因为我正在绘制并清除每帧的很多圆圈以获得效果.最后,我发现了一种不同的方法,通过在弧上绘制较粗的线条来获得与我想要的相似的效果,但上述对于具有不同性能要求的人来说仍然有用.