Web Components实战:打造轻量级图片编辑器

Canvas Drawing Editor 完整使用指南

一个强大的、零依赖的 Canvas 画布编辑器 Web Component

Giteehttps://gitee.com/susantyp/canvas-drawing-editor

GitHub: https://github.com/typsusan-zzz/canvas-drawing-editor

NPM: https://www.npmjs.com/package/canvas-drawing-editor

在线演示: https://typsusan-zzz.github.io/canvas-drawing-editor/


目录

  1. 简介
  2. 为什么选择 Canvas Drawing Editor
  3. 功能特性
  4. 快速开始
  5. 安装指南
  6. 框架集成
  7. 配置选项详解
  8. 工具配置
  9. 绘图工具使用
  10. 高级功能
  11. 热区功能
  12. Tween 动画系统
  13. 事件监听
  14. 数据格式
  15. API 参考
  16. 移动端支持
  17. 键盘快捷键
  18. 最佳实践
  19. 常见问题

简介

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 标签一样简单 -->
<canvas-drawing-editor title="我的画板"></canvas-drawing-editor>

3. 企业级功能

虽然轻量,但功能完整:

  • 20+ 绑图工具
  • 完整的撤销/重做历史
  • 图层管理系统
  • 热区模板功能
  • Tween 动画引擎
  • 多种导出格式

Canvas Drawing Editor 与主流 Canvas 库对比

功能特性Canvas Drawing EditorFabric.jsKonva.jsExcalidrawtldraw
基本信息
打包体积 (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 图片
清空画布一键清空所有内容

快速开始

最简示例

只需三步,即可在页面中添加一个功能完整的画布编辑器:

第一步:引入库文件

<script src="https://unpkg.com/canvas-drawing-editor/dist/canvas-drawing-editor.umd.js"></script>

第二步:添加编辑器标签

<canvas-drawing-editor title="我的画板"></canvas-drawing-editor>

第三步:设置样式

canvas-drawing-editor {
  width: 100%;
  height: 600px;
  display: block;
}

完整示例

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Canvas Drawing Editor 示例</title>
  <style>
    canvas-drawing-editor {
      width: 100%;
      height: 100vh;
      display: block;
    }
  </style>
</head>
<body>
  <canvas-drawing-editor
    title="我的画板"
    lang="zh"
    theme-color="#5450dc"
  ></canvas-drawing-editor>

  <script src="https://unpkg.com/canvas-drawing-editor/dist/canvas-drawing-editor.umd.js"></script>

  <script>
    // 监听画布变化事件
    document.addEventListener('editor-change', (e) => {
      console.log('画布内容变化:', e.detail.objects);
    });
  </script>
</body>
</html>

安装指南

NPM 安装(推荐)

npm install canvas-drawing-editor

或使用 yarn:

yarn add canvas-drawing-editor

或使用 pnpm:

pnpm add canvas-drawing-editor

CDN 引入

如果不使用包管理器,可以直接通过 CDN 引入:

<!-- unpkg -->
<script src="https://unpkg.com/canvas-drawing-editor/dist/canvas-drawing-editor.umd.js"></script>

<!-- 或指定版本 -->
<script src="https://unpkg.com/canvas-drawing-editor@latest/dist/canvas-drawing-editor.umd.js"></script>

ES Module 引入

// 在项目中导入
import 'canvas-drawing-editor';

// 或导入特定类型(TypeScript)
import { CanvasDrawingEditor, ToolType, CanvasObject } from 'canvas-drawing-editor';

框架集成

原生 HTML

原生 HTML 是最简单的集成方式,无需任何构建工具:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Canvas Drawing Editor</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    canvas-drawing-editor {
      width: 100vw;
      height: 100vh;
      display: block;
    }
  </style>
</head>
<body>
  <canvas-drawing-editor
    title="我的画布"
    lang="zh"
    theme-color="#5450dc"
  ></canvas-drawing-editor>

  <script src="https://unpkg.com/canvas-drawing-editor/dist/canvas-drawing-editor.umd.js"></script>

  <script>
    // 获取编辑器实例
    const editor = document.querySelector('canvas-drawing-editor');

    // 监听编辑器事件
    document.addEventListener('editor-change', (e) => {
      console.log('画布内容变化:', e.detail.objects);
      // 可以在这里保存数据到服务器或 localStorage
    });

    document.addEventListener('editor-close', () => {
      console.log('编辑器已关闭');
    });
  </script>
</body>
</html>

Vue 3

在 Vue 3 项目中使用 Canvas Drawing Editor:

1. 安装

npm install canvas-drawing-editor

2. 基础使用

<template>
  <canvas-drawing-editor
    title="Vue 画板"
    style="width: 100%; height: 600px;"
  ></canvas-drawing-editor>
</template>

<script setup>
import 'canvas-drawing-editor';
</script>

3. 完整示例(带配置和事件监听)

<template>
  <canvas-drawing-editor
    :title="editorTitle"
    :lang="lang"
    :theme-color="themeColor"
    :tool-config="toolConfigStr"
    class="editor"
  ></canvas-drawing-editor>
</template>

<script setup lang="ts">
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);
});
</script>

<style scoped>
.editor {
  width: 100%;
  height: 100vh;
  display: block;
}
</style>

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. 组件使用

<template>
  <canvas-drawing-editor
    title="Vue2 画板"
    lang="zh"
    :theme-color="themeColor"
    style="width: 100%; height: 600px;"
  ></canvas-drawing-editor>
</template>

<script>
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);
    }
  }
};
</script>

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<HTMLElement> & {
          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<HTMLElement>(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 className="app">
      <canvas-drawing-editor
        ref={editorRef}
        title="React 画板"
        lang="zh"
        theme-color="#5450dc"
        tool-config={JSON.stringify(toolConfig)}
        style={{ width: '100%', height: '100vh', display: 'block' }}
      />
    </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: `
    <canvas-drawing-editor
      [attr.title]="editorTitle"
      [attr.lang]="lang"
      [attr.theme-color]="themeColor"
      [attr.tool-config]="toolConfigStr"
      style="width: 100%; height: 100vh; display: block;"
    ></canvas-drawing-editor>
  `
})
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 提供了丰富的配置选项,让你可以完全自定义编辑器的行为和外观。

基础属性

属性类型默认值说明
titlestring“Canvas Editor”编辑器标题,显示在顶部
langstring“zh”界面语言,支持 “zh”(中文)和 “en”(英文)
theme-colorstring“#5450dc”主题色,影响按钮、悬停状态、选中状态等
initial-datastring-初始化 JSON 数据,用于加载已有内容
enable-hotzonebooleanfalse是否启用热区功能(管理员模式)
hotzone-datastring-热区变量数据(JSON 格式)
tool-configstring-工具配置对象(JSON 格式)

属性使用示例

<canvas-drawing-editor
  title="我的画板"
  lang="zh"
  theme-color="#3b82f6"
  enable-hotzone="true"
  tool-config='{"pencil":true,"rectangle":true,"circle":true}'
  initial-data='{"objects":[{"id":"1","type":"RECTANGLE","x":100,"y":100,"width":200,"height":150,"color":"#3b82f6","lineWidth":2}]}'
></canvas-drawing-editor>

动态更新属性

可以通过 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        // 对齐/分布
};

// 使用
<canvas-drawing-editor
  tool-config={JSON.stringify(toolConfig)}
></canvas-drawing-editor>

在这里插入图片描述

旧版属性(向后兼容)

除了 tool-config,还支持单独的 show-* 属性,但推荐使用 tool-config

属性类型默认值说明
show-pencilbooleantrue显示画笔工具
show-rectanglebooleantrue显示矩形工具
show-circlebooleantrue显示圆形工具
show-linebooleantrue显示线条工具
show-arrowbooleantrue显示箭头工具
show-polygonbooleantrue显示多边形工具
show-textbooleantrue显示文本工具
show-imagebooleantrue显示图片导入
show-undobooleantrue显示撤销按钮
show-redobooleantrue显示重做按钮
show-zoombooleantrue显示缩放控制
show-downloadbooleantrue显示 PNG 导出
show-exportbooleantrue显示 JSON 保存
show-importbooleantrue显示 JSON 加载
show-colorbooleantrue显示颜色选择器
show-clearbooleantrue显示清空画布按钮
show-layersbooleantrue显示图层管理
show-groupbooleantrue显示组合/解组
show-alignbooleantrue显示对齐/分布

绘图工具使用

选择工具(V)

选择工具是最基本的工具,用于选择、移动和变换对象。

操作方式:

  • 单击:选择单个对象
  • Shift + 点击:多选对象
  • 框选:拖拽创建选择框,选中框内所有对象
  • 拖拽:移动选中的对象
  • 拖拽角点:缩放对象
  • Shift + 拖拽角点:等比例缩放
  • 拖拽旋转手柄:旋转对象

画笔工具(P)

自由绑制路径,适合手绑签名、草图等。

操作方式:

  1. 选择画笔工具
  2. 在画布上按住鼠标左键绘制
  3. 松开鼠标完成绘制

属性:

  • 颜色:通过颜色选择器设置
  • 线宽:默认为 3px
    在这里插入图片描述

矩形工具(R)

绘制矩形或正方形。

操作方式:

  1. 选择矩形工具
  2. 在画布上按住鼠标左键拖拽
  3. 松开鼠标完成绘制
  4. 按住 Shift:绘制正方形

在这里插入图片描述

圆形工具(C)

绘制椭圆或正圆。

操作方式:

  1. 选择圆形工具
  2. 在画布上按住鼠标左键拖拽
  3. 松开鼠标完成绘制
  4. 按住 Shift:绘制正圆

线条工具(L)

绘制直线,支持三种线条样式。

操作方式:

  1. 选择线条工具
  2. 在画布上按住鼠标左键拖拽
  3. 松开鼠标完成绘制

线条样式:

  • 实线(Solid)
  • 虚线(Dashed)
  • 点线(Dotted)

箭头工具(A)

绘制箭头,支持单向箭头和双向箭头。

操作方式:

  1. 选择箭头工具
  2. 在画布上按住鼠标左键拖拽
  3. 松开鼠标完成绘制

箭头类型:

  • 单向箭头(Single):终点有箭头
  • 双向箭头(Double):两端都有箭头

多边形工具

绘制正多边形,支持任意边数。

操作方式:

  1. 选择多边形工具
  2. 在画布上按住鼠标左键拖拽
  3. 调整多边形边数(3边=三角形,6边=六边形等)

文本工具(T)

添加文本内容。

操作方式:

  1. 选择文本工具
  2. 在画布上点击位置
  3. 输入文本内容
  4. Enter 确认,按 Esc 取消

文本属性:

  • 字体大小
  • 颜色
  • 加粗/斜体

富文本

支持在同一文本对象中使用不同的样式。

特性:

  • 部分文字加粗
  • 部分文字改色
  • 部分文字斜体
  • 混合样式

图片导入

导入本地图片到画布。

操作方式:

  1. 点击图片导入按钮
  2. 选择本地图片文件
  3. 图片将添加到画布中心

支持的格式:

  • 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 的一个强大特性,允许在文本中使用动态变量,实现模板化的内容展示。

什么是热区?

热区功能允许你在文本中定义变量占位符,然后在运行时动态替换这些变量的值。这在以下场景非常有用:

  • 证书生成:姓名、日期、编号等动态内容
  • 海报模板:活动名称、时间、地点等
  • 数据可视化:实时数据展示
  • 个性化内容:用户信息、订单详情等

在这里插入图片描述

在这里插入图片描述

热区使用流程

热区功能分为两个模式:

  1. 管理员模式:设计模板,定义变量
  2. 用户模式:查看渲染后的内容
管理员模式(设计模板)
<canvas-drawing-editor
  title="模板设计器"
  enable-hotzone="true"
></canvas-drawing-editor>

在管理员模式下:

  1. 添加文本对象
  2. 在文本中使用 {{变量名}} 语法定义变量
  3. 例如:尊敬的 {{userName}},您的订单 {{orderId}} 已确认
  4. 保存模板 JSON
用户模式(展示内容)
<canvas-drawing-editor
  title="证书展示"
  enable-hotzone="false"
  :initial-data="templateData"
  :hotzone-data="hotzoneVariables"
></canvas-drawing-editor>
// 热区变量数据
const hotzoneVariables = JSON.stringify({
  userName: '张三',
  orderId: 'ORD-2024-001',
  date: '2024年1月15日'
});

热区变量语法

语法说明示例
{{变量名}}基本变量{{userName}}
{{日期}}中文变量名{{创建时间}}
{{data.name}}嵌套变量{{user.email}}

完整热区示例

管理员端(设计模板):

<!DOCTYPE html>
<html>
<head>
  <title>热区模板设计</title>
  <style>
    canvas-drawing-editor { width: 100%; height: 600px; display: block; }
  </style>
</head>
<body>
  <canvas-drawing-editor
    title="证书模板设计"
    lang="zh"
    enable-hotzone="true"
  ></canvas-drawing-editor>

  <script src="https://unpkg.com/canvas-drawing-editor/dist/canvas-drawing-editor.umd.js"></script>

  <script>
    document.addEventListener('editor-change', (e) => {
      // 保存模板数据
      const templateData = JSON.stringify({ objects: e.detail.objects });
      localStorage.setItem('certificate-template', templateData);
      console.log('模板已保存');
    });
  </script>
</body>
</html>

用户端(展示证书):

<!DOCTYPE html>
<html>
<head>
  <title>我的证书</title>
  <style>
    canvas-drawing-editor { width: 100%; height: 600px; display: block; }
  </style>
</head>
<body>
  <canvas-drawing-editor
    id="certificate"
    title="我的证书"
    lang="zh"
    enable-hotzone="false"
  ></canvas-drawing-editor>

  <script src="https://unpkg.com/canvas-drawing-editor/dist/canvas-drawing-editor.umd.js"></script>

  <script>
    // 加载模板
    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));
  </script>
</body>
</html>

Tween 动画系统

Canvas Drawing Editor 内置了强大的 Tween 动画系统,可以为画布上的对象添加流畅的动画效果。

动画基础

Tween 动画可以平滑地改变对象的属性值,如位置、大小、旋转角度、透明度等。

可动画属性

属性说明示例值
xX 坐标100, 200, 300
yY 坐标50, 150, 250
width宽度100, 200
height高度80, 160
rotation旋转角度(度)0, 90, 180, 360
opacity透明度0 ~ 1
scaleXX 轴缩放0.5, 1, 2
scaleYY 轴缩放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 中监听事件

<script setup>
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);
});
</script>

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 <canvas-drawing-editor />;
}

数据格式

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?)ExportOptionsstring导出 PNG DataURL
tweenAnimate(config)TweenConfigTweenInstance执行动画
stopAllAnimations()void停止所有动画
stopAnimation(id)stringvoid停止特定动画

移动端支持

Canvas Drawing Editor 完全支持移动端触摸操作。

触摸手势

手势操作
单指点击选择对象
单指拖拽移动对象/绘制
双指捏合缩放画布
双指旋转旋转画布
长按显示上下文菜单

移动端优化

编辑器针对移动端做了以下优化:

  1. 触摸区域放大:控制手柄更大,便于触摸操作
  2. 手势识别:智能识别单指/双指操作
  3. 惯性滚动:平滑的画布滚动体验
  4. 响应式布局:工具栏自适应屏幕宽度

移动端示例

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>移动端画板</title>
  <style>
    * { margin: 0; padding: 0; }
    html, body {
      width: 100%;
      height: 100%;
      overflow: hidden;
      touch-action: none;
    }
    canvas-drawing-editor {
      width: 100%;
      height: 100%;
      display: block;
    }
  </style>
</head>
<body>
  <canvas-drawing-editor
    title="移动画板"
    lang="zh"
  ></canvas-drawing-editor>

  <script src="https://unpkg.com/canvas-drawing-editor/dist/canvas-drawing-editor.umd.js"></script>
</body>
</html>

键盘快捷键

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. 性能优化

控制对象数量

// 定期清理不需要的对象
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 - 60px);
}

/* 平板端 */
@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: 编辑器不显示或显示空白

可能原因:

  1. 未正确引入库文件
  2. 未设置编辑器尺寸

解决方案:

<!-- 确保正确引入 -->
<script src="https://unpkg.com/canvas-drawing-editor/dist/canvas-drawing-editor.umd.js"></script>

<!-- 确保设置尺寸 -->
<style>
  canvas-drawing-editor {
    width: 100%;
    height: 600px;
    display: block;  /* 重要! */
  }
</style>

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: 初始数据加载失败

可能原因:

  1. JSON 格式错误
  2. 数据结构不正确

解决方案:

// 确保数据格式正确
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: 移动端触摸不灵敏

解决方案:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

<style>
  html, body {
    touch-action: none;
    overflow: hidden;
  }
</style>

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 都能满足你的需求。


相关链接


许可证

MIT License

Copyright © 2025 typsusan


感谢使用 Canvas Drawing Editor!如果这个项目对你有帮助,请给我们一个 ⭐ Star!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来自上海的这位朋友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值