Canvas 合成与裁剪 超详细讲解
Canvas 的**合成(Compositing)和裁剪(Clip)**是实现高级视觉效果的核心技术,我会把 全局合成、透明度合成、路径裁剪 拆解得通俗易懂,附带可直接运行的代码和效果图逻辑。
先明确核心概念:
- 透明度合成:单个图形/图片自身的透明效果
- 路径裁剪(clip):用一个路径当“模具”,只在模具内绘制内容
- 全局合成(globalCompositeOperation):控制新图形和已有图形的叠加规则
一、基础前置:Canvas 渲染层级
Canvas 是画布,后绘制的图形默认会覆盖先绘制的图形,这是默认合成规则:source-over。
所有合成/裁剪/透明度,都是在修改这个“覆盖规则”。
二、透明度合成(opacity)
1. 两种透明度设置方式
Canvas 支持全局透明度和局部透明度:
| 方式 | API | 作用范围 |
|---|---|---|
| 全局透明度 | ctx.globalAlpha = 0~1 | 所有后续绘制的图形 |
| 局部透明度 | rgba/rbga 颜色值 | 仅当前图形 |
2. 代码示例
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 1. 局部透明度:仅红色矩形生效
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; // 透明度 0.5
ctx.fillRect(50, 50, 100, 100);
// 2. 全局透明度:后续所有图形都生效
ctx.globalAlpha = 0.3;
ctx.fillStyle = 'blue';
ctx.fillRect(100, 100, 100, 100); // 蓝色矩形透明度 0.3
// 重置全局透明度(必须!)
ctx.globalAlpha = 1;
3. 核心要点
globalAlpha是全局生效的,用完必须重置为1- 局部透明度(rgba)优先级更高,互不干扰
- 透明度叠加:两个半透明图形重叠,重叠区域会更透明
三、路径裁剪 clip() —— 画布“模具”
1. 核心原理
clip() 会把当前路径变成一个裁剪区域(蒙版/模具),后续所有绘制只会显示在这个区域内,超出部分全部隐藏。
就像用剪纸模具,只能在模具里涂色。
2. 关键规则
- 必须先定义路径,再调用
clip() clip()是单向不可逆的,想要恢复必须用save()+restore()- 可以嵌套裁剪(模具里再做小模具)
3. 基础使用(圆形裁剪图片)
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = '图片地址';
img.onload = function() {
ctx.save(); // 保存画布状态(关键!)
// 1. 绘制裁剪路径:圆形
ctx.arc(150, 150, 100, 0, Math.PI * 2);
ctx.clip(); // 把路径变成裁剪模具
// 2. 在模具内绘制图片(只会显示圆形区域)
ctx.drawImage(img, 50, 50, 200, 200);
ctx.restore(); // 恢复画布状态,关闭裁剪
};
4. 高级:不规则路径裁剪
任何路径(多边形、曲线、文字)都能当裁剪模具:
// 五角星路径裁剪
ctx.save();
ctx.beginPath();
ctx.moveTo(150,50);
ctx.lineTo(180,150);
ctx.lineTo(280,150);
ctx.lineTo(200,200);
ctx.lineTo(230,300);
ctx.lineTo(150,250);
ctx.lineTo(70,300);
ctx.lineTo(100,200);
ctx.lineTo(20,150);
ctx.lineTo(120,150);
ctx.closePath();
ctx.clip();
// 绘制内容,只显示五角星内
ctx.fillStyle = 'red';
ctx.fillRect(0,0,300,300);
ctx.restore();
四、全局合成 globalCompositeOperation
这是 Canvas 最强大的功能,控制新图形和已有图形的叠加方式。
1. 核心概念
- 源图像(source):即将绘制的新图形
- 目标图像(destination):画布上已经存在的图形
ctx.globalCompositeOperation = "模式"
2. 常用合成模式详解
以下是几种最常用、最能体现其威力的模式:
| 模式 | 描述 | 典型应用 |
|---|---|---|
source-over | 默认值。新图形绘制在旧图形的上方。 | 常规的绘图操作。 |
destination-over | 新图形绘制在旧图形的下方。 | 为已有图形添加背景或衬底。 |
source-in | 新图形只在与旧图形重叠的区域显示,其余部分变透明。 | 遮罩/贴图。例如,将一张图片限制在一个圆形或文字形状内显示。 |
destination-in | 只保留旧图形中与新图形重叠的部分,其余清空。 | 蒙版提取。例如,用文字的形状“抠”出底下图片的局部。 |
source-out | 新图形只在不与旧图形重叠的区域显示。 | 制作镂空效果。 |
destination-out | 擦除旧图形中与新图形重叠的部分。 | 橡皮擦效果。常用于涂鸦板或擦除动画。 |
lighter | 重叠区域的颜色值相加。 | 创建发光或加亮效果。 |
xor | 重叠区域变为透明。 | 制作特殊的异或效果。 |
3. 代码演示(source-in 蒙版)
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 1. 目标图像(已有图形):蓝色矩形
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 150, 150);
// 2. 设置合成模式:只保留重叠区域,显示新图形
ctx.globalCompositeOperation = 'source-in';
// 3. 源图像(新图形):红色圆形
ctx.fillStyle = 'red';
ctx.arc(150, 150, 100, 0, Math.PI * 2);
ctx.fill();
// 重置合成模式(必须!)
ctx.globalCompositeOperation = 'source-over';
4. 橡皮擦效果(destination-out)
// 先铺满画布
ctx.fillStyle = 'black';
ctx.fillRect(0,0,400,400);
// 设置合成模式:擦除重叠区域
ctx.globalCompositeOperation = 'destination-out';
// 绘制圆形,重叠的黑色会被擦掉
ctx.arc(200,200,80,0,Math.PI*2);
ctx.fill();
五、关键避坑指南
- 状态管理:
clip()和globalAlpha/globalCompositeOperation修改后必须重置,最佳实践:ctx.save(); // 保存 // 合成/裁剪代码 ctx.restore(); // 恢复 - 执行顺序:
- 裁剪:先路径 → 再 clip → 再绘制
- 合成:先画目标图形 → 设置模式 → 再画源图形
- clip 不可逆:不用 save/restore 无法取消裁剪,会一直生效
- 合成模式互斥:同一时间只能生效一种模式
总结
- 透明度:
globalAlpha(全局)/rgba(局部),控制半透明效果 - 路径裁剪 clip:用路径做模具,只在模具内绘制,必须配合 save/restore
- 全局合成:
globalCompositeOperation控制新旧图形叠加方式,核心是source-in(蒙版)和destination-out(橡皮擦) - 三者可以组合使用,实现图片圆角、蒙版、擦除、镂空等所有高级视觉效果