clip遮罩与合成层
clip() 把 当前 path(或 Path2D) 交进裁剪区,之后所有绘制(含 drawImage)都被卡住。裁剪区只能变小,扩大必须 restore。这和 globalCompositeOperation 不是一回事:clip 改后续绘制的可写区域,GCO 改与 已有像素 的混合公式。
1. clip 的正确用法
export function withClip(
ctx: CanvasRenderingContext2D,
path: Path2D,
fillRule: CanvasFillRule,
paint: () => void,
): void {
ctx.save();
ctx.clip(path, fillRule);
paint();
ctx.restore();
}
头像圆裁、地图圆角窗口、刮刮卡未刮开区域,用 clip。
evenodd 做环状窗口。忘记 closePath 的当前路径去 clip,缺口行为按规范「连到起点」,不要靠它。
clip 与 CTM:path 仍乘当前矩阵。先 setTransform(world) 再 clip 局部 path。
2. 不要用 clip 模拟图层
一棵场景树每个节点 clip 一次,状态栈深度和光栅成本一起涨。矩形窗口优先 clear + 不画窗外;复杂遮罩烘焙成一张 alpha ImageBitmap,用 destination-in 一次。
export function applyAlphaMask(
ctx: CanvasRenderingContext2D,
mask: CanvasImageSource,
): void {
ctx.save();
ctx.globalCompositeOperation = "destination-in";
ctx.drawImage(mask, 0, 0);
ctx.restore();
}
这要求内容已经在当前表面上。通常在离屏完成:先画内容,再 destination-in mask,再 blit 回视图。
source-in / destination-out 做橡皮、开洞。每次 GCO 都只影响 下一笔。连画三笔中间忘了设回 source-over,洞会越挖越怪。
3. 遮罩从哪来
- 矢量:
Path2Dfill 到离屏 alpha - 位图:灰度图当 alpha(自己
getImageData填 A,或drawImage+destination-in) - 文字挖空:fillText 到 mask 表面
软边遮罩(羽毛)= 对 mask 做 blur 再 destination-in,成本在 blur,不在 clip。
要 可编辑、可导出的矢量挖洞,不要停在这一层,见 路径布尔运算。
4. 失败形态
| 症状 | 原因 |
|---|---|
| 后面所有东西消失 | clip 未 restore |
| 圆角外仍画出 | clip 用了错误 CTM / 错 fillRule |
| 开洞失败 | GCO 只作用在下一笔,clearRect 在 source-over |
| 越 clip 越慢 | 每节点 clip 深栈 |
权威资料
核对日期:2026-08-26