在 canvas 中创建复合剪辑

Creating compound clip in canvas

我尝试在 canvas 中创建一个复合剪辑路径以创建一个类似甜甜圈的剪辑路径。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

function draw() {
    ctx.save();    

    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

    ctx.beginPath();

    ctx.arc(200, 200, 30, 0, Math.PI * 2, true);
    ctx.arc(200, 200, 100, 0, Math.PI * 2, true);
    ctx.clip();

    ctx.fillRect(0,0,500,400); 
}

draw();

正如您在我的 jsfiddle 中看到的那样,这不起作用:https://jsfiddle.net/nahman/05jcjkvn/

我发现,如果我将其更改为使用两种不同的形状类型——弧形和矩形、弧形和路径——它会起作用,但我需要能够使用两种相同的形状: https://jsfiddle.net/nahman/9wmvLea7/

我的问题是:

  1. 为什么它不能用于两个相同的对象类型,但可以 与不同的?有什么好的资源可以解释这一点吗? 遗憾的是,我的 google 搜索结果为空...

  2. 我该如何解决这个问题? :)

我应该注意,我目前通过在绘图后绘制较小的剪辑然后应用 clearRect,强制执行我想要的行为,(https://jsfiddle.net/nahman/pg6ya2ob/) 但出于各种原因我更愿意了解什么是如果可能的话,继续并做得更好。

看看Clip and fill rules文章

您需要为您的情况指定正确的填充规则,"evenodd"。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

function draw() {
  ctx.save();    
    
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    
    ctx.beginPath();
    
    ctx.arc(200, 200, 100, 0, Math.PI * 2, true);
    ctx.arc(200, 200, 30, 0, Math.PI * 2, true);
    
    ctx.clip("evenodd");
    ctx.fillRect(0,0,500,400);
}

draw();
<canvas id="canvas" width=500 height=400></canvas>