How do I perform clearRect() in canvas after clip()?

Kes*_*iam 5 javascript html5-canvas

I need to perform clearRect() after performing clip() in canvas. Unfortunately, It does not working for me.

If I exclude clip() means, clearRect() is working fine me.

<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 300, 150);
ctx.clip();  //after removing clip() clearRect() working
ctx.clearRect(20, 20, 100, 50);
</script>
Run Code Online (Sandbox Code Playgroud)

I need to perform clearRect() after performing clip(). Is this possible?

Please find the fiddle

<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 300, 150);
ctx.clip();  //after removing clip() clearRect() working
ctx.clearRect(20, 20, 100, 50);
</script>
Run Code Online (Sandbox Code Playgroud)

If I called clearRect() after calling canvasClip(), it did not worked for me.

thanks in advance, Kesavan

Kai*_*ido 3

工作方式clip()是,它采用当前的子路径声明,并且不应该在其填充区域中的所有内容都将从绘图区域中丢弃。也就是说,如果您再次在该区域之外绘制某些内容,那么它就不会出现在上下文中。

我猜你的困惑来自fillRect()于。此方法有点特殊,因为它创建了一个仅用于此方法的临时strokeRect矩形子路径(作用相同)。

这是一个直观的例子来说明这意味着什么:

const ctx = canvas.getContext('2d');

// declare a sub-path 
ctx.beginPath();
ctx.arc(50,50,30,0,Math.PI*2); // circle

// this will discard our circle
ctx.fillStyle = 'red';
ctx.fillRect(120, 50, 30, 30);

// wait a bit to show it has been discarded
setTimeout(() => {
  ctx.fillStyle = 'blue';
  ctx.fill(); // this draws only the circle,
  // the internal rect() in fillRect() has disappeared,
  // otherwise it would be blue now
}, 1000);
Run Code Online (Sandbox Code Playgroud)
canvas {border: 1px solid}
Run Code Online (Sandbox Code Playgroud)
<canvas id="canvas" width="500"></canvas>
Run Code Online (Sandbox Code Playgroud)

因此,在调用 之前,您实际上没有在上下文中声明任何子路径clip(),并且新的绘图区域(未剪辑)是 0x0px 路径(即它不存在)。然后,每个绘图操作(并且clearRect是一个)都将无效。

const ctx = canvas.getContext('2d');

// what OP did is equivalent to
ctx.beginPath();
ctx.clip(); // clip a non-existent sub-path

// you can try to draw, it won't work
ctx.arc(50,50,30,0,Math.PI*2);
ctx.fill();
ctx.fillRect(120, 50, 30, 30);
Run Code Online (Sandbox Code Playgroud)
canvas {border: 1px solid}
Run Code Online (Sandbox Code Playgroud)
<canvas id="canvas" width="500"></canvas>
Run Code Online (Sandbox Code Playgroud)

唯一仍然有效的方法是putImageData

由于您只能删除绘图区域,因此通过剪切此非区域,您实际上将上下文锁定在这种状态。*
因此,在使用之前clip(),请始终调用ctx.save()以便能够在之后重置剪切区域。
*好吧,它仍然可以通过设置画布宽度或高度来解锁,但这很糟糕吗?

const ctx = canvas.getContext('2d');

// so we can reset our clipping area
ctx.save();

ctx.fillStyle = "red";
// use `rect()` which does add to the current sub-path
ctx.rect(0, 0, 300, 150);
ctx.fill();
ctx.clip();

ctx.clearRect(20, 20, 100, 50); // now we can clear

ctx.restore(); // remove the clipping area
ctx.fillRect(320, 0, 20, 20); // now we can draw anywhere
Run Code Online (Sandbox Code Playgroud)
canvas {border: 1px solid}
Run Code Online (Sandbox Code Playgroud)
<canvas id="canvas" width="500"></canvas>
Run Code Online (Sandbox Code Playgroud)

但请注意,大多数时候,您最好使用合成来代替剪辑,这样可以实现更清晰的抗锯齿效果,并且通常可以获得更好的性能。但由于我不知道你为什么想使用剪辑,所以我无法真正向你展示等效内容。