canvas 的 path2d 对象是 html5 封装矢量路径的核心工具,支持构造函数或 svg 字符串创建、多次绘制与变换、裁剪及命中检测,并可通过对象或 map 管理图形库实现复用与解耦。

Canvas 的 Path2D 对象是 HTML5 提供的用于封装矢量路径的核心工具,它让复杂图形(如图标、Logo、UI 元素)能被定义一次、多次绘制、平移缩放甚至参与裁剪和命中检测,真正实现复用与解耦。
创建并封装路径:用构造函数或 SVG 字符串
Path2D 支持两种主流初始化方式,适合不同场景:
- 用 Canvas 路径方法构建:适合动态生成或逻辑驱动的图形。例如封装一个带圆角的对话气泡:
const speechBubble = new Path2D(); speechBubble.moveTo(10, 20); speechBubble.lineTo(80, 20); speechBubble.arcTo(100, 20, 100, 40, 10); // 右上圆角 speechBubble.lineTo(100, 70); speechBubble.lineTo(90, 80); // 小三角尾巴 speechBubble.lineTo(80, 70); speechBubble.lineTo(80, 40); speechBubble.arcTo(80, 20, 60, 20, 10); // 左上圆角 speechBubble.closePath();
- 用 SVG 路径字符串构建:适合设计师导出的图标或已知 d 值的图形,简洁且可读性高。例如封装一个心形:
const heart = new Path2D('M50,10 C20,10 0,40 0,70 C0,90 20,110 50,110 C80,110 100,90 100,70 C100,40 80,10 50,10 Z');
复用路径:在任意上下文多次绘制与变换
封装后的 Path2D 实例不绑定坐标系,可在不同 ctx 中自由使用,并支持独立变换:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 直接调用
ctx.stroke(path)或ctx.fill(path),无需重录路径命令; - 使用
ctx.translate()、ctx.scale()、ctx.rotate()配合ctx.setTransform(1,0,0,1,0,0)重置全局变换,再绘制,确保每次变换只影响当前实例; - 也可用
ctx.addPath(path)将其合并进当前路径(适合组合绘制),但注意这会受当前 ctx 状态影响。
示例:在画布上绘制 3 个不同位置、大小的心形:
ctx.fillStyle = '#e74c3c'; ctx.fill(heart); // 默认原点 (0,0) <p>ctx.save(); ctx.translate(120, 50); ctx.scale(0.8, 0.8); ctx.fill(heart); ctx.restore();</p><p>ctx.save(); ctx.translate(200, 30); ctx.rotate(Math.PI / 6); ctx.fill(heart); ctx.restore(); </p>
进阶复用:路径裁剪与命中检测
Path2D 不仅用于绘制,还能提升交互能力:
-
作为裁剪区域:用
ctx.clip(path)限定后续绘制范围。例如只在气泡形状内渲染文字纹理; - 命中检测(isPointInPath):配合事件坐标判断用户是否点击了该图形,无需手动计算几何。注意需传入当前变换下的路径和坐标:
canvas.addEventListener('click', (e) => {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
<p>// 使用当前 ctx 的变换矩阵检测(推荐)
if (ctx.isPointInPath(speechBubble, x, y)) {
console.log('点中了气泡');
}
});
</p>管理多个路径:用对象或 Map 组织图形库
项目中图形增多时,建议用结构化方式管理,避免全局变量污染:
- 用普通对象组织:
const Icons = {
home: new Path2D('M10 20 L30 5 L30 35 Z'),
search: new Path2D('M50 50 Q70 70 50 90'),
close: new Path2D('M80 20 L100 40 M80 40 L100 20')
};
// 使用:ctx.fill(Icons.home);
- 或用
Map支持动态注册与按需加载; - 搭配模块系统(ESM)导出,便于在组件中按需引入。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










