用source-atop实现图形内部贴图需先绘制不透明遮罩作为destination,再设globalcompositeoperation="source-atop",最后drawimage使图像仅显现在遮罩内;更推荐clip()方案。

在Canvas中用globalCompositeOperation = "source-atop"实现图形内部贴图,核心是“先画遮罩(目标图形),再画图像(源内容),让图像只显示在遮罩区域内”。这不是直接“贴图”,而是通过合成模式裁剪图像——Source-Atop 会保留目标已有像素的区域,仅把新绘制的图像叠加在这些区域上。
理解 Source-Atop 的行为逻辑
source-atop 的合成规则是:仅在目标(destination)已有不透明像素的位置,绘制源(source)图像;目标透明区域完全不显示源内容。因此必须确保:目标图形已绘制且不透明(如用 fill() 或 clip() 建立有效遮罩),之后再绘制图像。
- 目标(destination):通常是用
fillRect()、arc()等绘制的纯色形状,或更常用的是先beginPath()+fill()创建一个实心区域 - 源(source):你要“贴”进去的图像(
HTMLImageElement或另一个canvas) - 关键前提:目标图形必须在调用
drawImage()前已渲染到 canvas 上(即已成为 destination)
标准四步操作流程
以圆形内部贴图为例子(将一张图片只显示在圆内):
- 清空画布(可选,避免旧内容干扰):
ctx.clearRect(0, 0, canvas.width, canvas.height); - 绘制遮罩图形(目标):用
fillStyle填充一个实心圆(颜色任意,甚至透明色也可,只要 alpha > 0)ctx.beginPath(); ctx.arc(100, 100, 50, 0, Math.PI * 2); ctx.fill(); - 设置合成模式:
ctx.globalCompositeOperation = "source-atop"; - 绘制图像(源):
ctx.drawImage(img, 50, 50, 100, 100);(坐标需对齐遮罩位置)
更可靠替代方案:用 clip() 配合 drawImage
虽然 source-atop 可行,但实际开发中更推荐用 clip() —— 它语义清晰、兼容性好、无需依赖 destination 像素状态:
- 先
beginPath()+ 绘制路径(如圆、多边形) - 调用
ctx.clip()(此操作会限制后续所有绘制只在该路径内生效) - 直接
drawImage(),图像自动被裁剪 - 如需继续在全画布绘制,记得
ctx.save()/ctx.restore()或重置裁剪区
注意事项与常见坑
注意顺序不能颠倒:如果先设 source-atop 再画遮罩圆,那圆本身会被合成模式影响(可能消失或异常);必须先让遮罩成为 destination 内容。
- 图像加载必须完成后再执行绘制,否则
drawImage()无效 —— 务必监听img.onload - Canvas 像素默认有抗锯齿边缘,可能导致遮罩边缘半透明,影响
source-atop效果;可用ctx.imageSmoothingEnabled = false或改用clip()规避 -
source-atop对透明背景 canvas 无效(destination 全透明 → 没有“ atop ”的位置);确保遮罩图形 fill 后有明确不透明区域
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











