Skip to content

强大的 Canvas 画布编辑器 Web Component,零依赖,支持多种框架

Published:

原文链接


Canvas Drawing Editor

npm version GitHub

中文 | English

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

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

在线文档 / Documentation: https://typsusan-zzz.github.io/canvas-drawing-editor/


中文

一个强大的基于 Canvas 的画布编辑器 Web Component,零依赖,支持 Vue 2/3ReactAngular原生 HTML

✨ 功能特性

📦 安装

npm install canvas-drawing-editor

🚀 使用方法

原生 HTML

<!DOCTYPE html>
<html>
<head>
  <style>
    canvas-drawing-editor { width: 100%; height: 600px; display: block; }
  </style>
</head>
<body>
  <canvas-drawing-editor title="我的画板"></canvas-drawing-editor>

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

Vue 3

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

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

可选配置: 如果控制台出现 Failed to resolve component: canvas-drawing-editor 警告,可在 vite.config.ts 中添加以下配置来消除警告:

export default defineConfig({
  vue: {
    template: {
      compilerOptions: {
        isCustomElement: (tag) => tag === 'canvas-drawing-editor'
      }
    }
  }
});

Vue 2

// main.js
import 'canvas-drawing-editor'

// 可选:如需消除控制台警告
// Vue.config.ignoredElements = ['canvas-drawing-editor']
<template>
  <canvas-drawing-editor
    title="Vue2 画板"
    style="width: 100%; height: 600px;"
  ></canvas-drawing-editor>
</template>

React

import 'canvas-drawing-editor';

function App() {
  return (
    <canvas-drawing-editor
      title="React 画板"
      style={{ width: '100%', height: '600px' }}
    />
  );
}

Angular

// app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import 'canvas-drawing-editor';

@NgModule({
  // ...
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }
<!-- app.component.html -->
<canvas-drawing-editor
  title="Angular 画板"
  style="width: 100%; height: 600px;"
></canvas-drawing-editor>

⚙️ 配置项

基础属性

属性类型默认值说明
titlestring”Canvas Editor”编辑器标题
langstring”zh”界面语言(“zh” 中文,“en” 英文)
theme-colorstring”#5450dc”主题色(影响按钮、悬停状态等)
initial-datastring-初始化 JSON 数据(格式见下方)
enable-hotzonebooleanfalse是否启用热区功能(管理员模式)
hotzone-datastring-热区变量数据(JSON 格式,用于动态替换文本)
tool-configstring-工具配置对象(JSON 格式,见下方)

工具配置(tool-config)

推荐使用 tool-config 属性统一配置工具显示:

<canvas-drawing-editor
  tool-config='{"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}'
></canvas-drawing-editor>
配置项类型默认值说明
pencilbooleantrue画笔工具
rectanglebooleantrue矩形工具
circlebooleantrue圆形工具
linebooleantrue线条工具
arrowbooleantrue箭头工具
polygonbooleantrue多边形工具
textbooleantrue文本工具
imagebooleantrue图片导入
undobooleantrue撤销按钮
redobooleantrue重做按钮
zoombooleantrue缩放控制
downloadbooleantruePNG 导出
exportJsonbooleantrueJSON 保存
importJsonbooleantrueJSON 加载
clearbooleantrue清空画布
colorbooleantrue颜色选择器
layersbooleantrue图层管理
groupbooleantrue组合/解组
alignbooleantrue对齐/分布

旧版属性(向后兼容)

仍支持单独的 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显示对齐/分布

📊 初始化数据

可以通过 initial-data 属性传入 JSON 数据来初始化画布内容:

<canvas-drawing-editor
  initial-data='{"objects":[{"id":"abc123","type":"RECTANGLE","x":100,"y":100,"width":200,"height":150,"color":"#3b82f6","lineWidth":2}]}'
></canvas-drawing-editor>

📡 事件监听

editor-change 事件

当画布内容变化时触发。e.detail.objects 数组包含所有绑图对象。

document.addEventListener('editor-change', (e) => {
  console.log('对象列表:', e.detail.objects);
  // 保存到服务器或 localStorage
  localStorage.setItem('canvas-data', JSON.stringify({ objects: e.detail.objects }));
});

对象类型和属性说明

e.detail.objects 中每个对象都有以下基础属性:

属性类型说明
idstring唯一标识符
typestring对象类型:RECTANGLECIRCLEPATHTEXTRICH_TEXTIMAGELINEARROWPOLYGONTRIANGLESTARHEARTDIAMONDBEZIERGROUP
rotationnumber旋转角度(弧度,可选,默认 0)
opacitynumber透明度(0-1,可选,默认 1)
xnumberX 坐标
ynumberY 坐标
colorstring描边/填充颜色(十六进制格式,如 #3b82f6
lineWidthnumber线条宽度(像素)
visibleboolean是否可见(可选,默认 true)
lockedboolean是否锁定(可选,默认 false)

矩形 (type: "RECTANGLE"):

属性类型说明
widthnumber矩形宽度
heightnumber矩形高度

圆形 (type: "CIRCLE"):

属性类型说明
radiusnumber圆形半径

画笔路径 (type: "PATH"):

属性类型说明
pointsArray<{x, y}>点坐标数组

线条 (type: "LINE"):

属性类型说明
x2number终点 X 坐标
y2number终点 Y 坐标

箭头 (type: "ARROW"):

属性类型说明
x2number终点 X 坐标
y2number终点 Y 坐标

多边形 (type: "POLYGON"):

属性类型说明
radiusnumber外接圆半径
sidesnumber边数(如 3=三角形,6=六边形)

文本 (type: "TEXT"):

属性类型说明
textstring文本内容
fontSizenumber字体大小(像素)
fontFamilystring字体(可选,默认 sans-serif)
boldboolean是否加粗(可选)
italicboolean是否斜体(可选)
hotzoneobject热区配置(可选,详见下方热区功能)

图片 (type: "IMAGE"):

属性类型说明
widthnumber图片宽度
heightnumber图片高度
dataUrlstringBase64 编码的图片数据

组合 (type: "GROUP"):

属性类型说明
widthnumber组合宽度
heightnumber组合高度
childrenArray子对象数组

富文本 (type: "RICH_TEXT"):

属性类型说明
segmentsArray文本段落数组,每段包含 text, color, bold, italic, fontSize
fontSizenumber默认字体大小(像素)

星形 (type: "STAR"):

属性类型说明
outerRadiusnumber外圆半径
innerRadiusnumber内圆半径
pointsnumber星形角数(默认 5)

心形 (type: "HEART")、三角形 (type: "TRIANGLE")、菱形 (type: "DIAMOND"):

属性类型说明
widthnumber宽度
heightnumber高度

贝塞尔曲线 (type: "BEZIER"):

属性类型说明
pointsArray控制点数组(包含锚点和控制柄)
closedboolean是否闭合路径

示例:保存和加载画布

// 保存画布内容
document.addEventListener('editor-change', (e) => {
  const data = JSON.stringify({ objects: e.detail.objects });
  localStorage.setItem('my-canvas', data);
});

// 加载画布内容
const savedData = localStorage.getItem('my-canvas');
if (savedData) {
  document.querySelector('canvas-drawing-editor').setAttribute('initial-data', savedData);
}

editor-close 事件

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

animation-start 事件

当动画开始时触发。

document.addEventListener('animation-start', (e) => {
  console.log('动画开始:', e.detail);
  // e.detail: { tweenId, objectId }
});

animation-complete 事件

当动画完成时触发。

document.addEventListener('animation-complete', (e) => {
  console.log('动画完成:', e.detail);
  // e.detail: { tweenId, objectId }
});

animation-update 事件

动画每帧更新时触发。

document.addEventListener('animation-update', (e) => {
  console.log('动画进度:', e.detail.progress);
  // e.detail: { tweenId, objectId, progress }
});

🔥 热区功能

热区功能允许你给文本对象绑定动态变量,实现模板化的动态文本替换。

使用场景

  1. 设计模板(如证书、名片、海报)
  2. 给文本添加热区,绑定变量名
  3. 使用时传入变量值,动态替换文本内容

管理员端(设计模板)

<!-- 启用热区编辑功能 -->
<canvas-drawing-editor
  title="模板设计器"
  enable-hotzone="true"
></canvas-drawing-editor>

操作步骤:

  1. 创建文本(如:“姓名”)
  2. 右键点击文本 → 选择「新建热区」
  3. 输入变量名(如:name)→ 保存
  4. 导出 JSON 保存模板

用户端(展示动态数据)

<!-- 传入模板数据和变量值 -->
<canvas-drawing-editor
  initial-data='{"objects":[...]}'
  hotzone-data='{"name": "张三", "company": "XX公司"}'
></canvas-drawing-editor>

热区数据结构

// 文本对象的热区配置
{
  "type": "TEXT",
  "text": "姓名",
  "hotzone": {
    "variableName": "name",      // 变量名(必填)
    "defaultValue": "默认值",     // 默认值(可选)
    "description": "用户姓名"     // 描述(可选)
  }
}

🎬 Tween 动画 API

通过 tweenAnimate() 方法可以为对象创建平滑的属性过渡动画:

const editor = document.querySelector('canvas-drawing-editor');

// 基本用法
editor.tweenAnimate(objectId, { x: 300, y: 200 }, {
  duration: 1000,        // 动画时长(毫秒)
  easing: 'easeOutQuad', // 缓动函数
  onComplete: () => console.log('动画完成')
});

// 可动画属性:x, y, width, height, rotation, opacity, fontSize, radius

// 缓动函数:linear, easeInQuad, easeOutQuad, easeInOutQuad,
//          easeInElastic, easeOutElastic, easeInBounce, easeOutBounce,
//          easeInBack, easeOutBack

// 循环动画
editor.tweenAnimate(objectId, { x: 400 }, {
  duration: 1000,
  repeat: -1,    // 无限循环
  yoyo: true     // 往返
});

// 停止动画
editor.stopAllAnimations();

🛠️ 开发

# 安装依赖
npm install

# 启动开发服务器
npm run dev

# 构建库
npm run build:lib

English

A powerful canvas-based drawing editor Web Component with zero dependencies. Works with Vue 2/3, React, Angular, and vanilla HTML.

✨ Features

📦 Installation

npm install canvas-drawing-editor

🚀 Usage

Vanilla HTML

<!DOCTYPE html>
<html>
<head>
  <style>
    canvas-drawing-editor { width: 100%; height: 600px; display: block; }
  </style>
</head>
<body>
  <canvas-drawing-editor title="My Canvas"></canvas-drawing-editor>

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

Vue 3

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

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

Optional: To suppress the Failed to resolve component: canvas-drawing-editor warning in the console, add to vite.config.ts:

export default defineConfig({
  vue: {
    template: {
      compilerOptions: {
        isCustomElement: (tag) => tag === 'canvas-drawing-editor'
      }
    }
  }
});

Vue 2

// main.js
import 'canvas-drawing-editor'

// Optional: To suppress console warnings
// Vue.config.ignoredElements = ['canvas-drawing-editor']
<template>
  <canvas-drawing-editor
    title="Vue2 Canvas"
    style="width: 100%; height: 600px;"
  ></canvas-drawing-editor>
</template>

React

import 'canvas-drawing-editor';

function App() {
  return (
    <canvas-drawing-editor
      title="React Canvas"
      style={{ width: '100%', height: '600px' }}
    />
  );
}

Angular

// app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import 'canvas-drawing-editor';

@NgModule({
  // ...
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }
<!-- app.component.html -->
<canvas-drawing-editor
  title="Angular Canvas"
  style="width: 100%; height: 600px;"
></canvas-drawing-editor>

⚙️ Configuration

Basic Attributes

AttributeTypeDefaultDescription
titlestring”Canvas Editor”Editor title
langstring”zh”UI language (“zh” for Chinese, “en” for English)
theme-colorstring”#5450dc”Theme color (affects buttons, hover states, etc.)
initial-datastring-Initial JSON data to render (see format below)
enable-hotzonebooleanfalseEnable hotzone feature (admin mode)
hotzone-datastring-Hotzone variable data (JSON format for dynamic text replacement)
tool-configstring-Tool configuration object (JSON format, see below)

Tool Configuration (tool-config)

Recommended: Use tool-config attribute for unified tool configuration:

<canvas-drawing-editor
  tool-config='{"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}'
></canvas-drawing-editor>
OptionTypeDefaultDescription
pencilbooleantruePencil tool
rectanglebooleantrueRectangle tool
circlebooleantrueCircle tool
linebooleantrueLine tool
arrowbooleantrueArrow tool
polygonbooleantruePolygon tool
textbooleantrueText tool
imagebooleantrueImage import
undobooleantrueUndo button
redobooleantrueRedo button
zoombooleantrueZoom controls
downloadbooleantruePNG export
exportJsonbooleantrueJSON save
importJsonbooleantrueJSON load
clearbooleantrueClear canvas
colorbooleantrueColor picker
layersbooleantrueLayer management
groupbooleantrueGroup/Ungroup
alignbooleantrueAlign/Distribute

Legacy Attributes (Backward Compatible)

Individual show-* attributes are still supported but tool-config is recommended:

AttributeTypeDefaultDescription
show-pencilbooleantrueShow pencil tool
show-rectanglebooleantrueShow rectangle tool
show-circlebooleantrueShow circle tool
show-linebooleantrueShow line tool
show-arrowbooleantrueShow arrow tool
show-polygonbooleantrueShow polygon tool
show-textbooleantrueShow text tool
show-imagebooleantrueShow image import
show-undobooleantrueShow undo button
show-redobooleantrueShow redo button
show-zoombooleantrueShow zoom controls
show-downloadbooleantrueShow PNG export
show-exportbooleantrueShow JSON save
show-importbooleantrueShow JSON load
show-colorbooleantrueShow color picker
show-clearbooleantrueShow clear canvas button
show-layersbooleantrueShow layer management
show-groupbooleantrueShow group/ungroup
show-alignbooleantrueShow align/distribute

📊 Initial Data

You can pass JSON data to initialize the canvas content:

<canvas-drawing-editor
  initial-data='{"objects":[{"id":"abc123","type":"RECTANGLE","x":100,"y":100,"width":200,"height":150,"color":"#3b82f6","lineWidth":2}]}'
></canvas-drawing-editor>

📡 Events

editor-change Event

Fires when canvas content changes. The e.detail.objects array contains all drawing objects.

document.addEventListener('editor-change', (e) => {
  console.log('Objects:', e.detail.objects);
  // Save to server or localStorage
  localStorage.setItem('canvas-data', JSON.stringify({ objects: e.detail.objects }));
});

Object Types & Properties

Each object in e.detail.objects has the following base properties:

PropertyTypeDescription
idstringUnique identifier
typestringObject type: RECTANGLE, CIRCLE, PATH, TEXT, IMAGE, LINE, ARROW, POLYGON, GROUP
xnumberX coordinate
ynumberY coordinate
colorstringStroke/fill color (hex format, e.g., #3b82f6)
lineWidthnumberLine width in pixels
visiblebooleanVisibility (optional, default true)
lockedbooleanLock state (optional, default false)

Rectangle (type: "RECTANGLE"):

PropertyTypeDescription
widthnumberRectangle width
heightnumberRectangle height

Circle (type: "CIRCLE"):

PropertyTypeDescription
radiusnumberCircle radius

Path/Pencil (type: "PATH"):

PropertyTypeDescription
pointsArray<{x, y}>Array of point coordinates

Line (type: "LINE"):

PropertyTypeDescription
x2numberEnd point X coordinate
y2numberEnd point Y coordinate

Arrow (type: "ARROW"):

PropertyTypeDescription
x2numberEnd point X coordinate
y2numberEnd point Y coordinate

Polygon (type: "POLYGON"):

PropertyTypeDescription
radiusnumberCircumscribed circle radius
sidesnumberNumber of sides (e.g., 3=triangle, 6=hexagon)

Text (type: "TEXT"):

PropertyTypeDescription
textstringText content
fontSizenumberFont size in pixels
fontFamilystringFont family (optional, default sans-serif)
boldbooleanBold style (optional)
italicbooleanItalic style (optional)
hotzoneobjectHotzone config (optional, see Hotzone section)

Image (type: "IMAGE"):

PropertyTypeDescription
widthnumberImage width
heightnumberImage height
dataUrlstringBase64 encoded image data

Group (type: "GROUP"):

PropertyTypeDescription
widthnumberGroup width
heightnumberGroup height
childrenArrayArray of child objects

Example: Saving and Loading

// Save canvas content
document.addEventListener('editor-change', (e) => {
  const data = JSON.stringify({ objects: e.detail.objects });
  localStorage.setItem('my-canvas', data);
});

// Load canvas content
const savedData = localStorage.getItem('my-canvas');
if (savedData) {
  document.querySelector('canvas-drawing-editor').setAttribute('initial-data', savedData);
}

editor-close Event

document.addEventListener('editor-close', () => {
  console.log('Editor closed');
});

animation-start Event

Triggered when an animation starts.

document.addEventListener('animation-start', (e) => {
  console.log('Animation started:', e.detail);
  // e.detail: { tweenId, objectId }
});

animation-complete Event

Triggered when an animation completes.

document.addEventListener('animation-complete', (e) => {
  console.log('Animation completed:', e.detail);
  // e.detail: { tweenId, objectId }
});

animation-update Event

Triggered on each animation frame update.

document.addEventListener('animation-update', (e) => {
  console.log('Animation progress:', e.detail.progress);
  // e.detail: { tweenId, objectId, progress }
});

🔥 Hotzone Feature

The hotzone feature allows you to bind dynamic variables to text objects for template-based dynamic text replacement.

Use Cases

  1. Design templates (certificates, business cards, posters)
  2. Add hotzones to text, bind variable names
  3. Pass variable values at runtime to dynamically replace text

Admin Mode (Design Templates)

<!-- Enable hotzone editing -->
<canvas-drawing-editor
  title="Template Designer"
  enable-hotzone="true"
></canvas-drawing-editor>

Steps:

  1. Create text (e.g., “Name”)
  2. Right-click on text → Select “Create Hotzone”
  3. Enter variable name (e.g., name) → Save
  4. Export JSON to save template

User Mode (Display Dynamic Data)

<!-- Pass template data and variable values -->
<canvas-drawing-editor
  initial-data='{"objects":[...]}'
  hotzone-data='{"name": "John Doe", "company": "Acme Inc"}'
></canvas-drawing-editor>

Hotzone Data Structure

// Text object with hotzone config
{
  "type": "TEXT",
  "text": "Name",
  "hotzone": {
    "variableName": "name",       // Variable name (required)
    "defaultValue": "Default",    // Default value (optional)
    "description": "User name"    // Description (optional)
  }
}

🎬 Tween Animation API

Use tweenAnimate() method to create smooth property transition animations:

const editor = document.querySelector('canvas-drawing-editor');

// Basic usage
editor.tweenAnimate(objectId, { x: 300, y: 200 }, {
  duration: 1000,        // Animation duration (ms)
  easing: 'easeOutQuad', // Easing function
  onComplete: () => console.log('Animation complete')
});

// Animatable properties: x, y, width, height, rotation, opacity, fontSize, radius

// Easing functions: linear, easeInQuad, easeOutQuad, easeInOutQuad,
//                   easeInElastic, easeOutElastic, easeInBounce, easeOutBounce,
//                   easeInBack, easeOutBack

// Loop animation
editor.tweenAnimate(objectId, { x: 400 }, {
  duration: 1000,
  repeat: -1,    // Infinite loop
  yoyo: true     // Reverse on repeat
});

// Stop animations
editor.stopAllAnimations();

🛠️ Development

# Install dependencies
npm install

# Start dev server
npm run dev

# Build library
npm run build:lib

📄 License

MIT © typsusan


Next Post
Telegram Search: 高效导出和模糊搜索你的 Telegram 聊天记录