2017/7 更新
由于给出了这个答案,现在在较新的浏览器中提供了一个新选项,即上下文中的filter属性。请注意,目前并非所有浏览器都支持它。
对于这样做的浏览器,我们可以减少代码并像这样删除临时画布:
var ctx = demo.getContext('2d');
ctx.fillStyle = '#f90';
ctx.fillRect(0, 0, demo.width, demo.height);
clipArc(ctx, 200, 200, 150, 40);
function clipArc(ctx, x, y, r, f) {
ctx.globalCompositeOperation = 'destination-out';
ctx.filter = "blur(25px)"; // "feather"
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.fill();
// reset comp. mode and filter
ctx.globalCompositeOperation = 'destination-out';
ctx.filter = "none";
}
body {background:#07c}
<canvas id="demo" width=400 height=400></canvas>
旧答案
技术
您可以通过组合以下步骤来实现此目的:
- 使用离屏画布
- 使用阴影功能(秘密成分)
- 使用复合模式
这个概念是基于让浏览器利用模糊阴影在内部制作羽毛。这比 JavaScript 中的模糊要快得多。因为我们可以为任何对象制作阴影,所以您可以制作复杂的羽毛蒙版。
离屏画布仅用于绘制阴影。我们通过将实际形状移动到画布外然后相应地偏移阴影来实现这一点。结果是在屏幕外画布上绘制阴影,而实际形状是“不可见的”。
现在我们有了形状的羽化版本,我们可以将其用作复合模式的蒙版。我们选择destination-out
在绘制阴影的位置进行夹板,或destination-in
反转蒙版。
例子
让我们创建一个包装函数来为我们完成所有步骤
在线演示在这里
function clipArc(ctx, x, y, r, f) { /// context, x, y, radius, feather size
/// create off-screen temporary canvas where we draw in the shadow
var temp = document.createElement('canvas'),
tx = temp.getContext('2d');
temp.width = ctx.canvas.width;
temp.height = ctx.canvas.height;
/// offset the context so shape itself is drawn outside canvas
tx.translate(-temp.width, 0);
/// offset the shadow to compensate, draws shadow only on canvas
tx.shadowOffsetX = temp.width;
tx.shadowOffsetY = 0;
/// black so alpha gets solid
tx.shadowColor = '#000';
/// "feather"
tx.shadowBlur = f;
/// draw the arc, only the shadow will be inside the context
tx.beginPath();
tx.arc(x, y, r, 0, 2 * Math.PI);
tx.closePath();
tx.fill();
/// now punch a hole in main canvas with the blurred shadow
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
ctx.drawImage(temp, 0, 0);
ctx.restore();
}
这里的所有都是它的。
用法
clipArc(context, centerX, centerY, radius, featherSize);
带有演示背景(见小提琴):
ctx.fillStyle = '#ffa';
ctx.fillRect(0, 0, demo.width, demo.height);
clipArc(ctx, 200, 200, 150, 40);
结果:
如果要保持中心不变,只需将复合模式替换为destination-in
.
倒置羽毛面具演示