Canvas Drawing Editor 完整使用指南
一个强大的、零依赖的 Canvas 画布编辑器 Web Component
Gitee:
GitHub:
NPM:
在线演示:
目录
- 简介
- [为什么选择 Canvas Drawing Editor](#为什么选择 Canvas Drawing Editor "#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-canvas-drawing-editor")
- 功能特性
- 快速开始
- 安装指南
- 框架集成
- 配置选项详解
- 工具配置
- 绘图工具使用
- 高级功能
- 热区功能
- [Tween 动画系统](#Tween 动画系统 "#tween-%E5%8A%A8%E7%94%BB%E7%B3%BB%E7%BB%9F")
- 事件监听
- 数据格式
- [API 参考](#API 参考 "#api-%E5%8F%82%E8%80%83")
- 移动端支持
- 键盘快捷键
- 最佳实践
- 常见问题
简介
Canvas Drawing Editor 是一个基于 HTML5 Canvas 的现代化画布编辑器,它以 Web Component 的形式封装,使其可以无缝集成到任何前端框架或原生 HTML 项目中。

核心优势
- 零依赖:纯 JavaScript 实现,无需 React、Vue 等框架
- 轻量级:gzip 压缩后仅约 33KB
- 跨框架:支持 Vue 2/3、React、Angular 和原生 HTML
- 功能丰富:涵盖绑图、编辑、导出等完整工作流
- 移动端友好:支持触摸手势操作
为什么选择 Canvas Drawing Editor
在众多的画布编辑器库中,Canvas Drawing Editor 以其独特的优势脱颖而出:
1. 真正的零依赖
与市面上大多数需要依赖特定框架的画布库不同,Canvas Drawing Editor 是完全独立的。这意味着:
- 没有框架锁定
- 更小的包体积
- 更快的加载速度
- 更简单的集成方式
2. Web Component 标准
基于 Web Component 标准开发,享受原生浏览器支持:
html
3. 企业级功能
虽然轻量,但功能完整:
- 20+ 绑图工具
- 完整的撤销/重做历史
- 图层管理系统
- 热区模板功能
- Tween 动画引擎
- 多种导出格式
Canvas Drawing Editor 与主流 Canvas 库对比
| 功能特性 | Canvas Drawing Editor | Fabric.js | Konva.js | Excalidraw | tldraw |
|---|---|---|---|---|---|
| 基本信息 | |||||
| 打包体积 (gzip) | ~33KB | ~90KB | ~60KB | ~500KB+ | ~300KB+ |
| 零依赖 | ✅ | ✅ | ✅ | ❌ (依赖 React) | ❌ (依赖 React) |
| Web Component | ✅ | ❌ | ❌ | ❌ | ❌ |
| TypeScript 支持 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 框架兼容性 | |||||
| 原生 HTML | ✅ 开箱即用 | ✅ | ✅ | ❌ | ❌ |
| Vue 2/3 | ✅ 开箱即用 | ⚠️ 需要封装 | ⚠️ 需要封装 | ❌ | ❌ |
| React | ✅ 开箱即用 | ⚠️ 需要封装 | ✅ react-konva | ✅ 原生支持 | ✅ 原生支持 |
| Angular | ✅ 开箱即用 | ⚠️ 需要封装 | ⚠️ 需要封装 | ❌ | ❌ |
| 绘图工具 | |||||
| 铅笔/手绘 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 矩形/圆形 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 直线/箭头 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 多边形 | ✅ | ✅ | ✅ | ❌ | ❌ |
| 星形/心形 | ✅ | ❌ | ✅ 仅星形 | ❌ | ❌ |
| 贝塞尔曲线 | ✅ | ✅ | ✅ | ❌ | ❌ |
| 文本输入 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 富文本 | ✅ | ⚠️ 有限支持 | ❌ | ❌ | ❌ |
| 图片导入 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 编辑功能 | |||||
| 撤销/重做 | ✅ 内置 | ❌ 需自行实现 | ❌ 需自行实现 | ✅ 内置 | ✅ 内置 |
| 图层管理 | ✅ 内置UI | ❌ 需自行实现 | ❌ 需自行实现 | ❌ | ❌ |
| 组合/取消组合 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 对齐/分布 | ✅ 内置UI | ❌ 需自行实现 | ❌ 需自行实现 | ❌ | ✅ |
| 锁定/隐藏 | ✅ | ✅ | ✅ | ❌ | ✅ |
| 旋转/缩放 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 高级功能 | |||||
| 内置工具栏UI | ✅ | ❌ | ❌ | ✅ | ✅ |
| 图片滤镜 | ✅ | ✅ | ✅ | ❌ | ❌ |
| 热区/模板变量 | ✅ | ❌ | ❌ | ❌ | ❌ |
| 补间动画 | ✅ 内置 | ❌ 需自行实现 | ✅ 内置 | ❌ | ❌ |
| 多种线条样式 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 导入/导出 | |||||
| JSON 保存/加载 | ✅ | ✅ | ✅ | ✅ | ✅ |
| PNG 导出 | ✅ | ✅ | ✅ | ✅ | ✅ |
| SVG 导出 | ❌ | ✅ | ❌ | ✅ | ✅ |
| 移动端支持 | |||||
| 触摸手势 | ✅ | ⚠️ 有限支持 | ✅ | ✅ | ✅ |
| 双指缩放 | ✅ | ⚠️ 需自行实现 | ✅ | ✅ | ✅ |
| 响应式布局 | ✅ | ❌ 需自行实现 | ❌ 需自行实现 | ✅ | ✅ |
| 开发者体验 | |||||
| 学习曲线 | ⭐ 低 | ⭐⭐⭐ 中高 | ⭐⭐ 中等 | ⭐ 低 | ⭐ 低 |
| 开箱即用程度 | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| API 灵活性 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐ |
| 文档完善度 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
图例说明:
- ✅ 完全支持 / 内置功能
- ⚠️ 部分支持 / 需要额外实现
- ❌ 不支持
- 需自行实现 = 需要自己编写代码实现该功能
功能特性
🎨 绑图工具集
| 工具 | 快捷键 | 说明 |
|---|---|---|
| 选择工具 | V | 选择、移动、缩放对象 |
| 画笔 | P | 自由绑制路径 |
| 矩形 | R | 绑制矩形 |
| 圆形 | C | 绑制圆形 |
| 线条 | L | 绘制直线 |
| 箭头 | A | 绘制箭头(单向/双向) |
| 多边形 | - | 绘制多边形(支持任意边数) |
| 文本 | T | 添加文本 |
| 富文本 | - | 支持混合样式的富文本 |

🔷 更多形状
- 星形:可自定义角数和内外半径
- 心形:完美的心形曲线
- 三角形:等边三角形
- 菱形:标准菱形
- 贝塞尔曲线:精确的曲线控制

✏️ 线条样式
支持三种线条样式,适用于所有形状:
- 实线(Solid)
- 虚线(Dashed)
- 点线(Dotted)

📚 图层管理
- 图层上移/下移
- 置顶/置底
- 可见性控制
- 锁定/解锁

🔄 编辑功能
- 撤销/重做:完整的历史记录支持(Ctrl+Z / Ctrl+Y)
- 复制/粘贴:快速复制对象(Ctrl+C / Ctrl+V)
- 删除:删除选中对象(Delete / Backspace)
- 旋转:自由旋转任意角度
- 等比缩放:Shift + 拖拽角点
💾 导入导出
| 功能 | 说明 |
|---|---|
| JSON 保存 | 保存完整项目数据,支持后续编辑 |
| JSON 加载 | 加载之前保存的项目 |
| PNG 导出 | 导出为高质量 PNG 图片 |
| 清空画布 | 一键清空所有内容 |
快速开始
最简示例
只需三步,即可在页面中添加一个功能完整的画布编辑器:
第一步:引入库文件
html
第二步:添加编辑器标签
html
第三步:设置样式
css
canvas-drawing-editor {
width: 100%;
height: 600px;
display: block;
}
完整示例
html
Canvas Drawing Editor 示例
canvas-drawing-editor {
width: 100%;
height: 100vh;
display: block;
}
// 监听画布变化事件
document.addEventListener('editor-change', (e) => {
console.log('画布内容变化:', e.detail.objects);
});
安装指南
NPM 安装(推荐)
bash
npm install canvas-drawing-editor
或使用 yarn:
bash
yarn add canvas-drawing-editor
或使用 pnpm:
bash
pnpm add canvas-drawing-editor
CDN 引入
如果不使用包管理器,可以直接通过 CDN 引入:
html
ES Module 引入
javascript
// 在项目中导入
import 'canvas-drawing-editor';
// 或导入特定类型(TypeScript)
import { CanvasDrawingEditor, ToolType, CanvasObject } from 'canvas-drawing-editor';
框架集成
原生 HTML
原生 HTML 是最简单的集成方式,无需任何构建工具:
html
Canvas Drawing Editor
* { margin: 0; padding: 0; box-sizing: border-box; }
canvas-drawing-editor {
width: 100vw;
height: 100vh;
display: block;
}
// 获取编辑器实例
const editor = document.querySelector('canvas-drawing-editor');
// 监听编辑器事件
document.addEventListener('editor-change', (e) => {
console.log('画布内容变化:', e.detail.objects);
// 可以在这里保存数据到服务器或 localStorage
});
document.addEventListener('editor-close', () => {
console.log('编辑器已关闭');
});
Vue 3
在 Vue 3 项目中使用 Canvas Drawing Editor:
1. 安装
bash
npm install canvas-drawing-editor
2. 基础使用
vue
import 'canvas-drawing-editor';
3. 完整示例(带配置和事件监听)
vue
import { ref, computed, onMounted, onUnmounted } from 'vue';
import 'canvas-drawing-editor';
// 配置项
const editorTitle = ref('Vue3 画板');
const lang = ref('zh');
const themeColor = ref('#5450dc');
// 工具配置
const toolConfig = ref({
pencil: true,
rectangle: true,
circle: true,
line: true,
arrow: true,
polygon: true,
text: true,
image: true,
undo: true,
redo: true,
zoom: true,
download: true,
exportJson: true,
importJson: true,
clear: true,
color: true,
layers: true,
group: true,
align: true
});
// 转换为 JSON 字符串
const toolConfigStr = computed(() => JSON.stringify(toolConfig.value));
// 事件处理
const handleEditorChange = (e: CustomEvent) => {
console.log('画布内容变化:', e.detail.objects);
// 保存到 localStorage
localStorage.setItem('canvas-data', JSON.stringify({ objects: e.detail.objects }));
};
onMounted(() => {
document.addEventListener('editor-change', handleEditorChange as EventListener);
});
onUnmounted(() => {
document.removeEventListener('editor-change', handleEditorChange as EventListener);
});
.editor {
width: 100%;
height: 100vh;
display: block;
}
4. 消除控制台警告(可选)
如果控制台出现 Failed to resolve component: canvas-drawing-editor 警告,可在 vite.config.ts 中添加以下配置:
typescript
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
// 将 canvas-drawing-editor 标记为自定义元素
isCustomElement: (tag) => tag === 'canvas-drawing-editor'
}
}
})
]
});
Vue 2
Vue 2 的集成方式与 Vue 3 类似:
1. main.js 配置
javascript
import Vue from 'vue';
import App from './App.vue';
// 引入 Canvas Drawing Editor
import 'canvas-drawing-editor';
// 可选:消除控制台警告
Vue.config.ignoredElements = ['canvas-drawing-editor'];
new Vue({
render: h => h(App)
}).$mount('#app');
2. 组件使用
vue
export default {
data() {
return {
themeColor: '#5450dc'
};
},
mounted() {
document.addEventListener('editor-change', this.handleChange);
},
beforeDestroy() {
document.removeEventListener('editor-change', this.handleChange);
},
methods: {
handleChange(e) {
console.log('画布内容变化:', e.detail.objects);
}
}
};
React
在 React 项目中使用 Canvas Drawing Editor:
1. 安装
bash
npm install canvas-drawing-editor
2. TypeScript 类型声明
为了获得更好的类型支持,可以添加类型声明:
tsx
// types/canvas-drawing-editor.d.ts
declare global {
namespace JSX {
interface IntrinsicElements {
'canvas-drawing-editor': React.DetailedHTMLProps<
React.HTMLAttributes & {
title?: string;
lang?: string;
'theme-color'?: string;
'tool-config'?: string;
'initial-data'?: string;
'enable-hotzone'?: string;
'hotzone-data'?: string;
},
HTMLElement
>;
}
}
}
3. 完整使用示例
tsx
import { useEffect, useRef } from 'react';
import 'canvas-drawing-editor';
function App() {
const editorRef = useRef(null);
// 工具配置
const toolConfig = {
pencil: true,
rectangle: true,
circle: true,
line: true,
arrow: true,
polygon: true,
text: true,
image: true,
undo: true,
redo: true,
zoom: true,
download: true,
exportJson: true,
importJson: true,
clear: true,
color: true,
layers: true,
group: true,
align: true
};
useEffect(() => {
// 监听编辑器事件
const handleEditorChange = (e: Event) => {
const customEvent = e as CustomEvent;
console.log('画布内容变化:', customEvent.detail.objects);
};
const handleEditorClose = () => {
console.log('编辑器已关闭');
};
document.addEventListener('editor-change', handleEditorChange);
document.addEventListener('editor-close', handleEditorClose);
return () => {
document.removeEventListener('editor-change', handleEditorChange);
document.removeEventListener('editor-close', handleEditorClose);
};
}, []);
return (
<div>
</div>
);
}
export default App;
Angular
在 Angular 项目中使用 Canvas Drawing Editor:
1. 安装
bash
npm install canvas-drawing-editor
2. 配置 CUSTOM_ELEMENTS_SCHEMA
Angular 需要添加 CUSTOM_ELEMENTS_SCHEMA 来支持 Web Component:
typescript
// app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
// 引入 Canvas Drawing Editor
import 'canvas-drawing-editor';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA], // 添加这行
bootstrap: [AppComponent]
})
export class AppModule { }
3. 组件使用
typescript
// app.component.ts
import { Component, OnInit, OnDestroy, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import 'canvas-drawing-editor';
@Component({
selector: 'app-root',
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
`
})
export class AppComponent implements OnInit, OnDestroy {
editorTitle = 'Angular 画板';
lang = 'zh';
themeColor = '#5450dc';
toolConfig = {
pencil: true,
rectangle: true,
circle: true,
line: true,
arrow: true,
polygon: true,
text: true,
image: true,
undo: true,
redo: true,
zoom: true,
download: true,
exportJson: true,
importJson: true,
clear: true,
color: true,
layers: true,
group: true,
align: true
};
get toolConfigStr(): string {
return JSON.stringify(this.toolConfig);
}
private handleEditorChange = (e: Event) => {
const customEvent = e as CustomEvent;
console.log('画布内容变化:', customEvent.detail.objects);
};
ngOnInit(): void {
document.addEventListener('editor-change', this.handleEditorChange);
}
ngOnDestroy(): void {
document.removeEventListener('editor-change', this.handleEditorChange);
}
}
配置选项详解
Canvas Drawing Editor 提供了丰富的配置选项,让你可以完全自定义编辑器的行为和外观。
基础属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title |
string | "Canvas Editor" | 编辑器标题,显示在顶部 |
lang |
string | "zh" | 界面语言,支持 "zh"(中文)和 "en"(英文) |
theme-color |
string | "#5450dc" | 主题色,影响按钮、悬停状态、选中状态等 |
initial-data |
string | - | 初始化 JSON 数据,用于加载已有内容 |
enable-hotzone |
boolean | false | 是否启用热区功能(管理员模式) |
hotzone-data |
string | - | 热区变量数据(JSON 格式) |
tool-config |
string | - | 工具配置对象(JSON 格式) |
属性使用示例
html
动态更新属性
可以通过 JavaScript 动态更新编辑器属性:
javascript
const editor = document.querySelector('canvas-drawing-editor');
// 更新标题
editor.setAttribute('title', '新标题');
// 切换语言
editor.setAttribute('lang', 'en');
// 更改主题色
editor.setAttribute('theme-color', '#10b981');
// 加载新数据
editor.setAttribute('initial-data', JSON.stringify({
objects: [
{ id: 'rect1', type: 'RECTANGLE', x: 50, y: 50, width: 100, height: 80, color: '#ef4444', lineWidth: 2 }
]
}));
工具配置
通过 tool-config 属性可以精确控制工具栏中显示哪些工具。
tool-config 完整选项
javascript
const toolConfig = {
// 绘图工具
pencil: true, // 画笔工具
rectangle: true, // 矩形工具
circle: true, // 圆形工具
line: true, // 线条工具
arrow: true, // 箭头工具
polygon: true, // 多边形工具
text: true, // 文本工具
image: true, // 图片导入
// 操作工具
undo: true, // 撤销按钮
redo: true, // 重做按钮
zoom: true, // 缩放控制
// 文件操作
download: true, // PNG 导出
exportJson: true, // JSON 保存
importJson: true, // JSON 加载
clear: true, // 清空画布
// 样式工具
color: true, // 颜色选择器
// 高级功能
layers: true, // 图层管理
group: true, // 组合/解组
align: true // 对齐/分布
};
// 使用

旧版属性(向后兼容)
除了 tool-config,还支持单独的 show-* 属性,但推荐使用 tool-config:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
show-pencil |
boolean | true | 显示画笔工具 |
show-rectangle |
boolean | true | 显示矩形工具 |
show-circle |
boolean | true | 显示圆形工具 |
show-line |
boolean | true | 显示线条工具 |
show-arrow |
boolean | true | 显示箭头工具 |
show-polygon |
boolean | true | 显示多边形工具 |
show-text |
boolean | true | 显示文本工具 |
show-image |
boolean | true | 显示图片导入 |
show-undo |
boolean | true | 显示撤销按钮 |
show-redo |
boolean | true | 显示重做按钮 |
show-zoom |
boolean | true | 显示缩放控制 |
show-download |
boolean | true | 显示 PNG 导出 |
show-export |
boolean | true | 显示 JSON 保存 |
show-import |
boolean | true | 显示 JSON 加载 |
show-color |
boolean | true | 显示颜色选择器 |
show-clear |
boolean | true | 显示清空画布按钮 |
show-layers |
boolean | true | 显示图层管理 |
show-group |
boolean | true | 显示组合/解组 |
show-align |
boolean | true | 显示对齐/分布 |
绘图工具使用
选择工具(V)
选择工具是最基本的工具,用于选择、移动和变换对象。
操作方式:
- 单击:选择单个对象
- Shift + 点击:多选对象
- 框选:拖拽创建选择框,选中框内所有对象
- 拖拽:移动选中的对象
- 拖拽角点:缩放对象
- Shift + 拖拽角点:等比例缩放
- 拖拽旋转手柄:旋转对象
画笔工具(P)
自由绑制路径,适合手绑签名、草图等。
操作方式:
- 选择画笔工具
- 在画布上按住鼠标左键绘制
- 松开鼠标完成绘制
属性:
- 颜色:通过颜色选择器设置
- 线宽:默认为 3px

矩形工具(R)
绘制矩形或正方形。
操作方式:
- 选择矩形工具
- 在画布上按住鼠标左键拖拽
- 松开鼠标完成绘制
- 按住 Shift:绘制正方形

圆形工具(C)
绘制椭圆或正圆。
操作方式:
- 选择圆形工具
- 在画布上按住鼠标左键拖拽
- 松开鼠标完成绘制
- 按住 Shift:绘制正圆
线条工具(L)
绘制直线,支持三种线条样式。
操作方式:
- 选择线条工具
- 在画布上按住鼠标左键拖拽
- 松开鼠标完成绘制
线条样式:
- 实线(Solid)
- 虚线(Dashed)
- 点线(Dotted)
箭头工具(A)
绘制箭头,支持单向箭头和双向箭头。
操作方式:
- 选择箭头工具
- 在画布上按住鼠标左键拖拽
- 松开鼠标完成绘制
箭头类型:
- 单向箭头(Single):终点有箭头
- 双向箭头(Double):两端都有箭头
多边形工具
绘制正多边形,支持任意边数。
操作方式:
- 选择多边形工具
- 在画布上按住鼠标左键拖拽
- 调整多边形边数(3边=三角形,6边=六边形等)
文本工具(T)
添加文本内容。
操作方式:
- 选择文本工具
- 在画布上点击位置
- 输入文本内容
- 按 Enter 确认,按 Esc 取消
文本属性:
- 字体大小
- 颜色
- 加粗/斜体
富文本
支持在同一文本对象中使用不同的样式。
特性:
- 部分文字加粗
- 部分文字改色
- 部分文字斜体
- 混合样式
图片导入
导入本地图片到画布。
操作方式:
- 点击图片导入按钮
- 选择本地图片文件
- 图片将添加到画布中心
支持的格式:
- PNG
- JPG/JPEG
- GIF
- WebP
- SVG
图片操作:
- 缩放
- 旋转
- 应用滤镜(亮度/对比度)



高级功能
图层管理
Canvas Drawing Editor 提供完整的图层管理功能。
功能列表:
| 功能 | 说明 |
|---|---|
| 上移图层 | 将选中对象上移一层 |
| 下移图层 | 将选中对象下移一层 |
| 置于顶层 | 将选中对象移到最顶层 |
| 置于底层 | 将选中对象移到最底层 |
| 显示/隐藏 | 控制图层可见性 |
| 锁定/解锁 | 锁定图层防止误操作 |

对齐与分布
当选中多个对象时,可以使用对齐和分布功能。
对齐选项:
| 功能 | 说明 |
|---|---|
| 左对齐 | 所有对象左边缘对齐 |
| 水平居中 | 所有对象水平中心对齐 |
| 右对齐 | 所有对象右边缘对齐 |
| 顶对齐 | 所有对象顶边缘对齐 |
| 垂直居中 | 所有对象垂直中心对齐 |
| 底对齐 | 所有对象底边缘对齐 |
分布选项:
| 功能 | 说明 |
|---|---|
| 水平分布 | 对象之间水平间距相等 |
| 垂直分布 | 对象之间垂直间距相等 |

组合与解组
将多个对象组合成一个整体,方便统一操作。
操作方式:
- 组合 :选中多个对象,按
Ctrl+G或点击组合按钮 - 解组 :选中组合对象,按
Ctrl+Shift+G或点击解组按钮
组合特性:
- 组合后的对象作为整体移动、缩放、旋转
- 可以嵌套组合(组合中包含组合)
- 解组后恢复为独立对象

图片滤镜
对导入的图片应用滤镜效果。
支持的滤镜:
| 滤镜 | 范围 | 说明 |
|---|---|---|
| 亮度 | -100 ~ 100 | 调整图片亮度 |
| 对比度 | -100 ~ 100 | 调整图片对比度 |
| 模糊 | 0 ~ 20 | 高斯模糊效果 |
| 灰度 | 0 ~ 100 | 转换为灰度图 |
| 饱和度 | 0 ~ 200 | 调整色彩饱和度 |
热区功能
热区(Hotzone)是 Canvas Drawing Editor 的一个强大特性,允许在文本中使用动态变量,实现模板化的内容展示。
什么是热区?
热区功能允许你在文本中定义变量占位符,然后在运行时动态替换这些变量的值。这在以下场景非常有用:
- 证书生成:姓名、日期、编号等动态内容
- 海报模板:活动名称、时间、地点等
- 数据可视化:实时数据展示
- 个性化内容:用户信息、订单详情等


热区使用流程
热区功能分为两个模式:
- 管理员模式:设计模板,定义变量
- 用户模式:查看渲染后的内容
管理员模式(设计模板)
html
在管理员模式下:
- 添加文本对象
- 在文本中使用
{{变量名}}语法定义变量 - 例如:
尊敬的 {{userName}},您的订单 {{orderId}} 已确认 - 保存模板 JSON
用户模式(展示内容)
html
javascript
// 热区变量数据
const hotzoneVariables = JSON.stringify({
userName: '张三',
orderId: 'ORD-2024-001',
date: '2024年1月15日'
});
热区变量语法
| 语法 | 说明 | 示例 |
|---|---|---|
{{变量名}} |
基本变量 | {{userName}} |
{{日期}} |
中文变量名 | {{创建时间}} |
{{data.name}} |
嵌套变量 | {{user.email}} |
完整热区示例
管理员端(设计模板):
html
热区模板设计
canvas-drawing-editor { width: 100%; height: 600px; display: block; }
document.addEventListener('editor-change', (e) => {
// 保存模板数据
const templateData = JSON.stringify({ objects: e.detail.objects });
localStorage.setItem('certificate-template', templateData);
console.log('模板已保存');
});
用户端(展示证书):
html
我的证书
canvas-drawing-editor { width: 100%; height: 600px; display: block; }
// 加载模板
const templateData = localStorage.getItem('certificate-template');
// 定义变量值
const hotzoneData = {
userName: '李明',
courseName: 'Web 前端开发',
completionDate: '2024年1月20日',
certificateNo: 'CERT-2024-00123'
};
const editor = document.getElementById('certificate');
editor.setAttribute('initial-data', templateData);
editor.setAttribute('hotzone-data', JSON.stringify(hotzoneData));
Tween 动画系统
Canvas Drawing Editor 内置了强大的 Tween 动画系统,可以为画布上的对象添加流畅的动画效果。
动画基础
Tween 动画可以平滑地改变对象的属性值,如位置、大小、旋转角度、透明度等。
可动画属性
| 属性 | 说明 | 示例值 |
|---|---|---|
x |
X 坐标 | 100, 200, 300 |
y |
Y 坐标 | 50, 150, 250 |
width |
宽度 | 100, 200 |
height |
高度 | 80, 160 |
rotation |
旋转角度(度) | 0, 90, 180, 360 |
opacity |
透明度 | 0 ~ 1 |
scaleX |
X 轴缩放 | 0.5, 1, 2 |
scaleY |
Y 轴缩放 | 0.5, 1, 2 |
缓动函数
Canvas Drawing Editor 提供了丰富的缓动函数,让动画更加生动:
| 缓动函数 | 说明 |
|---|---|
linear |
线性,匀速运动 |
easeInQuad |
二次方缓入 |
easeOutQuad |
二次方缓出 |
easeInOutQuad |
二次方缓入缓出 |
easeInCubic |
三次方缓入 |
easeOutCubic |
三次方缓出 |
easeInOutCubic |
三次方缓入缓出 |
easeInQuart |
四次方缓入 |
easeOutQuart |
四次方缓出 |
easeInOutQuart |
四次方缓入缓出 |
easeInElastic |
弹性缓入 |
easeOutElastic |
弹性缓出 |
easeInOutElastic |
弹性缓入缓出 |
easeOutBounce |
弹跳缓出 |
使用 tweenAnimate API
javascript
// 获取编辑器实例
const editor = document.querySelector('canvas-drawing-editor');
// 基本动画
editor.tweenAnimate({
objectId: 'rect-001', // 目标对象 ID
property: 'x', // 动画属性
from: 100, // 起始值
to: 500, // 结束值
duration: 1000, // 持续时间(毫秒)
easing: 'easeOutQuad' // 缓动函数
});
// 旋转动画
editor.tweenAnimate({
objectId: 'star-001',
property: 'rotation',
from: 0,
to: 360,
duration: 2000,
easing: 'linear',
loop: true // 循环播放
});
// 透明度动画(淡入淡出)
editor.tweenAnimate({
objectId: 'text-001',
property: 'opacity',
from: 0,
to: 1,
duration: 500,
easing: 'easeInOutQuad'
});
动画配置选项
typescript
interface TweenConfig {
objectId: string; // 目标对象 ID
property: string; // 动画属性
from: number; // 起始值
to: number; // 结束值
duration: number; // 持续时间(毫秒)
easing?: string; // 缓动函数,默认 'linear'
delay?: number; // 延迟开始(毫秒)
loop?: boolean; // 是否循环
yoyo?: boolean; // 是否往返(配合 loop 使用)
onStart?: () => void; // 动画开始回调
onUpdate?: (value: number) => void; // 每帧更新回调
onComplete?: () => void; // 动画完成回调
}
停止动画
javascript
// 停止所有动画
editor.stopAllAnimations();
// 停止特定对象的动画
editor.stopAnimation('rect-001');
动画事件
javascript
// 动画开始事件
document.addEventListener('animation-start', (e) => {
console.log('动画开始:', e.detail.objectId, e.detail.property);
});
// 动画更新事件
document.addEventListener('animation-update', (e) => {
console.log('动画进度:', e.detail.progress);
});
// 动画完成事件
document.addEventListener('animation-complete', (e) => {
console.log('动画完成:', e.detail.objectId);
});
复杂动画示例
javascript
// 组合动画:移动 + 旋转 + 缩放
const editor = document.querySelector('canvas-drawing-editor');
// 同时执行多个动画
editor.tweenAnimate({
objectId: 'star-001',
property: 'x',
from: 100,
to: 400,
duration: 2000,
easing: 'easeInOutQuad'
});
editor.tweenAnimate({
objectId: 'star-001',
property: 'rotation',
from: 0,
to: 720,
duration: 2000,
easing: 'linear'
});
editor.tweenAnimate({
objectId: 'star-001',
property: 'scaleX',
from: 1,
to: 1.5,
duration: 1000,
easing: 'easeOutElastic',
yoyo: true,
loop: true
});
事件监听
Canvas Drawing Editor 通过自定义事件与外部通信。
可用事件
| 事件名 | 触发时机 | 事件数据 |
|---|---|---|
editor-change |
画布内容变化时 | { objects: CanvasObject[] } |
editor-close |
编辑器关闭时 | 无 |
animation-start |
动画开始时 | { objectId, property } |
animation-update |
动画每帧更新时 | { objectId, property, progress, value } |
animation-complete |
动画完成时 | { objectId, property } |
事件监听示例
javascript
// 监听画布变化
document.addEventListener('editor-change', (e) => {
const { objects } = e.detail;
console.log('画布对象数量:', objects.length);
// 自动保存到 localStorage
localStorage.setItem('canvas-backup', JSON.stringify({ objects }));
});
// 监听编辑器关闭
document.addEventListener('editor-close', () => {
console.log('编辑器已关闭');
// 可以在这里执行清理操作
});
// 监听动画事件
document.addEventListener('animation-complete', (e) => {
const { objectId, property } = e.detail;
console.log(`对象 ${objectId} 的 ${property} 动画已完成`);
});
Vue 3 中监听事件
vue
import { onMounted, onUnmounted } from 'vue';
const handleEditorChange = (e) => {
console.log('画布变化:', e.detail.objects);
};
onMounted(() => {
document.addEventListener('editor-change', handleEditorChange);
});
onUnmounted(() => {
document.removeEventListener('editor-change', handleEditorChange);
});
React 中监听事件
tsx
import { useEffect } from 'react';
function App() {
useEffect(() => {
const handleEditorChange = (e: CustomEvent) => {
console.log('画布变化:', e.detail.objects);
};
document.addEventListener('editor-change', handleEditorChange as EventListener);
return () => {
document.removeEventListener('editor-change', handleEditorChange as EventListener);
};
}, []);
return ;
}
数据格式
JSON 数据结构
Canvas Drawing Editor 使用 JSON 格式保存和加载画布数据。
typescript
interface CanvasData {
objects: CanvasObject[];
}
interface CanvasObject {
id: string; // 唯一标识符
type: ToolType; // 对象类型
x: number; // X 坐标
y: number; // Y 坐标
color: string; // 颜色
lineWidth: number; // 线宽
rotation?: number; // 旋转角度
opacity?: number; // 透明度
locked?: boolean; // 是否锁定
visible?: boolean; // 是否可见
// ... 其他属性根据类型不同而不同
}
对象类型(ToolType)
| 类型 | 说明 | 特有属性 |
|---|---|---|
PENCIL |
画笔路径 | points: Point[] |
RECTANGLE |
矩形 | width, height, fillColor, lineStyle |
CIRCLE |
圆形 | radiusX, radiusY, fillColor |
LINE |
线条 | endX, endY, lineStyle |
ARROW |
箭头 | endX, endY, arrowType |
POLYGON |
多边形 | sides, radius |
TEXT |
文本 | text, fontSize, fontFamily, bold, italic |
RICH_TEXT |
富文本 | segments: TextSegment[] |
IMAGE |
图片 | src, width, height, filters |
TRIANGLE |
三角形 | width, height |
STAR |
星形 | points, innerRadius, outerRadius |
HEART |
心形 | size |
DIAMOND |
菱形 | width, height |
BEZIER |
贝塞尔曲线 | controlPoints: Point[] |
GROUP |
组合 | children: CanvasObject[] |
矩形对象示例
json
{
"id": "rect-001",
"type": "RECTANGLE",
"x": 100,
"y": 100,
"width": 200,
"height": 150,
"color": "#3b82f6",
"fillColor": "#93c5fd",
"lineWidth": 2,
"lineStyle": "solid",
"rotation": 0,
"opacity": 1,
"locked": false,
"visible": true
}
文本对象示例
json
{
"id": "text-001",
"type": "TEXT",
"x": 200,
"y": 200,
"text": "Hello World",
"fontSize": 24,
"fontFamily": "Arial",
"color": "#1f2937",
"bold": false,
"italic": false,
"rotation": 0
}
图片对象示例
json
{
"id": "image-001",
"type": "IMAGE",
"x": 50,
"y": 50,
"width": 300,
"height": 200,
"src": "data:image/png;base64,...",
"rotation": 0,
"filters": {
"brightness": 0,
"contrast": 0,
"blur": 0,
"grayscale": 0,
"saturation": 100
}
}
组合对象示例
json
{
"id": "group-001",
"type": "GROUP",
"x": 100,
"y": 100,
"children": [
{
"id": "rect-002",
"type": "RECTANGLE",
"x": 0,
"y": 0,
"width": 100,
"height": 80
},
{
"id": "text-002",
"type": "TEXT",
"x": 10,
"y": 30,
"text": "标签"
}
]
}
API 参考
编辑器实例方法
获取编辑器实例后,可以调用以下方法:
javascript
const editor = document.querySelector('canvas-drawing-editor');
exportJSON()
导出画布数据为 JSON 格式。
javascript
const jsonData = editor.exportJSON();
console.log(jsonData);
// 输出: { objects: [...] }
// 保存到文件
const blob = new Blob([JSON.stringify(jsonData)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'canvas-data.json';
a.click();
exportPNG(options?)
导出画布为 PNG 图片。
javascript
// 基本导出
const pngDataUrl = editor.exportPNG();
// 带选项导出
const pngDataUrl = editor.exportPNG({
scale: 2, // 缩放倍数,用于高清导出
backgroundColor: '#ffffff' // 背景色
});
// 下载图片
const a = document.createElement('a');
a.href = pngDataUrl;
a.download = 'canvas-image.png';
a.click();
tweenAnimate(config)
执行 Tween 动画。
javascript
editor.tweenAnimate({
objectId: 'rect-001',
property: 'x',
from: 100,
to: 500,
duration: 1000,
easing: 'easeOutQuad'
});
stopAllAnimations()
停止所有正在进行的动画。
javascript
editor.stopAllAnimations();
stopAnimation(objectId)
停止特定对象的动画。
javascript
editor.stopAnimation('rect-001');
完整 API 列表
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
exportJSON() |
无 | CanvasData |
导出 JSON 数据 |
exportPNG(options?) |
ExportOptions |
string |
导出 PNG DataURL |
tweenAnimate(config) |
TweenConfig |
TweenInstance |
执行动画 |
stopAllAnimations() |
无 | void |
停止所有动画 |
stopAnimation(id) |
string |
void |
停止特定动画 |
移动端支持
Canvas Drawing Editor 完全支持移动端触摸操作。
触摸手势
| 手势 | 操作 |
|---|---|
| 单指点击 | 选择对象 |
| 单指拖拽 | 移动对象/绘制 |
| 双指捏合 | 缩放画布 |
| 双指旋转 | 旋转画布 |
| 长按 | 显示上下文菜单 |
移动端优化
编辑器针对移动端做了以下优化:
- 触摸区域放大:控制手柄更大,便于触摸操作
- 手势识别:智能识别单指/双指操作
- 惯性滚动:平滑的画布滚动体验
- 响应式布局:工具栏自适应屏幕宽度
移动端示例
html
移动端画板
* { margin: 0; padding: 0; }
html, body {
width: 100%;
height: 100%;
overflow: hidden;
touch-action: none;
}
canvas-drawing-editor {
width: 100%;
height: 100%;
display: block;
}
键盘快捷键
Canvas Drawing Editor 支持丰富的键盘快捷键,提高操作效率。
工具快捷键
| 快捷键 | 功能 |
|---|---|
V |
选择工具 |
P |
画笔工具 |
R |
矩形工具 |
C |
圆形工具 |
L |
线条工具 |
A |
箭头工具 |
T |
文本工具 |
编辑快捷键
| 快捷键 | 功能 |
|---|---|
Ctrl + Z |
撤销 |
Ctrl + Y |
重做 |
Ctrl + Shift + Z |
重做(备选) |
Ctrl + C |
复制 |
Ctrl + V |
粘贴 |
Ctrl + X |
剪切 |
Ctrl + A |
全选 |
Delete / Backspace |
删除选中对象 |
Escape |
取消选择/取消操作 |
组合快捷键
| 快捷键 | 功能 |
|---|---|
Ctrl + G |
组合选中对象 |
Ctrl + Shift + G |
解组 |
视图快捷键
| 快捷键 | 功能 |
|---|---|
Ctrl + + |
放大 |
Ctrl + - |
缩小 |
Ctrl + 0 |
重置缩放 |
Space + 拖拽 |
平移画布 |
辅助快捷键
| 快捷键 | 功能 |
|---|---|
Shift + 拖拽 |
等比例缩放 |
Alt + 拖拽 |
从中心缩放 |
Shift + 绘制 |
绘制正方形/正圆 |
最佳实践
1. 性能优化
控制对象数量
javascript
// 定期清理不需要的对象
document.addEventListener('editor-change', (e) => {
const { objects } = e.detail;
if (objects.length > 500) {
console.warn('画布对象过多,可能影响性能');
}
});
使用适当的图片尺寸
javascript
// 导入图片前压缩
function compressImage(file, maxWidth = 1920) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
const ratio = Math.min(maxWidth / img.width, 1);
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
resolve(canvas.toDataURL('image/jpeg', 0.8));
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
});
}
2. 数据持久化
自动保存
javascript
let saveTimeout;
document.addEventListener('editor-change', (e) => {
// 防抖:500ms 内的多次变化只保存一次
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
const data = JSON.stringify({ objects: e.detail.objects });
localStorage.setItem('canvas-autosave', data);
console.log('自动保存成功');
}, 500);
});
加载保存的数据
javascript
window.addEventListener('load', () => {
const savedData = localStorage.getItem('canvas-autosave');
if (savedData) {
const editor = document.querySelector('canvas-drawing-editor');
editor.setAttribute('initial-data', savedData);
}
});
3. 错误处理
javascript
// 监听加载错误
try {
const editor = document.querySelector('canvas-drawing-editor');
const data = JSON.parse(localStorage.getItem('canvas-data'));
if (data && data.objects) {
editor.setAttribute('initial-data', JSON.stringify(data));
}
} catch (error) {
console.error('加载画布数据失败:', error);
// 清除损坏的数据
localStorage.removeItem('canvas-data');
}
4. 响应式设计
css
/* 桌面端 */
canvas-drawing-editor {
width: 100%;
height: calc(100vh - 60px);
}
/* 平板端 */
@media (max-width: 1024px) {
canvas-drawing-editor {
height: calc(100vh - 50px);
}
}
/* 移动端 */
@media (max-width: 768px) {
canvas-drawing-editor {
height: calc(100vh - 40px);
}
}
5. 与后端集成
javascript
// 保存到服务器
async function saveToServer(objects) {
try {
const response = await fetch('/api/canvas/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ objects })
});
if (!response.ok) {
throw new Error('保存失败');
}
const result = await response.json();
console.log('保存成功:', result.id);
return result;
} catch (error) {
console.error('保存到服务器失败:', error);
throw error;
}
}
// 从服务器加载
async function loadFromServer(canvasId) {
try {
const response = await fetch(`/api/canvas/${canvasId}`);
if (!response.ok) {
throw new Error('加载失败');
}
const data = await response.json();
const editor = document.querySelector('canvas-drawing-editor');
editor.setAttribute('initial-data', JSON.stringify(data));
} catch (error) {
console.error('从服务器加载失败:', error);
}
}
常见问题
Q1: 编辑器不显示或显示空白
可能原因:
- 未正确引入库文件
- 未设置编辑器尺寸
解决方案:
html
canvas-drawing-editor {
width: 100%;
height: 600px;
display: block; /* 重要! */
}
Q2: Vue/React 控制台出现警告
Vue 警告: Failed to resolve component: canvas-drawing-editor
解决方案(Vue 3 + Vite):
typescript
// vite.config.ts
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag === 'canvas-drawing-editor'
}
}
})
]
});
解决方案(Vue 2):
javascript
// main.js
Vue.config.ignoredElements = ['canvas-drawing-editor'];
Q3: 事件监听不生效
可能原因: 事件是在 document 上触发的,而不是编辑器元素上。
正确做法:
javascript
// ✅ 正确
document.addEventListener('editor-change', handler);
// ❌ 错误
editor.addEventListener('editor-change', handler);
Q4: 初始数据加载失败
可能原因:
- JSON 格式错误
- 数据结构不正确
解决方案:
javascript
// 确保数据格式正确
const validData = {
objects: [
{
id: 'unique-id', // 必须有唯一 ID
type: 'RECTANGLE', // 必须是有效的类型
x: 100,
y: 100,
width: 200,
height: 150,
color: '#3b82f6',
lineWidth: 2
}
]
};
editor.setAttribute('initial-data', JSON.stringify(validData));
Q5: 导出的 PNG 图片模糊
解决方案:
javascript
// 使用 scale 参数导出高清图片
const pngDataUrl = editor.exportPNG({
scale: 2 // 2倍分辨率
});
Q6: 移动端触摸不灵敏
解决方案:
html
html, body {
touch-action: none;
overflow: hidden;
}
Q7: 如何获取特定对象
javascript
document.addEventListener('editor-change', (e) => {
const { objects } = e.detail;
// 按 ID 查找
const targetObject = objects.find(obj => obj.id === 'my-object-id');
// 按类型筛选
const rectangles = objects.filter(obj => obj.type === 'RECTANGLE');
// 按属性筛选
const redObjects = objects.filter(obj => obj.color === '#ff0000');
});
Q8: 如何实现协同编辑
Canvas Drawing Editor 本身不提供协同编辑功能,但可以通过以下方式实现:
javascript
// 使用 WebSocket 同步数据
const ws = new WebSocket('wss://your-server.com/canvas');
// 发送本地变化
document.addEventListener('editor-change', (e) => {
ws.send(JSON.stringify({
type: 'canvas-update',
objects: e.detail.objects
}));
});
// 接收远程变化
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'canvas-update') {
const editor = document.querySelector('canvas-drawing-editor');
editor.setAttribute('initial-data', JSON.stringify({ objects: data.objects }));
}
};
总结
Canvas Drawing Editor 是一个功能强大、易于使用的 Canvas 画布编辑器。它的主要优势包括:
- 零依赖:无需任何框架,纯 JavaScript 实现
- 跨框架:支持 Vue、React、Angular 和原生 HTML
- 功能丰富:20+ 绘图工具,完整的编辑功能
- 高度可定制:灵活的配置选项和 API
- 移动端友好:完整的触摸手势支持
- 动画系统:内置 Tween 动画引擎
- 热区功能:支持动态变量模板
无论是简单的绘图应用,还是复杂的图形编辑器,Canvas Drawing Editor 都能满足你的需求。
相关链接
- Gitee 仓库:
- GitHub 仓库:
- NPM 包:
- 在线演示:
- 问题反馈:
许可证
MIT License
Copyright (c) 2025 typsusan
感谢使用 Canvas Drawing Editor!如果这个项目对你有帮助,请给我们一个 ⭐ Star!

