C Canvas Drawing Editor 完整使用指南
一个强劲的、零依赖的 Canvas 画布编辑器 Web Component
Gitee :
GitHub :
NPM :
在线演示 :
目录
- 简介
- 为什么选择 Canvas Drawing Editor
- 功能特性 #JavaScript #Vue.js #Canvas
- 快速开始
- 安装指南
- 框架集成
- 原生 HTML
- Vue 3
- Vue 2
- React
- Angular
- 配置选项详解
- 工具配置
- 绘图工具使用
- 高级功能
- 图层管理
- 对齐与分布
- 组合与解组
- 图片滤镜
- 热区功能
- Tween 动画系统
- 事件监听
- 数据格式
- API 参考
- 移动端支持
- 键盘快捷键
- 最佳实践
- 常见问题
简介
Canvas Drawing Editor 是一个基于 HTML5 Canvas 的现代化画布编辑器,它以 Web Component 的形式封装,使其可以无缝集成到任何前端框架或原生 HTML 项目中。
核心优势
- 零依赖 :纯 JavaScript 实现,无需 React、Vue 等框架
- 轻量级 :gzip 压缩后仅约 33KB
- 跨框架 :支持 Vue 2/3、React、Angular 和原生 HTML
- 功能丰富 :涵盖绑图、编辑、导出等完整工作流
- 移动端友善 :支持触摸手势操作
C 为什么选择 Canvas Drawing Editor
在众多的画布编辑器库中,Canvas Drawing Editor 以其独特的优势脱颖而出:
1. 真正的零依赖
与市面上大多数需要依赖特定框架的画布库不同,Canvas Drawing Editor 是完全独立的。这意味着:
- 没有框架锁定
- 更小的包体积
- 更快的加载速度
- 更简单的集成方式
2. Web Component 标准
基于 Web Component 标准开发,享受原生浏览器支持:
3. 企业级功能
虽然轻量,但功能完整:
- 20+ 绑图工具
- 完整的撤销/重做历史
- 图层管理系统
- 热区模板功能
- Tween 动画引擎
- 多种导出格式
Canvas Drawing Editor 与主流 Canvas 库对比
| 功能特性 | Canvas Drawing Editor | Fabric.js | Konva.js | Excalidraw | tldraw | | —
| 基本信息 | | | | | | | 打包体积 (gzip) | ~33KB | ~90KB | ~60KB | ~500KB+
| 零依赖 | ✅ | ✅ | ✅ | ❌ (依赖 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 图片 | | 清空画布 | 一键清空所有内容 |
快速开始
最简示例
只需三步,即可在页面中添加一个功能完整的画布编辑器:
第一步:引入库文件
第二步:添加编辑器标签
第三步:设置样式
canvas-drawing-editor {
width: 100%;
height: 600px;
display: block;
}
完整示例
Canvas Drawing Editor 示例
canvas-drawing-editor {
width: 100%;
height: 100vh;
display: block;
}
// 监听画布变化事件 document.addEventListener('editor-change', (e) => { console.log('画布内容变化:', e.detail.objects); });
安装指南
NPM 安装(推荐)
npm install canvas-drawing-editor
或使用 yarn:
yarn add canvas-drawing-editor
或使用 pnpm:
pnpm add canvas-drawing-editor
CDN 引入
如果不使用包管理器,可以直接通过 CDN 引入:
ES Module 引入
// 在项目中导入
import 'canvas-drawing-editor';
// 或导入特定类型(TypeScript) import { CanvasDrawingEditor, ToolType, CanvasObject } from 'canvas-drawing-editor';
框架集成
原生 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. 安装
npm install canvas-drawing-editor
2. 基础使用
import 'canvas-drawing-editor';
3. 完整示例(带配置和事件监听)
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 中添加以下配置:
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 配置
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. 组件使用
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. 安装
npm install canvas-drawing-editor
2. TypeScript 类型声明
为了获得更好的类型支持,可以添加类型声明:
// 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. 完整使用示例
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. 安装
npm install canvas-drawing-editor
2. 配置 CUSTOM_ELEMENTS_SCHEMA
Angular 需要添加 CUSTOM_ELEMENTS_SCHEMA 来支持 Web Component:
// 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. 组件使用
// 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 | –
| enable-hotzone | boolean | false | 是否启用热区功能(管理员模式) | | hotzone-data | string | –
| tool-config | string | – | 工具配置对象(JSON 格式) |
属性使用示例
动态更新属性
可以通过 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 完整选项
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 的一个强劲特性,允许在文本中使用动态变量,实现模板化的内容展示。
什么是热区?
热区功能允许你在文本中定义变量占位符,然后在运行时动态替换这些变量的值。这在以下场景超级有用:
- 证书生成 :姓名、日期、编号等动态内容
- 海报模板 :活动名称、时间、地点等
- 数据可视化 :实时数据展示
- 个性化内容 :用户信息、订单详情等
热区使用流程
热区功能分为两个模式:
- 管理员模式 :设计模板,定义变量
- 用户模式 :查看渲染后的内容
管理员模式(设计模板)
在管理员模式下:
- 添加文本对象
- 在文本中使用 {{变量名}} 语法定义变量
- 例如: 尊敬的 {{userName}},您的订单 {{orderId}} 已确认
- 保存模板 JSON
用户模式(展示内容)
// 热区变量数据
const hotzoneVariables = JSON.stringify({
userName: '张三',
orderId: 'ORD-2024-001',
date: '2024年1月15日'
});
热区变量语法
| 语法 | 说明 | 示例 | | —
| {{变量名}} | 基本变量 | {{userName}} | | {{日期}} | 中文变量名 | {{创建时间}} | | {{data.name}} | 嵌套变量 | {{user.email}} |
完整热区示例
管理员端(设计模板):
热区模板设计
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('模板已保存'); });
用户端(展示证书):
我的证书
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
// 获取编辑器实例
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' });
动画配置选项
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; // 动画完成回调
}
停止动画
// 停止所有动画
editor.stopAllAnimations();
// 停止特定对象的动画 editor.stopAnimation('rect-001');
动画事件
// 动画开始事件
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); });
复杂动画示例
// 组合动画:移动 +
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 } |
事件监听示例
// 监听画布变化
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 中监听事件
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 中监听事件
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 格式保存和加载画布数据。
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[] |
矩形对象示例
{
"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
}
文本对象示例
{
"id": "text-001",
"type": "TEXT",
"x": 200,
"y": 200,
"text": "Hello World",
"fontSize": 24,
"fontFamily": "Arial",
"color": "#1f2937",
"bold": false,
"italic": false,
"rotation": 0
}
图片对象示例
{
"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
}
}
组合对象示例
{
"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 参考
编辑器实例方法
获取编辑器实例后,可以调用以下方法:
const editor = document.querySelector('canvas-drawing-editor');
exportJSON()
导出画布数据为 JSON 格式。
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 图片。
// 基本导出
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 动画。
editor.tweenAnimate({
objectId: 'rect-001',
property: 'x',
from: 100,
to: 500,
duration: 1000,
easing: 'easeOutQuad'
});
stopAllAnimations()
停止所有正在进行的动画。
editor.stopAllAnimations();
stopAnimation(objectId)
停止特定对象的动画。
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 完全支持移动端触摸操作。
触摸手势
| 手势 | 操作 | | —
| 单指点击 | 选择对象 | | 单指拖拽 | 移动对象/绘制 | | 双指捏合 | 缩放画布 | | 双指旋转 | 旋转画布 | | 长按 | 显示上下文菜单 |
移动端优化
编辑器针对移动端做了以下优化:
- 触摸区域放大 :控制手柄更大,便于触摸操作
- 手势识别 :智能识别单指/双指操作
- 惯性滚动 :平滑的画布滚动体验
- 响应式布局 :工具栏自适应屏幕宽度
移动端示例
移动端画板
* { 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 +
| Ctrl +
| Ctrl +
| Ctrl +
| Ctrl +
| Ctrl +
| Ctrl +
| Delete / Backspace | 删除选中对象 | | Escape | 撤销选择/撤销操作 |
组合快捷键
| 快捷键 | 功能 | | —
| Ctrl +
| Ctrl + Shift + G | 解组 |
视图快捷键
| 快捷键 | 功能 | | —
| Ctrl +
| Ctrl +
| Ctrl +
| Space + 拖拽 | 平移画布 |
辅助快捷键
| 快捷键 | 功能 | | —
| Shift +
| Alt +
| Shift + 绘制 | 绘制正方形/正圆 |
最佳实践
1. 性能优化
控制对象数量
// 定期清理不需要的对象
document.addEventListener('editor-change', (e) => {
const { objects } = e.detail;
if (objects.length > 500) {
console.warn('画布对象过多,可能影响性能');
}
});
使用适当的图片尺寸
// 导入图片前压缩
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. 数据持久化
自动保存
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); });
加载保存的数据
window.addEventListener('load', () => {
const savedData = localStorage.getItem('canvas-autosave');
if (savedData) {
const editor = document.querySelector('canvas-drawing-editor');
editor.setAttribute('initial-data', savedData);
}
});
3. 错误处理
// 监听加载错误
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. 响应式设计
/*
canvas-drawing-editor { width: 100%; height: calc(100vh -
}
/*
@media (max-width: 1024px) { canvas-drawing-editor { height: calc(100vh - 50px); } }
/*
@media (max-width: 768px) { canvas-drawing-editor { height: calc(100vh - 40px); } }
5. 与后端集成
// 保存到服务器
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: 编辑器不显示或显示空白
可能缘由:
- 未正确引入库文件
- 未设置编辑器尺寸
解决方案:
canvas-drawing-editor {
width: 100%;
height: 600px;
display: block; /* 重大! */
}
Q2: Vue/React 控制台出现警告
Vue 警告: Failed to resolve component: canvas-drawing-editor
解决方案(Vue 3 + Vite):
// vite.config.ts
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag === 'canvas-drawing-editor'
}
}
})
]
});
解决方案(Vue 2):
// main.js
Vue.config.ignoredElements = ['canvas-drawing-editor'];
Q3: 事件监听不生效
可能缘由: 事件是在 document 上触发的,而不是编辑器元素上。
正确做法:
// ✅ 正确
document.addEventListener('editor-change', handler);
// ❌ 错误 editor.addEventListener('editor-change', handler);
Q4: 初始数据加载失败
可能缘由:
- JSON 格式错误
- 数据结构不正确
解决方案:
// 确保数据格式正确
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 图片模糊
解决方案:
// 使用 scale 参数导出高清图片
const pngDataUrl = editor.exportPNG({
scale: 2 // 2倍分辨率
});
Q6: 移动端触摸不灵敏
解决方案:
html, body {
touch-action: none;
overflow: hidden;
}
Q7: 如何获取特定对象
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 本身不提供协同编辑功能,但可以通过以下方式实现:
// 使用 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!
