vkedit 2.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +1173 -0
- package/README.md +1172 -0
- package/dist/commands/add-element-command.d.ts +13 -0
- package/dist/commands/align-elements-command.d.ts +13 -0
- package/dist/commands/base-command.d.ts +15 -0
- package/dist/commands/batch-command.d.ts +16 -0
- package/dist/commands/change-layer-order-command.d.ts +15 -0
- package/dist/commands/clear-selection-command.d.ts +11 -0
- package/dist/commands/i-command.d.ts +13 -0
- package/dist/commands/index.d.ts +16 -0
- package/dist/commands/remove-element-command.d.ts +12 -0
- package/dist/commands/transform-element-command.d.ts +18 -0
- package/dist/commands/update-property-command.d.ts +20 -0
- package/dist/components/BaseElementPropertyPanel.vue.d.ts +9 -0
- package/dist/components/CanvasPropertyPanel.vue.d.ts +9 -0
- package/dist/components/ContextMenuDelete.vue.d.ts +5 -0
- package/dist/components/TextProperty.vue.d.ts +15 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/ui/button/Button.vue.d.ts +27 -0
- package/dist/components/ui/button/index.d.ts +7 -0
- package/dist/components/ui/button-group/ButtonGroup.vue.d.ts +23 -0
- package/dist/components/ui/button-group/ButtonGroupSeparator.vue.d.ts +9 -0
- package/dist/components/ui/button-group/ButtonGroupText.vue.d.ts +26 -0
- package/dist/components/ui/button-group/index.d.ts +8 -0
- package/dist/components/ui/dropdown-menu/DropdownMenu.vue.d.ts +22 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue.d.ts +28 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuContent.vue.d.ts +36 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuGroup.vue.d.ts +18 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuItem.vue.d.ts +26 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuLabel.vue.d.ts +23 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue.d.ts +22 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuRadioItem.vue.d.ts +26 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuSeparator.vue.d.ts +7 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuShortcut.vue.d.ts +21 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuSub.vue.d.ts +22 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuSubContent.vue.d.ts +38 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue.d.ts +23 -0
- package/dist/components/ui/dropdown-menu/DropdownMenuTrigger.vue.d.ts +18 -0
- package/dist/components/ui/dropdown-menu/index.d.ts +15 -0
- package/dist/components/ui/index.d.ts +14 -0
- package/dist/components/ui/input/Input.vue.d.ts +12 -0
- package/dist/components/ui/input/index.d.ts +1 -0
- package/dist/components/ui/input-mm/InputMM.vue.d.ts +13 -0
- package/dist/components/ui/input-mm/InputNumberMM.vue.d.ts +14 -0
- package/dist/components/ui/input-mm/index.d.ts +2 -0
- package/dist/components/ui/input-number/VkInputNumber.vue.d.ts +9 -0
- package/dist/components/ui/input-number/index.d.ts +1 -0
- package/dist/components/ui/label/Label.vue.d.ts +22 -0
- package/dist/components/ui/label/index.d.ts +1 -0
- package/dist/components/ui/number-field/NumberField.vue.d.ts +26 -0
- package/dist/components/ui/number-field/NumberFieldContent.vue.d.ts +21 -0
- package/dist/components/ui/number-field/NumberFieldDecrement.vue.d.ts +22 -0
- package/dist/components/ui/number-field/NumberFieldIncrement.vue.d.ts +22 -0
- package/dist/components/ui/number-field/NumberFieldInput.vue.d.ts +6 -0
- package/dist/components/ui/number-field/index.d.ts +5 -0
- package/dist/components/ui/scroll-area/ScrollArea.vue.d.ts +22 -0
- package/dist/components/ui/scroll-area/ScrollBar.vue.d.ts +9 -0
- package/dist/components/ui/scroll-area/index.d.ts +2 -0
- package/dist/components/ui/select/Select.vue.d.ts +25 -0
- package/dist/components/ui/select/SelectContent.vue.d.ts +32 -0
- package/dist/components/ui/select/SelectGroup.vue.d.ts +18 -0
- package/dist/components/ui/select/SelectItem.vue.d.ts +22 -0
- package/dist/components/ui/select/SelectItemText.vue.d.ts +18 -0
- package/dist/components/ui/select/SelectLabel.vue.d.ts +22 -0
- package/dist/components/ui/select/SelectScrollDownButton.vue.d.ts +22 -0
- package/dist/components/ui/select/SelectScrollUpButton.vue.d.ts +22 -0
- package/dist/components/ui/select/SelectSeparator.vue.d.ts +7 -0
- package/dist/components/ui/select/SelectTrigger.vue.d.ts +25 -0
- package/dist/components/ui/select/SelectValue.vue.d.ts +18 -0
- package/dist/components/ui/select/index.d.ts +11 -0
- package/dist/components/ui/separator/Separator.vue.d.ts +10 -0
- package/dist/components/ui/separator/index.d.ts +1 -0
- package/dist/components/ui/slider/Slider.vue.d.ts +13 -0
- package/dist/components/ui/slider/index.d.ts +1 -0
- package/dist/components/ui/switch/Switch.vue.d.ts +26 -0
- package/dist/components/ui/switch/index.d.ts +1 -0
- package/dist/components/ui/textarea/Textarea.vue.d.ts +12 -0
- package/dist/components/ui/textarea/index.d.ts +1 -0
- package/dist/components/ui/toggle/Toggle.vue.d.ts +33 -0
- package/dist/components/ui/toggle/index.d.ts +7 -0
- package/dist/core/BgLayer.vue.d.ts +8 -0
- package/dist/core/ContentLayer.vue.d.ts +29 -0
- package/dist/core/ContextMenu.vue.d.ts +6 -0
- package/dist/core/Editor.vue.d.ts +38 -0
- package/dist/core/PropertyPanel.vue.d.ts +23 -0
- package/dist/core/RulerLayer.vue.d.ts +10 -0
- package/dist/core/ScrollbarLayer.vue.d.ts +8 -0
- package/dist/core/SelectionLayer.vue.d.ts +6 -0
- package/dist/core/StageView.vue.d.ts +9 -0
- package/dist/core/Toolbar.vue.d.ts +29 -0
- package/dist/core/Toolbox.vue.d.ts +23 -0
- package/dist/core/Zoom.vue.d.ts +6 -0
- package/dist/core/editor-host.d.ts +34 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/create-host.d.ts +9 -0
- package/dist/favicon.ico +0 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/use-bg-layer.d.ts +22 -0
- package/dist/hooks/use-content-layer.d.ts +66 -0
- package/dist/hooks/use-host-state.d.ts +14 -0
- package/dist/hooks/use-property-command.d.ts +6 -0
- package/dist/hooks/use-ruler-layer.d.ts +24 -0
- package/dist/hooks/use-scrollbar-layer.d.ts +47 -0
- package/dist/hooks/use-selection-layer.d.ts +35 -0
- package/dist/hooks/use-stage-event.d.ts +33 -0
- package/dist/hooks/use-stage.d.ts +14 -0
- package/dist/hooks/use-zoom.d.ts +12 -0
- package/dist/html2canvas.esm-Dmi1NfiH.js +4871 -0
- package/dist/index-CjPgwxVC.js +82707 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.es-DekiblxN.js +6674 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/plugins/align/Align.vue.d.ts +6 -0
- package/dist/plugins/align/align.d.ts +11 -0
- package/dist/plugins/align/index.d.ts +2 -0
- package/dist/plugins/barcode/PropertyPanel.vue.d.ts +9 -0
- package/dist/plugins/barcode/Shape.vue.d.ts +8 -0
- package/dist/plugins/barcode/Tool.vue.d.ts +5 -0
- package/dist/plugins/barcode/barcode.d.ts +72 -0
- package/dist/plugins/barcode/index.d.ts +4 -0
- package/dist/plugins/chart/PropertyPanel.vue.d.ts +9 -0
- package/dist/plugins/chart/Shape.vue.d.ts +23 -0
- package/dist/plugins/chart/Tool.vue.d.ts +5 -0
- package/dist/plugins/chart/chart.d.ts +38 -0
- package/dist/plugins/chart/index.d.ts +4 -0
- package/dist/plugins/context-menu-manager/context-menu-manager.d.ts +28 -0
- package/dist/plugins/context-menu-manager/index.d.ts +1 -0
- package/dist/plugins/element-manager.d.ts +24 -0
- package/dist/plugins/export/Export.vue.d.ts +6 -0
- package/dist/plugins/export/export.d.ts +36 -0
- package/dist/plugins/export/index.d.ts +2 -0
- package/dist/plugins/graphic-manager/graphic-manager.d.ts +31 -0
- package/dist/plugins/graphic-manager/index.d.ts +1 -0
- package/dist/plugins/graphic-tool-manager.d.ts +16 -0
- package/dist/plugins/import/Import.vue.d.ts +6 -0
- package/dist/plugins/import/import.d.ts +33 -0
- package/dist/plugins/import/index.d.ts +2 -0
- package/dist/plugins/index.d.ts +19 -0
- package/dist/plugins/keydown.d.ts +15 -0
- package/dist/plugins/line/PropertyPanel.vue.d.ts +9 -0
- package/dist/plugins/line/Shape.vue.d.ts +6 -0
- package/dist/plugins/line/Tool.vue.d.ts +6 -0
- package/dist/plugins/line/index.d.ts +4 -0
- package/dist/plugins/line/line.d.ts +62 -0
- package/dist/plugins/preview/PreviewButton.vue.d.ts +5 -0
- package/dist/plugins/preview/index.d.ts +1 -0
- package/dist/plugins/preview/preview.d.ts +26 -0
- package/dist/plugins/property-panel-manager/index.d.ts +1 -0
- package/dist/plugins/property-panel-manager/property-panel-manager.d.ts +32 -0
- package/dist/plugins/qrcode/PropertyPanel.vue.d.ts +9 -0
- package/dist/plugins/qrcode/Shape.vue.d.ts +8 -0
- package/dist/plugins/qrcode/Tool.vue.d.ts +5 -0
- package/dist/plugins/qrcode/index.d.ts +4 -0
- package/dist/plugins/qrcode/qrcode.d.ts +75 -0
- package/dist/plugins/rect/PropertyPanel.vue.d.ts +9 -0
- package/dist/plugins/rect/Shape.vue.d.ts +6 -0
- package/dist/plugins/rect/Tool.vue.d.ts +6 -0
- package/dist/plugins/rect/index.d.ts +4 -0
- package/dist/plugins/rect/rect.d.ts +70 -0
- package/dist/plugins/selection.d.ts +35 -0
- package/dist/plugins/table/CellsBorder.vue.d.ts +6 -0
- package/dist/plugins/table/ContextMenu.vue.d.ts +9 -0
- package/dist/plugins/table/PropertyPanel.vue.d.ts +9 -0
- package/dist/plugins/table/Shape.vue.d.ts +26 -0
- package/dist/plugins/table/Tool.vue.d.ts +6 -0
- package/dist/plugins/table/cell.d.ts +61 -0
- package/dist/plugins/table/index.d.ts +6 -0
- package/dist/plugins/table/table.d.ts +93 -0
- package/dist/plugins/text/PropertyPanel.vue.d.ts +9 -0
- package/dist/plugins/text/Shape.vue.d.ts +6 -0
- package/dist/plugins/text/TextContextMenu.vue.d.ts +5 -0
- package/dist/plugins/text/Tool.vue.d.ts +5 -0
- package/dist/plugins/text/index.d.ts +5 -0
- package/dist/plugins/text/text.d.ts +75 -0
- package/dist/plugins/toolbar-manager.d.ts +16 -0
- package/dist/purify.es-8O7LIJdo.js +553 -0
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/use-stage-store.d.ts +40 -0
- package/dist/styles/index.css +144 -0
- package/dist/types/base-graphic-element.d.ts +82 -0
- package/dist/types/base-graphic-type.d.ts +9 -0
- package/dist/types/base-plugin.d.ts +17 -0
- package/dist/types/base.d.ts +81 -0
- package/dist/types/element-type-map.d.ts +12 -0
- package/dist/types/event-data.d.ts +116 -0
- package/dist/types/event-map.d.ts +146 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/konva-text.d.ts +3 -0
- package/dist/types/plugin-map.d.ts +12 -0
- package/dist/vkedit.css +1 -0
- package/dist/vkedit.es.js +113 -0
- package/package.json +91 -0
package/README.en.md
ADDED
|
@@ -0,0 +1,1173 @@
|
|
|
1
|
+
# vkedit
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/vkedit)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](package.json)
|
|
8
|
+
|
|
9
|
+
**Vue3 Konva Plug-in designer**
|
|
10
|
+
|
|
11
|
+
A powerful, extensible graphic editor plugin library built on Vue 3 and Konva.js. Suitable for label template design, QR code design, barcode design, ticket design, business card design, certificate design, and more.
|
|
12
|
+
|
|
13
|
+
**[🇨🇳 中文版](README.md)**
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div align="center">
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 📖 Project Overview
|
|
26
|
+
|
|
27
|
+
**vkedit** is a plugin-based graphic editor library built on Vue 3 and Konva.js. It provides a complete set of graphic editing features, including support for multiple graphic elements, a plugin system architecture, undo/redo mechanisms, and import/export functionality.
|
|
28
|
+
|
|
29
|
+
The project adopts a plugin-based architecture design, allowing developers to flexibly enable or disable various functional modules as needed, while supporting custom plugins and extension of graphic elements.
|
|
30
|
+
|
|
31
|
+
vkedit is particularly suitable for **label template design**, **QR code design**, **barcode design**, **ticket design**, **business card design**, **certificate design**, and various other graphic design scenarios, providing developers with powerful visual design capabilities.
|
|
32
|
+
|
|
33
|
+
- **Current Version**: 2.8.5
|
|
34
|
+
- **License**: MIT
|
|
35
|
+
- **Node.js Requirement**: ^20.19.0 || >=22.12.0
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## ✨ Core Features
|
|
40
|
+
|
|
41
|
+
- **🔌 Plugin-based Architecture**: Flexible plugin system that enables or disables functional modules on demand
|
|
42
|
+
- **🎨 Multi-graphic Element Support**:
|
|
43
|
+
- Rectangle
|
|
44
|
+
- Text
|
|
45
|
+
- Line
|
|
46
|
+
- Table
|
|
47
|
+
- QR Code
|
|
48
|
+
- Barcode
|
|
49
|
+
- Chart
|
|
50
|
+
- **📥📤 Import/Export**: Supports JSON format design data import and export
|
|
51
|
+
- **↩️↪️ Undo/Redo**: Complete history management based on command pattern
|
|
52
|
+
- **🏗️ Multi-layer Canvas System**: Supports background layer, content layer, selection layer, ruler layer, and scrollbar layer
|
|
53
|
+
- **🔍 Zoom and Ruler**: Precise canvas zooming and ruler display
|
|
54
|
+
- **📐 Alignment Tools**: Supports multiple alignment and distribution operations for elements
|
|
55
|
+
- **📋 Context Menu**: Right-click menu for quick operations
|
|
56
|
+
- **🎯 Event-driven**: Complete event system supporting inter-plugin communication
|
|
57
|
+
- **🏷️ Rich Application Scenarios**: Label template design, QR code design, barcode design, ticket design, business card design, certificate design, etc.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 🎯 Application Scenarios
|
|
62
|
+
|
|
63
|
+
vkedit can be widely applied to the following scenarios:
|
|
64
|
+
|
|
65
|
+
| Application Scenario | Suitable Features | Typical Usage |
|
|
66
|
+
| ------------------------- | -------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
67
|
+
| **Label Template Design** | QR codes, barcodes, text, rectangles, tables | Product labels, logistics labels, price tags, inventory labels |
|
|
68
|
+
| **QR Code Design** | QR code plugin, text, graphic elements | Marketing QR codes, payment QR codes, information QR codes |
|
|
69
|
+
| **Barcode Design** | Barcode plugin, text, graphic elements | Product barcodes, book barcodes, inventory barcodes, logistics tracking codes |
|
|
70
|
+
| **Ticket Design** | Tables, text, rectangles, lines | Invoices, receipts, vouchers, reports |
|
|
71
|
+
| **Business Card Design** | Text, rectangles, image elements | Personal cards, company cards, VIP cards |
|
|
72
|
+
| **Certificate Design** | Text, rectangles, tables, image elements | Graduation certificates, honorary certificates, qualification certificates |
|
|
73
|
+
| **Poster Design** | Combination of multiple graphic elements | Promotional posters, event posters, product posters |
|
|
74
|
+
| **Form Design** | Tables, text, lines | Survey forms, application forms, registration forms |
|
|
75
|
+
|
|
76
|
+
### Typical Use Cases
|
|
77
|
+
|
|
78
|
+
#### 1. Label Template Design
|
|
79
|
+
```typescript
|
|
80
|
+
// Create label editor
|
|
81
|
+
const host = createEditorHost({
|
|
82
|
+
exportPlugin: true,
|
|
83
|
+
previewPlugin: true
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// Install plugins required for label design
|
|
87
|
+
host
|
|
88
|
+
.installPlugin('rect-plugin', RectPlugin) // Borders, backgrounds
|
|
89
|
+
.installPlugin('text-plugin', TextPlugin) // Text information
|
|
90
|
+
.installPlugin('qr-plugin', QrcodePlugin) // Product QR code
|
|
91
|
+
.installPlugin('barcode-plugin', BarcodePlugin)// Product barcode
|
|
92
|
+
.installPlugin('table-plugin', TablePlugin) // Table data
|
|
93
|
+
|
|
94
|
+
// Set label dimensions (standard label 100mm x 60mm)
|
|
95
|
+
host.setStatus({
|
|
96
|
+
dpm: 8,
|
|
97
|
+
width: 100 * 8,
|
|
98
|
+
height: 60 * 8
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### 2. QR Code Design
|
|
103
|
+
```typescript
|
|
104
|
+
// Create QR code designer
|
|
105
|
+
const host = createEditorHost({
|
|
106
|
+
exportPlugin: true
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
host
|
|
110
|
+
.installPlugin('text-plugin', TextPlugin) // Description text
|
|
111
|
+
.installPlugin('qr-plugin', QrcodePlugin) // QR code element
|
|
112
|
+
.installPlugin('rect-plugin', RectPlugin) // Decorative border
|
|
113
|
+
|
|
114
|
+
// Set canvas dimensions
|
|
115
|
+
host.setStatus({
|
|
116
|
+
dpm: 8,
|
|
117
|
+
width: 150 * 8,
|
|
118
|
+
height: 150 * 8
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### 3. Barcode Design
|
|
123
|
+
```typescript
|
|
124
|
+
// Create barcode designer
|
|
125
|
+
const host = createEditorHost({
|
|
126
|
+
exportPlugin: true,
|
|
127
|
+
previewPlugin: true
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
host
|
|
131
|
+
.installPlugin('barcode-plugin', BarcodePlugin)// Barcode
|
|
132
|
+
.installPlugin('text-plugin', TextPlugin) // Product information
|
|
133
|
+
.installPlugin('line-plugin', LinePlugin) // Divider line
|
|
134
|
+
|
|
135
|
+
// Set barcode label dimensions
|
|
136
|
+
host.setStatus({
|
|
137
|
+
dpm: 8,
|
|
138
|
+
width: 80 * 8,
|
|
139
|
+
height: 50 * 8
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 🛠️ Tech Stack
|
|
146
|
+
|
|
147
|
+
### Core Framework and Libraries
|
|
148
|
+
|
|
149
|
+
| Dependency | Version | Description |
|
|
150
|
+
| ---------------------------------------------------- | ------- | -------------------------------- |
|
|
151
|
+
| [Vue](https://vuejs.org/) | ^3.5.18 | Progressive JavaScript Framework |
|
|
152
|
+
| [Konva.js](https://konvajs.org/) | ^10.0.2 | 2D Canvas Library |
|
|
153
|
+
| [vue-konva](https://www.npmjs.com/package/vue-konva) | ^3.2.6 | Vue 3 Binding |
|
|
154
|
+
| [Pinia](https://pinia.vuejs.org/) | ^3.0.3 | Vue State Management |
|
|
155
|
+
| [TypeScript](https://www.typescriptlang.org/) | ~5.8.0 | Type Safety |
|
|
156
|
+
| [Vite](https://vitejs.dev/) | ^7.0.6 | Build Tool |
|
|
157
|
+
|
|
158
|
+
### Runtime Dependencies
|
|
159
|
+
|
|
160
|
+
- **@vueuse/core**: Vue Composition Utility Library
|
|
161
|
+
- **echarts**: Chart Library
|
|
162
|
+
- **exceljs**: Excel File Processing
|
|
163
|
+
- **jsbarcode**: Barcode Generation
|
|
164
|
+
- **jspdf**: PDF Export
|
|
165
|
+
- **lodash**: JavaScript Utility Library
|
|
166
|
+
- **qrcode**: QR Code Generation
|
|
167
|
+
- **uuid**: Unique Identifier Generation
|
|
168
|
+
|
|
169
|
+
### Development Tools
|
|
170
|
+
|
|
171
|
+
- ESLint & Prettier: Code Linting and Formatting
|
|
172
|
+
- Tailwind CSS v4: Atomic CSS Framework
|
|
173
|
+
- Reka UI: UI Component Library
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 🏗️ Architecture Design
|
|
178
|
+
|
|
179
|
+
### Editor Host Mechanism
|
|
180
|
+
|
|
181
|
+
`EditorHost` is the core host class of the entire editor, responsible for managing all plugins, states, and events.
|
|
182
|
+
|
|
183
|
+
```mermaid
|
|
184
|
+
classDiagram
|
|
185
|
+
class EditorHost {
|
|
186
|
+
-Map~string,IEditorPlugin~ plugins
|
|
187
|
+
-Map~string,Function[]~ events
|
|
188
|
+
-ICommand[] commandStack
|
|
189
|
+
-number currentCommandIndex
|
|
190
|
+
+IEditorState status
|
|
191
|
+
+installPlugin() EditorHost
|
|
192
|
+
+uninstallPlugin() EditorHost
|
|
193
|
+
+getPlugin() IEditorPlugin
|
|
194
|
+
+executeCommand() void
|
|
195
|
+
+undo() void
|
|
196
|
+
+redo() void
|
|
197
|
+
+emit() void
|
|
198
|
+
+on() void
|
|
199
|
+
+off() void
|
|
200
|
+
+toJSON() string
|
|
201
|
+
+loadJSON() void
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Plugin System Architecture
|
|
206
|
+
|
|
207
|
+
All functions are implemented through plugins, which can be registered to the host and respond to events.
|
|
208
|
+
|
|
209
|
+
```mermaid
|
|
210
|
+
graph TD
|
|
211
|
+
A[EditorHost] --> B[ToolbarManagerPlugin]
|
|
212
|
+
A --> C[GraphicToolManagerPlugin]
|
|
213
|
+
A --> D[ElementManagerPlugin]
|
|
214
|
+
A --> E[SelectionPlugin]
|
|
215
|
+
A --> F[PropertyPanelManagerPlugin]
|
|
216
|
+
A --> G[ExportPlugin]
|
|
217
|
+
A --> H[ImportPlugin]
|
|
218
|
+
A --> I[PreviewPlugin]
|
|
219
|
+
A --> J[KeyDownPlugin]
|
|
220
|
+
A --> K[AlignPlugin]
|
|
221
|
+
|
|
222
|
+
A --> L[RectPlugin]
|
|
223
|
+
A --> M[TextPlugin]
|
|
224
|
+
A --> N[TablePlugin]
|
|
225
|
+
A --> O[QrcodePlugin]
|
|
226
|
+
A --> P[BarcodePlugin]
|
|
227
|
+
A --> Q[ChartPlugin]
|
|
228
|
+
A --> R[LinePlugin]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Command Pattern (Undo/Redo)
|
|
232
|
+
|
|
233
|
+
All undoable operations are implemented through commands, supporting command history management.
|
|
234
|
+
|
|
235
|
+
```mermaid
|
|
236
|
+
sequenceDiagram
|
|
237
|
+
participant User
|
|
238
|
+
participant EditorHost
|
|
239
|
+
participant Command
|
|
240
|
+
participant Stack
|
|
241
|
+
|
|
242
|
+
User->>EditorHost: executeCommand(cmd)
|
|
243
|
+
EditorHost->>Command: execute()
|
|
244
|
+
Command-->>EditorHost: Execution completed
|
|
245
|
+
EditorHost->>Stack: push(cmd)
|
|
246
|
+
|
|
247
|
+
User->>EditorHost: undo()
|
|
248
|
+
EditorHost->>Stack: get current cmd
|
|
249
|
+
Stack-->>EditorHost: command
|
|
250
|
+
EditorHost->>Command: undo()
|
|
251
|
+
|
|
252
|
+
User->>EditorHost: redo()
|
|
253
|
+
EditorHost->>Stack: get next cmd
|
|
254
|
+
Stack-->>EditorHost: command
|
|
255
|
+
EditorHost->>Command: redo()
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Event-driven Mechanism
|
|
259
|
+
|
|
260
|
+
The editor achieves loose coupling communication between plugins through the event system.
|
|
261
|
+
|
|
262
|
+
```mermaid
|
|
263
|
+
flowchart LR
|
|
264
|
+
A[Plugin 1] -- emit --> B[EventBus]
|
|
265
|
+
C[Plugin 2] -- on --> B
|
|
266
|
+
D[Plugin 3] -- on --> B
|
|
267
|
+
B -- notify --> C
|
|
268
|
+
B -- notify --> D
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Layer System
|
|
272
|
+
|
|
273
|
+
```mermaid
|
|
274
|
+
graph LR
|
|
275
|
+
A[Stage] --> B[BgLayer Background Layer]
|
|
276
|
+
A --> C[ContentLayer Content Layer]
|
|
277
|
+
A --> D[SelectionLayer Selection Layer]
|
|
278
|
+
A --> E[RulerLayer Ruler Layer]
|
|
279
|
+
A --> F[ScrollbarLayer Scrollbar Layer]
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## 📁 Project Structure
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
vkedit/
|
|
288
|
+
├── src/
|
|
289
|
+
│ ├── commands/ # Command pattern implementation
|
|
290
|
+
│ │ ├── base-command.ts
|
|
291
|
+
│ │ ├── add-element-command.ts
|
|
292
|
+
│ │ ├── remove-element-command.ts
|
|
293
|
+
│ │ ├── transform-element-command.ts
|
|
294
|
+
│ │ ├── update-property-command.ts
|
|
295
|
+
│ │ ├── batch-command.ts
|
|
296
|
+
│ │ ├── align-elements-command.ts
|
|
297
|
+
│ │ └── ...
|
|
298
|
+
│ ├── components/ # Vue components
|
|
299
|
+
│ │ ├── ui/ # Unified UI component library
|
|
300
|
+
│ │ │ ├── button/
|
|
301
|
+
│ │ │ ├── dropdown-menu/
|
|
302
|
+
│ │ │ ├── input/
|
|
303
|
+
│ │ │ ├── select/
|
|
304
|
+
│ │ │ └── ...
|
|
305
|
+
│ │ ├── BaseElementPropertyPanel.vue
|
|
306
|
+
│ │ ├── CanvasPropertyPanel.vue
|
|
307
|
+
│ │ └── ...
|
|
308
|
+
│ ├── core/ # Core editor components
|
|
309
|
+
│ │ ├── Editor.vue
|
|
310
|
+
│ │ ├── editor-host.ts
|
|
311
|
+
│ │ ├── StageView.vue
|
|
312
|
+
│ │ ├── Toolbar.vue
|
|
313
|
+
│ │ ├── PropertyPanel.vue
|
|
314
|
+
│ │ ├── BgLayer.vue
|
|
315
|
+
│ │ ├── ContentLayer.vue
|
|
316
|
+
│ │ ├── SelectionLayer.vue
|
|
317
|
+
│ │ ├── RulerLayer.vue
|
|
318
|
+
│ │ ├── ScrollbarLayer.vue
|
|
319
|
+
│ │ ├── ContextMenu.vue
|
|
320
|
+
│ │ ├── Zoom.vue
|
|
321
|
+
│ │ └── Toolbox.vue
|
|
322
|
+
│ ├── hooks/ # Vue composition functions
|
|
323
|
+
│ │ ├── use-host-state.ts
|
|
324
|
+
│ │ ├── use-bg-layer.ts
|
|
325
|
+
│ │ ├── use-content-layer.ts
|
|
326
|
+
│ │ ├── use-selection-layer.ts
|
|
327
|
+
│ │ ├── use-ruler-layer.ts
|
|
328
|
+
│ │ ├── use-scrollbar-layer.ts
|
|
329
|
+
│ │ ├── use-zoom.ts
|
|
330
|
+
│ │ └── use-stage-event.ts
|
|
331
|
+
│ ├── plugins/ # Plugin system
|
|
332
|
+
│ │ ├── element-manager.ts
|
|
333
|
+
│ │ ├── graphic-tool-manager.ts
|
|
334
|
+
│ │ ├── graphic-manager.ts
|
|
335
|
+
│ │ ├── selection.ts
|
|
336
|
+
│ │ ├── toolbar-manager.ts
|
|
337
|
+
│ │ ├── keydown.ts
|
|
338
|
+
│ │ ├── align/
|
|
339
|
+
│ │ │ ├── Align.vue
|
|
340
|
+
│ │ │ └── align.ts
|
|
341
|
+
│ │ ├── export/
|
|
342
|
+
│ │ │ ├── Export.vue
|
|
343
|
+
│ │ │ └── export.ts
|
|
344
|
+
│ │ ├── import/
|
|
345
|
+
│ │ │ ├── Import.vue
|
|
346
|
+
│ │ │ └── import.ts
|
|
347
|
+
│ │ ├── preview/
|
|
348
|
+
│ │ │ ├── PreviewButton.vue
|
|
349
|
+
│ │ │ └── preview.ts
|
|
350
|
+
│ │ ├── rect/
|
|
351
|
+
│ │ │ ├── RectPlugin.ts
|
|
352
|
+
│ │ │ ├── Shape.vue
|
|
353
|
+
│ │ │ ├── PropertyPanel.vue
|
|
354
|
+
│ │ │ └── Tool.vue
|
|
355
|
+
│ │ ├── text/
|
|
356
|
+
│ │ ├── table/
|
|
357
|
+
│ │ ├── qrcode/
|
|
358
|
+
│ │ ├── barcode/
|
|
359
|
+
│ │ ├── chart/
|
|
360
|
+
│ │ ├── line/
|
|
361
|
+
│ │ └── context-menu-manager/
|
|
362
|
+
│ ├── stores/ # Pinia state management
|
|
363
|
+
│ ├── types/ # TypeScript type definitions
|
|
364
|
+
│ │ ├── base-graphic-element.ts
|
|
365
|
+
│ │ ├── base-graphic-type.ts
|
|
366
|
+
│ │ ├── base-plugin.ts
|
|
367
|
+
│ │ ├── event-map.ts
|
|
368
|
+
│ │ ├── event-data.ts
|
|
369
|
+
│ │ └── ...
|
|
370
|
+
│ ├── styles/ # Style files
|
|
371
|
+
│ ├── create-host.ts # Host creation function
|
|
372
|
+
│ └── index.ts # Entry file
|
|
373
|
+
├── playground/ # Example project
|
|
374
|
+
│ ├── App.vue
|
|
375
|
+
│ └── main.ts
|
|
376
|
+
├── package.json
|
|
377
|
+
├── vite.config.ts
|
|
378
|
+
├── tsconfig.json
|
|
379
|
+
└── README.md
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## 🚀 Installation and Usage
|
|
385
|
+
|
|
386
|
+
### Environment Requirements
|
|
387
|
+
|
|
388
|
+
- **Node.js**: ^20.19.0 || >=22.12.0
|
|
389
|
+
- **Package Manager**: pnpm 10.19.0+
|
|
390
|
+
|
|
391
|
+
### Installation
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
# Using npm
|
|
395
|
+
npm install vkedit vue konva vue-konva pinia
|
|
396
|
+
|
|
397
|
+
# Using pnpm
|
|
398
|
+
pnpm add vkedit vue konva vue-konva pinia
|
|
399
|
+
|
|
400
|
+
# Using yarn
|
|
401
|
+
yarn add vkedit vue konva vue-konva pinia
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Basic Usage Example
|
|
405
|
+
|
|
406
|
+
```vue
|
|
407
|
+
<template>
|
|
408
|
+
<Vkedit
|
|
409
|
+
:host="host"
|
|
410
|
+
:show-toolbox="true"
|
|
411
|
+
:show-property-panel="true"
|
|
412
|
+
:show-toolbar="true"
|
|
413
|
+
/>
|
|
414
|
+
</template>
|
|
415
|
+
|
|
416
|
+
<script setup lang="ts">
|
|
417
|
+
import { createEditorHost, Vkedit } from 'vkedit'
|
|
418
|
+
import {
|
|
419
|
+
RectPlugin,
|
|
420
|
+
TextPlugin,
|
|
421
|
+
TablePlugin,
|
|
422
|
+
QrcodePlugin,
|
|
423
|
+
BarcodePlugin,
|
|
424
|
+
ChartPlugin,
|
|
425
|
+
LinePlugin
|
|
426
|
+
} from 'vkedit'
|
|
427
|
+
|
|
428
|
+
// Create editor host
|
|
429
|
+
const host = createEditorHost({
|
|
430
|
+
basePropertyPanel: false,
|
|
431
|
+
baseCanvasPropertyPanel: true,
|
|
432
|
+
exportPlugin: true,
|
|
433
|
+
previewPlugin: true,
|
|
434
|
+
importPlugin: true
|
|
435
|
+
})
|
|
436
|
+
|
|
437
|
+
// Install graphic plugins
|
|
438
|
+
host
|
|
439
|
+
.installPlugin('rect-plugin', RectPlugin)
|
|
440
|
+
.installPlugin('text-plugin', TextPlugin)
|
|
441
|
+
.installPlugin('table-plugin', TablePlugin)
|
|
442
|
+
.installPlugin('qr-plugin', QrcodePlugin)
|
|
443
|
+
.installPlugin('barcode-plugin', BarcodePlugin)
|
|
444
|
+
.installPlugin('chart-plugin', ChartPlugin)
|
|
445
|
+
.installPlugin('line-plugin', LinePlugin)
|
|
446
|
+
|
|
447
|
+
// Set canvas dimensions (A4 paper)
|
|
448
|
+
host.setStatus({
|
|
449
|
+
dpm: 8, // Dots per millimeter (DPI / 25.4)
|
|
450
|
+
width: 210 * 8, // A4 width 210mm
|
|
451
|
+
height: 297 * 8, // A4 height 297mm
|
|
452
|
+
zoom: 0.4 // Zoom level
|
|
453
|
+
})
|
|
454
|
+
</script>
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Optional Configuration
|
|
458
|
+
|
|
459
|
+
The `createEditorHost` function accepts the following configuration options:
|
|
460
|
+
|
|
461
|
+
| Option | Type | Default | Description |
|
|
462
|
+
| ------------------------- | ------- | ------- | ---------------------------------- |
|
|
463
|
+
| `basePropertyPanel` | boolean | false | Enable base element property panel |
|
|
464
|
+
| `baseCanvasPropertyPanel` | boolean | true | Enable canvas property panel |
|
|
465
|
+
| `exportPlugin` | boolean | true | Enable export plugin |
|
|
466
|
+
| `previewPlugin` | boolean | true | Enable preview plugin |
|
|
467
|
+
| `importPlugin` | boolean | true | Enable import plugin |
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## 🔌 Available Plugin List
|
|
472
|
+
|
|
473
|
+
### Core Plugins
|
|
474
|
+
|
|
475
|
+
| Plugin Name | Description |
|
|
476
|
+
| ------------------------------ | ---------------------------------------------------------------------------- |
|
|
477
|
+
| **ToolbarManagerPlugin** | Toolbar manager, providing top toolbar functionality |
|
|
478
|
+
| **GraphicToolManagerPlugin** | Graphic tool manager, managing graphic drawing tools |
|
|
479
|
+
| **GraphicManagerPlugin** | Graphic manager, unified management of all graphic elements |
|
|
480
|
+
| **ElementManagerPlugin** | Element manager, managing element lifecycle |
|
|
481
|
+
| **SelectionPlugin** | Selection plugin, handling element selection and multi-selection operations |
|
|
482
|
+
| **PropertyPanelManagerPlugin** | Property property panel manager, dynamically rendering property panels |
|
|
483
|
+
| **KeyDownPlugin** | Keyboard event plugin, handling shortcuts |
|
|
484
|
+
| **AlignPlugin** | Alignment plugin, providing element alignment and distribution functionality |
|
|
485
|
+
| **ContextMenuManagerPlugin** | Context menu manager |
|
|
486
|
+
|
|
487
|
+
### Feature Plugins
|
|
488
|
+
|
|
489
|
+
| Plugin Name | Description |
|
|
490
|
+
| ----------------- | ------------------------------------------------------------------------- |
|
|
491
|
+
| **ExportPlugin** | Export plugin, supporting export to JSON, PNG, JPG, PDF and other formats |
|
|
492
|
+
| **ImportPlugin** | Import plugin, supporting importing design data from JSON files |
|
|
493
|
+
| **PreviewPlugin** | Preview plugin, providing design preview functionality |
|
|
494
|
+
|
|
495
|
+
### Graphic Plugins
|
|
496
|
+
|
|
497
|
+
| Plugin Name | Graphic Type | Description |
|
|
498
|
+
| ----------------- | ------------ | ------------------------------------------------------------------- |
|
|
499
|
+
| **RectPlugin** | Rectangle | Rectangle elements with drag, resize, fill and border adjustments |
|
|
500
|
+
| **TextPlugin** | Text | Text elements supporting font, size, color, and alignment |
|
|
501
|
+
| **LinePlugin** | Line | Line elements supporting start point, end point, color, and width |
|
|
502
|
+
| **TablePlugin** | Table | Table elements supporting rows/columns, borders, and text alignment |
|
|
503
|
+
| **QrcodePlugin** | QR Code | Configurable QR code elements |
|
|
504
|
+
| **BarcodePlugin** | Barcode | Barcodes supporting multiple formats (EAN-13, CODE-128, etc.) |
|
|
505
|
+
| **ChartPlugin** | Chart | Chart elements based on ECharts |
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## 📚 API Reference
|
|
510
|
+
|
|
511
|
+
### createEditorHost()
|
|
512
|
+
|
|
513
|
+
Creates an editor host instance and installs core plugins.
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
function createEditorHost(options: IOptions): EditorHost
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**Parameters:**
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
interface IOptions {
|
|
523
|
+
basePropertyPanel?: boolean // Enable base element property panel
|
|
524
|
+
baseCanvasPropertyPanel?: boolean // Enable canvas property panel
|
|
525
|
+
exportPlugin?: boolean // Enable export plugin
|
|
526
|
+
previewPlugin?: boolean // Enable preview plugin
|
|
527
|
+
importPlugin?: boolean // Enable import plugin
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**Returns:** `EditorHost` instance
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
### EditorHost Class Methods
|
|
536
|
+
|
|
537
|
+
#### Plugin Management
|
|
538
|
+
|
|
539
|
+
| Method | Description |
|
|
540
|
+
| ---------------------------------- | ------------------- |
|
|
541
|
+
| `installPlugin(name, pluginClass)` | Install plugin |
|
|
542
|
+
| `uninstallPlugin(pluginName)` | Uninstall plugin |
|
|
543
|
+
| `getPlugin<T>(pluginName)` | Get plugin instance |
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
// Install plugin
|
|
547
|
+
host.installPlugin('rect-plugin', RectPlugin)
|
|
548
|
+
|
|
549
|
+
// Uninstall plugin
|
|
550
|
+
host.uninstallPlugin('rect-plugin')
|
|
551
|
+
|
|
552
|
+
// Get plugin instance
|
|
553
|
+
const rectPlugin = host.getPlugin<RectPlugin>('rect-plugin')
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
#### Command Operations
|
|
557
|
+
|
|
558
|
+
| Method | Description |
|
|
559
|
+
| ------------------------- | --------------- |
|
|
560
|
+
| `executeCommand(command)` | Execute command |
|
|
561
|
+
| `undo()` | Undo |
|
|
562
|
+
| `redo()` | Redo |
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
import { AddElementCommand } from 'vkedit'
|
|
566
|
+
|
|
567
|
+
// Execute command
|
|
568
|
+
const command = new AddElementCommand(element, host)
|
|
569
|
+
host.executeCommand(command)
|
|
570
|
+
|
|
571
|
+
// Undo
|
|
572
|
+
host.undo()
|
|
573
|
+
|
|
574
|
+
// Redo
|
|
575
|
+
host.redo()
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
#### Event System
|
|
579
|
+
|
|
580
|
+
| Method | Description |
|
|
581
|
+
| ---------------------- | ------------------ |
|
|
582
|
+
| `emit(event, payload)` | Trigger event |
|
|
583
|
+
| `on(event, handler)` | Subscribe to event |
|
|
584
|
+
| `off(event, handler)` | Unsubscribe |
|
|
585
|
+
|
|
586
|
+
```typescript
|
|
587
|
+
// Subscribe to event
|
|
588
|
+
host.on('element:added', (payload) => {
|
|
589
|
+
console.log('Element added:', payload)
|
|
590
|
+
})
|
|
591
|
+
|
|
592
|
+
// Trigger event
|
|
593
|
+
host.emit('element:added', { element: myElement })
|
|
594
|
+
|
|
595
|
+
// Unsubscribe
|
|
596
|
+
host.off('element:added')
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
#### State Management
|
|
600
|
+
|
|
601
|
+
| Property | Type | Description |
|
|
602
|
+
| -------- | -------------- | ------------------------ |
|
|
603
|
+
| `status` | `IEditorState` | Editor state (read-only) |
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
interface IEditorState {
|
|
607
|
+
zoom: number // Zoom level
|
|
608
|
+
currentTool: string // Current tool
|
|
609
|
+
snapToGrid: boolean // Whether to snap to grid
|
|
610
|
+
showGrid: boolean // Whether to show grid
|
|
611
|
+
width: number // Canvas width (pixels)
|
|
612
|
+
height: number // Canvas height (pixels)
|
|
613
|
+
wmm: number // Canvas width (mm)
|
|
614
|
+
hmm: number // Canvas height (mm)
|
|
615
|
+
dpm: number // Dots per millimeter
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
```typescript
|
|
620
|
+
// Update state
|
|
621
|
+
host.setStatus({
|
|
622
|
+
zoom: 1,
|
|
623
|
+
width: 800,
|
|
624
|
+
height: 600
|
|
625
|
+
})
|
|
626
|
+
|
|
627
|
+
// Read state
|
|
628
|
+
console.log(host.status.zoom)
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
#### Serialization
|
|
632
|
+
|
|
633
|
+
| Method | Description |
|
|
634
|
+
| ------------------- | ----------------------- |
|
|
635
|
+
| `toJSON()` | Export as JSON string |
|
|
636
|
+
| `loadJSON(jsonStr)` | Import from JSON string |
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
// Export
|
|
640
|
+
const json = host.toJSON()
|
|
641
|
+
|
|
642
|
+
// Import
|
|
643
|
+
host.loadJSON(json)
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
## 🎯 Event System
|
|
649
|
+
|
|
650
|
+
The editor provides rich event types, supporting loose coupling communication between plugins.
|
|
651
|
+
|
|
652
|
+
### Lifecycle Events
|
|
653
|
+
|
|
654
|
+
| Event Name | Description |
|
|
655
|
+
| ---------------- | ---------------- |
|
|
656
|
+
| `editor:ready` | Editor ready |
|
|
657
|
+
| `editor:destroy` | Editor destroyed |
|
|
658
|
+
| `editor:reset` | Editor reset |
|
|
659
|
+
|
|
660
|
+
### File Operation Events
|
|
661
|
+
|
|
662
|
+
| Event Name | Description |
|
|
663
|
+
| ---------------------- | ------------------------------- |
|
|
664
|
+
| `file:new` | New file |
|
|
665
|
+
| `file:open` | Open file |
|
|
666
|
+
| `file:save` | Save file |
|
|
667
|
+
| `file:save-as` | Save as |
|
|
668
|
+
| `file:export` | Export file |
|
|
669
|
+
| `file:import` | Import file |
|
|
670
|
+
| `file:loaded` | File loaded |
|
|
671
|
+
| `file:saved` | File saved |
|
|
672
|
+
| `file:modified-change` | File modification state changed |
|
|
673
|
+
|
|
674
|
+
### Stage Interaction Events
|
|
675
|
+
|
|
676
|
+
| Event Name | Description |
|
|
677
|
+
| ------------------- | ------------------ |
|
|
678
|
+
| `stage:mousedown` | Mouse down |
|
|
679
|
+
| `stage:mousemove` | Mouse move |
|
|
680
|
+
| `stage:mouseup` | Mouse up |
|
|
681
|
+
| `stage:click` | Mouse click |
|
|
682
|
+
| `stage:dblclick` | Mouse double click |
|
|
683
|
+
| `stage:contextmenu` | Context menu |
|
|
684
|
+
| `stage:wheel` | Mouse wheel |
|
|
685
|
+
| `stage:dragstart` | Drag start |
|
|
686
|
+
| `stage:dragend` | Drag end |
|
|
687
|
+
| `stage:redraw` | Stage redraw |
|
|
688
|
+
|
|
689
|
+
### Keyboard Events
|
|
690
|
+
|
|
691
|
+
| Event Name | Description |
|
|
692
|
+
| ---------------------- | ----------- |
|
|
693
|
+
| `stage:keydown` | Key down |
|
|
694
|
+
| `stage:keydown-delete` | Delete key |
|
|
695
|
+
| `stage:keydown-left` | Left arrow |
|
|
696
|
+
| `stage:keydown-right` | Right arrow |
|
|
697
|
+
| `stage:keydown-up` | Up arrow |
|
|
698
|
+
| `stage:keydown-down` | Down arrow |
|
|
699
|
+
|
|
700
|
+
### Graphic Element Events
|
|
701
|
+
|
|
702
|
+
| Event Name | Description |
|
|
703
|
+
| --------------------------- | ------------------------- |
|
|
704
|
+
| `element:registered` | Element type registered |
|
|
705
|
+
| `element:unregistered` | Element type unregistered |
|
|
706
|
+
| `element:added` | Element added |
|
|
707
|
+
| `element:removed` | Element removed |
|
|
708
|
+
| `element:selected` | Element selected |
|
|
709
|
+
| `element:deselected` | Element deselected |
|
|
710
|
+
| `element:transformed` | Element transformed |
|
|
711
|
+
| `element:updated` | Element updated |
|
|
712
|
+
| `element:copied` | Element copied |
|
|
713
|
+
| `element:pasted` | Element pasted |
|
|
714
|
+
| `element:cloned` | Element cloned |
|
|
715
|
+
| `element:locked-change` | Lock state changed |
|
|
716
|
+
| `element:visibility-change` | Visibility changed |
|
|
717
|
+
| `element:zindex-change` | Z-index changed |
|
|
718
|
+
|
|
719
|
+
### Selection Events
|
|
720
|
+
|
|
721
|
+
| Event Name | Description |
|
|
722
|
+
| ------------------------ | ----------------------- |
|
|
723
|
+
| `selection:changed` | Selection changed |
|
|
724
|
+
| `selection:cleared` | Selection cleared |
|
|
725
|
+
| `selection:multi-change` | Multi-selection changed |
|
|
726
|
+
|
|
727
|
+
### View Events
|
|
728
|
+
|
|
729
|
+
| Event Name | Description |
|
|
730
|
+
| ------------------------------ | ---------------- |
|
|
731
|
+
| `view:zoom-change` | Zoom changed |
|
|
732
|
+
| `view:pan` | Pan |
|
|
733
|
+
| `view:zoom-to` | Fit to view |
|
|
734
|
+
| `view:reset` | Reset view |
|
|
735
|
+
| `view:grid-visibility-change` | Grid visibility |
|
|
736
|
+
| `view:snap-change` | Snap changed |
|
|
737
|
+
| `view:ruler-visibility-change` | Ruler visibility |
|
|
738
|
+
|
|
739
|
+
### Layer Events
|
|
740
|
+
|
|
741
|
+
| Event Name | Description |
|
|
742
|
+
| ------------------------- | ------------------- |
|
|
743
|
+
| `layer:added` | Layer added |
|
|
744
|
+
| `layer:removed` | Layer removed |
|
|
745
|
+
| `layer:order-changed` | Layer order changed |
|
|
746
|
+
| `layer:visibility-change` | Layer visibility |
|
|
747
|
+
| `layer:locked-change` | Layer locked |
|
|
748
|
+
| `layer:active-change` | Layer active |
|
|
749
|
+
|
|
750
|
+
### Command History Events
|
|
751
|
+
|
|
752
|
+
| Event Name | Description |
|
|
753
|
+
| ------------------ | ---------------- |
|
|
754
|
+
| `command:executed` | Command executed |
|
|
755
|
+
| `command:undone` | Command undone |
|
|
756
|
+
| `command:redone` | Command redone |
|
|
757
|
+
| `history:changed` | History changed |
|
|
758
|
+
| `history:cleared` | History cleared |
|
|
759
|
+
|
|
760
|
+
### Plugin System Events
|
|
761
|
+
|
|
762
|
+
| Event Name | Description |
|
|
763
|
+
| --------------------- | ------------------- |
|
|
764
|
+
| `plugin:registered` | Plugin registered |
|
|
765
|
+
| `plugin:unregistered` | Plugin unregistered |
|
|
766
|
+
| `plugin:activated` | Plugin activated |
|
|
767
|
+
| `plugin:deactivated` | Plugin deactivated |
|
|
768
|
+
| `plugin:loaded` | Plugin loaded |
|
|
769
|
+
| `plugin:error` | Plugin error |
|
|
770
|
+
|
|
771
|
+
### Alignment Distribution Events
|
|
772
|
+
|
|
773
|
+
| Event Name | Description |
|
|
774
|
+
| --------------------- | -------------------- |
|
|
775
|
+
| `elements:align` | Elements aligned |
|
|
776
|
+
| `elements:distribute` | Elements distributed |
|
|
777
|
+
| `elements:group` | Elements grouped |
|
|
778
|
+
| `elements:ungroup`` | Elements ungrouped |
|
|
779
|
+
| `elements:layer` | Layer operation |
|
|
780
|
+
|
|
781
|
+
### State Management Events
|
|
782
|
+
|
|
783
|
+
| Event Name | Description |
|
|
784
|
+
| ---------------------- | --------------- |
|
|
785
|
+
| `host:status-changed` | Status changed |
|
|
786
|
+
| `host:status-saved` | Status saved |
|
|
787
|
+
| `host:status-restored` | Status restored |
|
|
788
|
+
|
|
789
|
+
### Serialization Events
|
|
790
|
+
|
|
791
|
+
| Event Name | Description |
|
|
792
|
+
| ------------------------- | -------------------- |
|
|
793
|
+
| `host:load-json:start` | Load JSON start |
|
|
794
|
+
| `host:load-json:complete` | Load JSON complete |
|
|
795
|
+
| `host:load-json:error` | Load JSON error |
|
|
796
|
+
| `host:to-json:start` | Export JSON start |
|
|
797
|
+
| `host:to-json:complete` | Export JSON complete |
|
|
798
|
+
| `host:to-json:error` | Export JSON error |
|
|
799
|
+
|
|
800
|
+
### Event Usage Example
|
|
801
|
+
|
|
802
|
+
```typescript
|
|
803
|
+
import type { ElementEventData, SelectionEventData } from 'vkedit'
|
|
804
|
+
|
|
805
|
+
// Listen to element add event
|
|
806
|
+
host.on('element:added', (payload: ElementEventData) => {
|
|
807
|
+
console.log('New element added:', payload.element)
|
|
808
|
+
})
|
|
809
|
+
|
|
810
|
+
// Listen to selection change event
|
|
811
|
+
host.on('selection:changed', (payload: SelectionEventData) => {
|
|
812
|
+
console.log('Selected element count:', payload.selectedIds.length)
|
|
813
|
+
})
|
|
814
|
+
|
|
815
|
+
// Listen to status change
|
|
816
|
+
host.on('host:status-changed', (payload) => {
|
|
817
|
+
console.log('Status updated:', payload.status)
|
|
818
|
+
})
|
|
819
|
+
|
|
820
|
+
// Trigger custom event
|
|
821
|
+
host.emit('custom:my-event', { data: 'some data' })
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
### Extending Event System
|
|
825
|
+
|
|
826
|
+
Developers can extend the event map through module declarations:
|
|
827
|
+
|
|
828
|
+
```typescript
|
|
829
|
+
declare module '@/types' {
|
|
830
|
+
interface EventMap {
|
|
831
|
+
'my-plugin:some-event': (payload: MyEventData) => void
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
interface MyEventData {
|
|
836
|
+
id: string
|
|
837
|
+
value: number
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// Use extended event
|
|
841
|
+
host.emit('my-plugin:some-event', { id: '123', value: 42 })
|
|
842
|
+
|
|
843
|
+
// Listen to extended event
|
|
844
|
+
host.on('my-plugin:some-event', (payload) => {
|
|
845
|
+
console.log(payload.value)
|
|
846
|
+
})
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
---
|
|
850
|
+
|
|
851
|
+
## 📝 Command System
|
|
852
|
+
|
|
853
|
+
vkedit uses the command pattern to implement undoable operations. All operations that modify the editor state should be executed through commands.
|
|
854
|
+
|
|
855
|
+
### Available Command Types
|
|
856
|
+
|
|
857
|
+
| Command Class | Description |
|
|
858
|
+
| ------------------------- | -------------------------------------------- |
|
|
859
|
+
| `AddElementCommand` | Add element |
|
|
860
|
+
| `RemoveElementCommand` | Remove element |
|
|
861
|
+
| `TransformElementCommand` | Transform element (position, size, rotation) |
|
|
862
|
+
| `UpdatePropertyCommand` | Update element property |
|
|
863
|
+
| `ClearSelectionCommand` | Clear selection |
|
|
864
|
+
| `BatchCommand` | Batch command |
|
|
865
|
+
| `ChangeLayerOrderCommand` | Change layer order |
|
|
866
|
+
| `AlignElementsCommand` | Align elements |
|
|
867
|
+
|
|
868
|
+
### Command Execution
|
|
869
|
+
|
|
870
|
+
```typescript
|
|
871
|
+
import { AddElementCommand, TransformElementCommand } from 'vkedit'
|
|
872
|
+
|
|
873
|
+
// Create and execute command
|
|
874
|
+
const command = new AddElementCommand(element, host)
|
|
875
|
+
host.executeCommand(command)
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
### Undo and Redo
|
|
879
|
+
|
|
880
|
+
```typescript
|
|
881
|
+
// Undo last operation
|
|
882
|
+
host.undo()
|
|
883
|
+
|
|
884
|
+
// Redo undone operation
|
|
885
|
+
host.redo()
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
### Batch Commands
|
|
889
|
+
|
|
890
|
+
```typescript
|
|
891
|
+
import { BatchCommand } from 'vkedit'
|
|
892
|
+
|
|
893
|
+
const commands = [
|
|
894
|
+
new UpdatePropertyCommand(element1, 'x', 100),
|
|
895
|
+
new UpdatePropertyCommand(element2, 'y', 200)
|
|
896
|
+
]
|
|
897
|
+
|
|
898
|
+
const batchCommand = new BatchCommand(commands)
|
|
899
|
+
host.executeCommand(batchCommand)
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
---
|
|
903
|
+
|
|
904
|
+
## 💻 Development Guide
|
|
905
|
+
|
|
906
|
+
### Development Environment Setup
|
|
907
|
+
|
|
908
|
+
```bash
|
|
909
|
+
# Clone repository
|
|
910
|
+
git clone https://github.com/your-org/vkedit.git
|
|
911
|
+
cd vkedit
|
|
912
|
+
|
|
913
|
+
# Install dependencies (recommended pnpm)
|
|
914
|
+
pnpm install
|
|
915
|
+
|
|
916
|
+
# Start development server
|
|
917
|
+
pnpm dev
|
|
918
|
+
|
|
919
|
+
# Type check
|
|
920
|
+
pnpm type-check
|
|
921
|
+
|
|
922
|
+
# Code check and fix
|
|
923
|
+
pnpm lint
|
|
924
|
+
|
|
925
|
+
# Code formatting
|
|
926
|
+
pnpm format
|
|
927
|
+
|
|
928
|
+
# Build production version
|
|
929
|
+
pnpm build
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
### Available Script Commands
|
|
933
|
+
|
|
934
|
+
| Command | Description |
|
|
935
|
+
| ----------------- | -------------------------- |
|
|
936
|
+
| `pnpm dev` | Start development server |
|
|
937
|
+
| `pnpm build` | Build production version |
|
|
938
|
+
| `pnpm build-only` | Build only (no type check) |
|
|
939
|
+
| `pnpm preview` | Preview production build |
|
|
940
|
+
| `pnpm type-check` | TypeScript type check |
|
|
941
|
+
| `pnpm lint` | ESLint check and auto-fix |
|
|
942
|
+
| `pnpm format` | Prettier format code |
|
|
943
|
+
| `pnpm build:css` | Build CSS files |
|
|
944
|
+
|
|
945
|
+
### Developing Custom Plugins
|
|
946
|
+
|
|
947
|
+
Custom plugins need to implement the [`IEditorPlugin`](src/types/base-plugin.ts:5) interface:
|
|
948
|
+
|
|
949
|
+
```typescript
|
|
950
|
+
import type { IEditorPlugin } from ''vkedit'
|
|
951
|
+
|
|
952
|
+
export class MyCustomPlugin implements IEditorPlugin {
|
|
953
|
+
constructor(private host: EditorHost) {}
|
|
954
|
+
|
|
955
|
+
install(host: EditorHost): void {
|
|
956
|
+
// Listen to events
|
|
957
|
+
host.on('element:added', this.onElementAdded)
|
|
958
|
+
|
|
959
|
+
// Register tool
|
|
960
|
+
host.emit('tool:registered', {
|
|
961
|
+
name: 'my-tool',
|
|
962
|
+
icon: 'my-icon',
|
|
963
|
+
render: () => MyToolComponent
|
|
964
|
+
})
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
uninstall(): void {
|
|
968
|
+
// Clean up resources
|
|
969
|
+
this.host.off('element:added', this.onElementAdded)
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
private onElementAdded = (payload: any) => {
|
|
973
|
+
console.log('Element added:', payload)
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// Use custom plugin
|
|
978
|
+
host.installPlugin('my-custom-plugin', MyCustomPlugin)
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
### Custom Graphic Elements
|
|
982
|
+
|
|
983
|
+
Creating custom graphic elements requires extending [`BaseGraphicElement`](src/types/base-graphic-element.ts:5):
|
|
984
|
+
|
|
985
|
+
```typescript
|
|
986
|
+
import { BaseGraphicElement } from 'vkedit'
|
|
987
|
+
|
|
988
|
+
export class MyCustomElement extends BaseGraphicElement {
|
|
989
|
+
constructor(
|
|
990
|
+
id: string,
|
|
991
|
+
public width: number = 100,
|
|
992
|
+
public height: number = 100,
|
|
993
|
+
public fill: string = '#ff0000'
|
|
994
|
+
) {
|
|
995
|
+
super(id, 'my-custom')
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
serialize(): Record<string, any> {
|
|
999
|
+
return {
|
|
1000
|
+
...super.serialize(),
|
|
1001
|
+
width: this.width,
|
|
1002
|
+
height: this.height,
|
|
1003
|
+
fill: this.fill
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
deserialize(data: Record<string, any>): void {
|
|
1008
|
+
super.deserialize(data)
|
|
1009
|
+
this.width = data.width
|
|
1010
|
+
this.height = data.height
|
|
1011
|
+
this.fill = data.fill
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
render() {
|
|
1015
|
+
return {
|
|
1016
|
+
tag: 'rect',
|
|
1017
|
+
props: {
|
|
1018
|
+
x: this.x,
|
|
1019
|
+
y: this.y,
|
|
1020
|
+
width: this.width,
|
|
1021
|
+
height: this.height,
|
|
1022
|
+
fill: this.fill
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
---
|
|
1030
|
+
|
|
1031
|
+
## ❓ Frequently Asked Questions (FAQ)
|
|
1032
|
+
|
|
1033
|
+
### Q: How to set canvas size to A4 paper?
|
|
1034
|
+
|
|
1035
|
+
```typescript
|
|
1036
|
+
host.setStatus({
|
|
1037
|
+
dpm: 8, // Dots per millimeter (DPI / 25.4)
|
|
1038
|
+
width: 210 * 8, // A4 width 210mm
|
|
1039
|
+
height: 297 * 8 // A4 height 297mm
|
|
1040
|
+
})
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
### Q: How to export design data?
|
|
1044
|
+
|
|
1045
|
+
```typescript
|
|
1046
|
+
// Export as JSON
|
|
1047
|
+
const json = host.toJSON()
|
|
1048
|
+
|
|
1049
|
+
// Export as image (requires ExportPlugin)
|
|
1050
|
+
host.getPlugin('export-plugin').exportAsPNG()
|
|
1051
|
+
```
|
|
1052
|
+
|
|
1053
|
+
### Q: How to listen to element selection changes?
|
|
1054
|
+
|
|
1055
|
+
```typescript
|
|
1056
|
+
host.on('selection:changed', (payload) => {
|
|
1057
|
+
const selectedIds = payload.selectedIds
|
|
1058
|
+
console.log('Currently selected elements:', selectedIds)
|
|
1059
|
+
})
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
### Q: How to batch update properties of multiple elements?
|
|
1063
|
+
|
|
1064
|
+
```typescript
|
|
1065
|
+
const batchCommand = new BatchCommand([
|
|
1066
|
+
new UpdatePropertyCommand(element1, 'fill', '#ff0000'),
|
|
1067
|
+
new UpdatePropertyCommand(element2, 'fill', '#00ff00'),
|
|
1068
|
+
new UpdatePropertyCommand(element3, 'fill', '#0000ff')
|
|
1069
|
+
])
|
|
1070
|
+
host.executeCommand(batchCommand)
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
### Q: How to disable all core plugins and customize configuration?
|
|
1074
|
+
|
|
1075
|
+
```typescript
|
|
1076
|
+
const host = createEditorHost({
|
|
1077
|
+
basePropertyPanel: false,
|
|
1078
|
+
baseCanvasPropertyPanel: false,
|
|
1079
|
+
exportPlugin: false,
|
|
1080
|
+
previewPlugin: false,
|
|
1081
|
+
importPlugin: false
|
|
1082
|
+
})
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
---
|
|
1086
|
+
|
|
1087
|
+
## 🤝 Contributing Guidelines
|
|
1088
|
+
|
|
1089
|
+
Contributions are welcome! Please follow the guidelines:
|
|
1090
|
+
|
|
1091
|
+
### Code Standards
|
|
1092
|
+
|
|
1093
|
+
- Write code using TypeScript
|
|
1094
|
+
- Follow ESLint rules (auto-check with `pnpm lint`)
|
|
1095
|
+
- Format code with Prettier (`pnpm format`)
|
|
1096
|
+
- Write clear comments and documentation
|
|
1097
|
+
|
|
1098
|
+
### Commit Standards
|
|
1099
|
+
|
|
1100
|
+
Use semantic commit messages:
|
|
1101
|
+
|
|
1102
|
+
```
|
|
1103
|
+
feat: add new feature
|
|
1104
|
+
fix: fix bug
|
|
1105
|
+
docs: update documentation
|
|
1106
|
+
style: code format adjustment
|
|
1107
|
+
refactor: code refactoring
|
|
1108
|
+
perf: performance optimization
|
|
1109
|
+
test: add tests
|
|
1110
|
+
chore: build/tool changes
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
### Development Workflow
|
|
1114
|
+
|
|
1115
|
+
1. Fork repository
|
|
1116
|
+
2. Create feature branch (`git checkout -b feature/AmazingFeature`)
|
|
1117
|
+
3. Commit changes (`git commit -m 'feat: add amazing feature'`)
|
|
1118
|
+
4. Push to branch (`git push origin feature/AmazingFeature`)
|
|
1119
|
+
5. Create Pull Request
|
|
1120
|
+
|
|
1121
|
+
---
|
|
1122
|
+
|
|
1123
|
+
## 📋 Changelog
|
|
1124
|
+
|
|
1125
|
+
### 2.8.5
|
|
1126
|
+
- Current stable version
|
|
1127
|
+
- Complete plugin system architecture
|
|
1128
|
+
- Support for multiple graphic elements
|
|
1129
|
+
- Import/Export functionality
|
|
1130
|
+
- Undo/Redo mechanism
|
|
1131
|
+
|
|
1132
|
+
### Version History
|
|
1133
|
+
For detailed version history, see [GitHub Releases](https://github.com/your-org/vkedit/releases)
|
|
1134
|
+
|
|
1135
|
+
---
|
|
1136
|
+
|
|
1137
|
+
## 📄 License
|
|
1138
|
+
|
|
1139
|
+
This project is licensed under the MIT License - see [LICENSE](LICENSE) file for details
|
|
1140
|
+
|
|
1141
|
+
---
|
|
1142
|
+
|
|
1143
|
+
## 🔗 Related Links
|
|
1144
|
+
|
|
1145
|
+
- [Vue.js](https://vuejs.org/)
|
|
1146
|
+
- [Konva.js](https://konvajs.org/)
|
|
1147
|
+
- [vue-konva](https://www.npmjs.com/package/vue-konva)
|
|
1148
|
+
- [Pinia](https://pinia.vuejs.org/)
|
|
1149
|
+
|
|
1150
|
+
---
|
|
1151
|
+
|
|
1152
|
+
## ☕ Support the Author
|
|
1153
|
+
|
|
1154
|
+
If you find vkedit helpful, please consider supporting the author! Your support is the driving force behind the continued development of the project.
|
|
1155
|
+
|
|
1156
|
+
<div align="center">
|
|
1157
|
+
|
|
1158
|
+
**Made with ❤️ by vkedit contributors**
|
|
1159
|
+
|
|
1160
|
+
</div>
|
|
1161
|
+
|
|
1162
|
+
---
|
|
1163
|
+
|
|
1164
|
+
## 📞 Contact Support
|
|
1165
|
+
|
|
1166
|
+
If you need technical support, custom features, or have any questions, please feel free to contact:
|
|
1167
|
+
|
|
1168
|
+
- **QQ**: 16871824
|
|
1169
|
+
- **Email**: 168715824@qq.com
|
|
1170
|
+
- **Services**: Technical support, feature customization, project collaboration
|
|
1171
|
+
|
|
1172
|
+
Looking forward to communicating with you and improving vkedit together!
|
|
1173
|
+
|