@hprint/plugins 0.0.1-alpha.2 → 0.0.1-alpha.3
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/dist/index.js +17 -17
- package/dist/index.mjs +1071 -1057
- package/dist/src/plugins/AlignGuidLinePlugin.d.ts +7 -2
- package/dist/src/plugins/AlignGuidLinePlugin.d.ts.map +1 -1
- package/dist/src/plugins/GroupAlignPlugin.d.ts.map +1 -1
- package/dist/src/plugins/LockPlugin.d.ts.map +1 -1
- package/dist/src/plugins/QrCodePlugin.d.ts +5 -0
- package/dist/src/plugins/QrCodePlugin.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/assets/style/resizePlugin.css +27 -27
- package/src/objects/Arrow.js +47 -47
- package/src/objects/ThinTailArrow.js +50 -50
- package/src/plugins/AlignGuidLinePlugin.ts +1152 -1141
- package/src/plugins/BarCodePlugin.ts +2 -2
- package/src/plugins/ControlsPlugin.ts +251 -251
- package/src/plugins/ControlsRotatePlugin.ts +111 -111
- package/src/plugins/CopyPlugin.ts +255 -255
- package/src/plugins/DeleteHotKeyPlugin.ts +57 -57
- package/src/plugins/DrawLinePlugin.ts +162 -162
- package/src/plugins/DrawPolygonPlugin.ts +205 -205
- package/src/plugins/DringPlugin.ts +125 -125
- package/src/plugins/FlipPlugin.ts +59 -59
- package/src/plugins/FontPlugin.ts +165 -165
- package/src/plugins/FreeDrawPlugin.ts +49 -49
- package/src/plugins/GroupAlignPlugin.ts +365 -365
- package/src/plugins/GroupPlugin.ts +82 -82
- package/src/plugins/GroupTextEditorPlugin.ts +198 -198
- package/src/plugins/HistoryPlugin.ts +181 -181
- package/src/plugins/ImageStroke.ts +121 -121
- package/src/plugins/LayerPlugin.ts +108 -108
- package/src/plugins/LockPlugin.ts +242 -240
- package/src/plugins/MaskPlugin.ts +155 -155
- package/src/plugins/MaterialPlugin.ts +224 -224
- package/src/plugins/MiddleMousePlugin.ts +45 -45
- package/src/plugins/MoveHotKeyPlugin.ts +46 -46
- package/src/plugins/PathTextPlugin.ts +89 -89
- package/src/plugins/PolygonModifyPlugin.ts +224 -224
- package/src/plugins/PrintPlugin.ts +81 -81
- package/src/plugins/PsdPlugin.ts +52 -52
- package/src/plugins/QrCodePlugin.ts +322 -329
- package/src/plugins/ResizePlugin.ts +278 -278
- package/src/plugins/RulerPlugin.ts +78 -78
- package/src/plugins/SimpleClipImagePlugin.ts +244 -244
- package/src/plugins/UnitPlugin.ts +326 -326
- package/src/plugins/WaterMarkPlugin.ts +257 -257
- package/src/types/eventType.ts +11 -11
- package/src/utils/psd.js +432 -432
- package/src/utils/ruler/guideline.ts +145 -145
- package/src/utils/ruler/index.ts +91 -91
- package/src/utils/ruler/ruler.ts +924 -924
- package/src/utils/ruler/utils.ts +162 -162
- package/tsconfig.json +10 -10
- package/vite.config.ts +29 -29
|
@@ -1,255 +1,255 @@
|
|
|
1
|
-
import { fabric } from '@hprint/core';
|
|
2
|
-
import { v4 as uuid } from 'uuid';
|
|
3
|
-
import { utils } from '@hprint/shared';
|
|
4
|
-
import type { IEditor, IPluginTempl } from '@hprint/core';
|
|
5
|
-
|
|
6
|
-
type IPlugin = Pick<CopyPlugin, 'clone'>;
|
|
7
|
-
|
|
8
|
-
declare module '@hprint/core' {
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
10
|
-
interface IEditor extends IPlugin {}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
class CopyPlugin implements IPluginTempl {
|
|
14
|
-
static pluginName = 'CopyPlugin';
|
|
15
|
-
static apis = ['clone'];
|
|
16
|
-
hotkeys: string[] = ['ctrl+v', 'ctrl+c'];
|
|
17
|
-
private cache: null | fabric.ActiveSelection | fabric.Object = null;
|
|
18
|
-
constructor(
|
|
19
|
-
public canvas: fabric.Canvas,
|
|
20
|
-
public editor: IEditor
|
|
21
|
-
) {
|
|
22
|
-
this.initPaste();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// 多选对象复制
|
|
26
|
-
_copyActiveSelection(activeObject: fabric.Object) {
|
|
27
|
-
// 间距设置
|
|
28
|
-
const grid = 10;
|
|
29
|
-
const canvas = this.canvas;
|
|
30
|
-
const keys = this.editor.getExtensionKey();
|
|
31
|
-
activeObject?.clone((cloned: fabric.Object) => {
|
|
32
|
-
// 再次进行克隆,处理选择多个对象的情况
|
|
33
|
-
cloned.clone((clonedObj: fabric.ActiveSelection) => {
|
|
34
|
-
canvas.discardActiveObject();
|
|
35
|
-
if (clonedObj.left === undefined || clonedObj.top === undefined)
|
|
36
|
-
return;
|
|
37
|
-
// 将克隆的画布重新赋值
|
|
38
|
-
clonedObj.canvas = canvas;
|
|
39
|
-
// 设置位置信息
|
|
40
|
-
clonedObj.set({
|
|
41
|
-
left: clonedObj.left + grid,
|
|
42
|
-
top: clonedObj.top + grid,
|
|
43
|
-
evented: true,
|
|
44
|
-
id: uuid(),
|
|
45
|
-
});
|
|
46
|
-
clonedObj.forEachObject((obj: fabric.Object) => {
|
|
47
|
-
obj.id = uuid();
|
|
48
|
-
canvas.add(obj);
|
|
49
|
-
});
|
|
50
|
-
// 解决不可选择问题
|
|
51
|
-
clonedObj.setCoords();
|
|
52
|
-
canvas.setActiveObject(clonedObj);
|
|
53
|
-
canvas.requestRenderAll();
|
|
54
|
-
});
|
|
55
|
-
}, keys);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// 单个对象复制
|
|
59
|
-
_copyObject(activeObject: fabric.Object) {
|
|
60
|
-
// 间距设置
|
|
61
|
-
const grid = 10;
|
|
62
|
-
const canvas = this.canvas;
|
|
63
|
-
const keys = this.editor.getExtensionKey();
|
|
64
|
-
activeObject?.clone((cloned: fabric.Object) => {
|
|
65
|
-
if (cloned.left === undefined || cloned.top === undefined) return;
|
|
66
|
-
canvas.discardActiveObject();
|
|
67
|
-
// 设置位置信息
|
|
68
|
-
cloned.set({
|
|
69
|
-
left: cloned.left + grid,
|
|
70
|
-
top: cloned.top + grid,
|
|
71
|
-
evented: true,
|
|
72
|
-
id: uuid(),
|
|
73
|
-
});
|
|
74
|
-
canvas.add(cloned);
|
|
75
|
-
canvas.setActiveObject(cloned);
|
|
76
|
-
canvas.requestRenderAll();
|
|
77
|
-
}, keys);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 复制元素
|
|
81
|
-
clone(paramsActiveObeject?: fabric.ActiveSelection | fabric.Object) {
|
|
82
|
-
const activeObject =
|
|
83
|
-
paramsActiveObeject || this.canvas.getActiveObject();
|
|
84
|
-
if (!activeObject) return;
|
|
85
|
-
if (activeObject?.type === 'activeSelection') {
|
|
86
|
-
this._copyActiveSelection(activeObject);
|
|
87
|
-
} else {
|
|
88
|
-
this._copyObject(activeObject);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// 快捷键扩展回调
|
|
93
|
-
hotkeyEvent(eventName: string, e: KeyboardEvent) {
|
|
94
|
-
if (eventName === 'ctrl+c' && e.type === 'keydown') {
|
|
95
|
-
const activeObject = this.canvas.getActiveObject();
|
|
96
|
-
this.cache = activeObject;
|
|
97
|
-
// 清空剪切板
|
|
98
|
-
navigator.clipboard.writeText('');
|
|
99
|
-
}
|
|
100
|
-
if (eventName === 'ctrl+v' && e.type === 'keydown') {
|
|
101
|
-
// 确保clone元素操作的执行晚于pasteListener
|
|
102
|
-
setTimeout(() => {
|
|
103
|
-
if (this.cache) {
|
|
104
|
-
this.clone(this.cache);
|
|
105
|
-
}
|
|
106
|
-
}, 0);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
contextMenu() {
|
|
111
|
-
const activeObject = this.canvas.getActiveObject();
|
|
112
|
-
if (activeObject) {
|
|
113
|
-
return [
|
|
114
|
-
{
|
|
115
|
-
text: '复制',
|
|
116
|
-
hotkey: 'Ctrl+V',
|
|
117
|
-
disabled: false,
|
|
118
|
-
onclick: () => this.clone(),
|
|
119
|
-
},
|
|
120
|
-
];
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
destroy() {
|
|
125
|
-
console.log('pluginDestroy');
|
|
126
|
-
window.removeEventListener('paste', (e) => this.pasteListener(e));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
initPaste() {
|
|
130
|
-
window.addEventListener('paste', (e) => this.pasteListener(e));
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async pasteListener(event: any) {
|
|
134
|
-
const canvas = this.canvas;
|
|
135
|
-
if (document.activeElement === document.body) {
|
|
136
|
-
event.preventDefault(); // 阻止默认粘贴行为
|
|
137
|
-
} else {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const items = (event.clipboardData || event.originalEvent.clipboardData)
|
|
142
|
-
.items;
|
|
143
|
-
const fileAccept =
|
|
144
|
-
'.pdf,.psd,.cdr,.ai,.svg,.jpg,.jpeg,.png,.webp,.json';
|
|
145
|
-
for (const item of items) {
|
|
146
|
-
if (item.kind === 'file') {
|
|
147
|
-
const file = item.getAsFile();
|
|
148
|
-
const curFileSuffix: string | undefined = file.name
|
|
149
|
-
.split('.')
|
|
150
|
-
.pop();
|
|
151
|
-
if (!fileAccept.split(',').includes(`.${curFileSuffix}`))
|
|
152
|
-
return;
|
|
153
|
-
if (curFileSuffix === 'svg') {
|
|
154
|
-
const svgFile = await utils.getImgStr(file);
|
|
155
|
-
if (!svgFile) throw new Error('file is undefined');
|
|
156
|
-
fabric.loadSVGFromURL(
|
|
157
|
-
svgFile as string,
|
|
158
|
-
(objects, options) => {
|
|
159
|
-
const item = fabric.util.groupSVGElements(objects, {
|
|
160
|
-
...options,
|
|
161
|
-
name: 'defaultSVG',
|
|
162
|
-
id: uuid(),
|
|
163
|
-
});
|
|
164
|
-
canvas.add(item).centerObject(item).renderAll();
|
|
165
|
-
}
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
// if (curFileSuffix === 'json') {
|
|
169
|
-
// const dataText = await getImageText(file);
|
|
170
|
-
// const template = JSON.parse(dataText);
|
|
171
|
-
// addTemplate(template);
|
|
172
|
-
// }
|
|
173
|
-
if (item.type.indexOf('image/') === 0) {
|
|
174
|
-
// 这是一个图片文件
|
|
175
|
-
const imageUrl = URL.createObjectURL(file);
|
|
176
|
-
const imgEl = document.createElement('img');
|
|
177
|
-
imgEl.src = imageUrl;
|
|
178
|
-
// 插入页面
|
|
179
|
-
document.body.appendChild(imgEl);
|
|
180
|
-
imgEl.onload = () => {
|
|
181
|
-
// 创建图片对象
|
|
182
|
-
const imgInstance = new fabric.Image(imgEl, {
|
|
183
|
-
id: uuid(),
|
|
184
|
-
name: '图片1',
|
|
185
|
-
left: 100,
|
|
186
|
-
top: 100,
|
|
187
|
-
});
|
|
188
|
-
// 设置缩放
|
|
189
|
-
canvas.add(imgInstance);
|
|
190
|
-
canvas.setActiveObject(imgInstance);
|
|
191
|
-
canvas.renderAll();
|
|
192
|
-
// 删除页面中的图片元素
|
|
193
|
-
imgEl.remove();
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
} else if (
|
|
197
|
-
item.kind === 'string' &&
|
|
198
|
-
item.type.indexOf('text/plain') === 0
|
|
199
|
-
) {
|
|
200
|
-
// 文本数据
|
|
201
|
-
item.getAsString((text: any) => {
|
|
202
|
-
// 插入到文本框
|
|
203
|
-
const activeObject =
|
|
204
|
-
canvas.getActiveObject() as fabric.Textbox;
|
|
205
|
-
// 如果是激活的文字把复制的内容插入到对应光标位置
|
|
206
|
-
if (
|
|
207
|
-
activeObject &&
|
|
208
|
-
(activeObject.type === 'textbox' ||
|
|
209
|
-
activeObject.type === 'i-text') &&
|
|
210
|
-
activeObject.text
|
|
211
|
-
) {
|
|
212
|
-
const cursorPosition = activeObject.selectionStart;
|
|
213
|
-
const textBeforeCursorPosition =
|
|
214
|
-
activeObject.text.substring(0, cursorPosition);
|
|
215
|
-
const textAfterCursorPosition =
|
|
216
|
-
activeObject.text.substring(
|
|
217
|
-
cursorPosition as number
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
// 更新文本对象的文本
|
|
221
|
-
activeObject.set(
|
|
222
|
-
'text',
|
|
223
|
-
textBeforeCursorPosition +
|
|
224
|
-
text +
|
|
225
|
-
textAfterCursorPosition
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
// 重新设置光标的位置
|
|
229
|
-
activeObject.selectionStart =
|
|
230
|
-
cursorPosition + text.length;
|
|
231
|
-
activeObject.selectionEnd =
|
|
232
|
-
cursorPosition + text.length;
|
|
233
|
-
|
|
234
|
-
// 重新渲染画布展示更新后的文本
|
|
235
|
-
activeObject.dirty = true;
|
|
236
|
-
canvas.renderAll();
|
|
237
|
-
} else {
|
|
238
|
-
const fabricText = new fabric.IText(text, {
|
|
239
|
-
left: 100,
|
|
240
|
-
top: 100,
|
|
241
|
-
fontSize: 80,
|
|
242
|
-
id: uuid(),
|
|
243
|
-
});
|
|
244
|
-
canvas.add(fabricText);
|
|
245
|
-
canvas.setActiveObject(fabricText);
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
// 复制浏览器外的元素时,清空暂存的画布内粘贴元素
|
|
251
|
-
if (items.length) this.cache = null;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
export default CopyPlugin;
|
|
1
|
+
import { fabric } from '@hprint/core';
|
|
2
|
+
import { v4 as uuid } from 'uuid';
|
|
3
|
+
import { utils } from '@hprint/shared';
|
|
4
|
+
import type { IEditor, IPluginTempl } from '@hprint/core';
|
|
5
|
+
|
|
6
|
+
type IPlugin = Pick<CopyPlugin, 'clone'>;
|
|
7
|
+
|
|
8
|
+
declare module '@hprint/core' {
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
10
|
+
interface IEditor extends IPlugin {}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class CopyPlugin implements IPluginTempl {
|
|
14
|
+
static pluginName = 'CopyPlugin';
|
|
15
|
+
static apis = ['clone'];
|
|
16
|
+
hotkeys: string[] = ['ctrl+v', 'ctrl+c'];
|
|
17
|
+
private cache: null | fabric.ActiveSelection | fabric.Object = null;
|
|
18
|
+
constructor(
|
|
19
|
+
public canvas: fabric.Canvas,
|
|
20
|
+
public editor: IEditor
|
|
21
|
+
) {
|
|
22
|
+
this.initPaste();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 多选对象复制
|
|
26
|
+
_copyActiveSelection(activeObject: fabric.Object) {
|
|
27
|
+
// 间距设置
|
|
28
|
+
const grid = 10;
|
|
29
|
+
const canvas = this.canvas;
|
|
30
|
+
const keys = this.editor.getExtensionKey();
|
|
31
|
+
activeObject?.clone((cloned: fabric.Object) => {
|
|
32
|
+
// 再次进行克隆,处理选择多个对象的情况
|
|
33
|
+
cloned.clone((clonedObj: fabric.ActiveSelection) => {
|
|
34
|
+
canvas.discardActiveObject();
|
|
35
|
+
if (clonedObj.left === undefined || clonedObj.top === undefined)
|
|
36
|
+
return;
|
|
37
|
+
// 将克隆的画布重新赋值
|
|
38
|
+
clonedObj.canvas = canvas;
|
|
39
|
+
// 设置位置信息
|
|
40
|
+
clonedObj.set({
|
|
41
|
+
left: clonedObj.left + grid,
|
|
42
|
+
top: clonedObj.top + grid,
|
|
43
|
+
evented: true,
|
|
44
|
+
id: uuid(),
|
|
45
|
+
});
|
|
46
|
+
clonedObj.forEachObject((obj: fabric.Object) => {
|
|
47
|
+
obj.id = uuid();
|
|
48
|
+
canvas.add(obj);
|
|
49
|
+
});
|
|
50
|
+
// 解决不可选择问题
|
|
51
|
+
clonedObj.setCoords();
|
|
52
|
+
canvas.setActiveObject(clonedObj);
|
|
53
|
+
canvas.requestRenderAll();
|
|
54
|
+
});
|
|
55
|
+
}, keys);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 单个对象复制
|
|
59
|
+
_copyObject(activeObject: fabric.Object) {
|
|
60
|
+
// 间距设置
|
|
61
|
+
const grid = 10;
|
|
62
|
+
const canvas = this.canvas;
|
|
63
|
+
const keys = this.editor.getExtensionKey();
|
|
64
|
+
activeObject?.clone((cloned: fabric.Object) => {
|
|
65
|
+
if (cloned.left === undefined || cloned.top === undefined) return;
|
|
66
|
+
canvas.discardActiveObject();
|
|
67
|
+
// 设置位置信息
|
|
68
|
+
cloned.set({
|
|
69
|
+
left: cloned.left + grid,
|
|
70
|
+
top: cloned.top + grid,
|
|
71
|
+
evented: true,
|
|
72
|
+
id: uuid(),
|
|
73
|
+
});
|
|
74
|
+
canvas.add(cloned);
|
|
75
|
+
canvas.setActiveObject(cloned);
|
|
76
|
+
canvas.requestRenderAll();
|
|
77
|
+
}, keys);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 复制元素
|
|
81
|
+
clone(paramsActiveObeject?: fabric.ActiveSelection | fabric.Object) {
|
|
82
|
+
const activeObject =
|
|
83
|
+
paramsActiveObeject || this.canvas.getActiveObject();
|
|
84
|
+
if (!activeObject) return;
|
|
85
|
+
if (activeObject?.type === 'activeSelection') {
|
|
86
|
+
this._copyActiveSelection(activeObject);
|
|
87
|
+
} else {
|
|
88
|
+
this._copyObject(activeObject);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 快捷键扩展回调
|
|
93
|
+
hotkeyEvent(eventName: string, e: KeyboardEvent) {
|
|
94
|
+
if (eventName === 'ctrl+c' && e.type === 'keydown') {
|
|
95
|
+
const activeObject = this.canvas.getActiveObject();
|
|
96
|
+
this.cache = activeObject;
|
|
97
|
+
// 清空剪切板
|
|
98
|
+
navigator.clipboard.writeText('');
|
|
99
|
+
}
|
|
100
|
+
if (eventName === 'ctrl+v' && e.type === 'keydown') {
|
|
101
|
+
// 确保clone元素操作的执行晚于pasteListener
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
if (this.cache) {
|
|
104
|
+
this.clone(this.cache);
|
|
105
|
+
}
|
|
106
|
+
}, 0);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
contextMenu() {
|
|
111
|
+
const activeObject = this.canvas.getActiveObject();
|
|
112
|
+
if (activeObject) {
|
|
113
|
+
return [
|
|
114
|
+
{
|
|
115
|
+
text: '复制',
|
|
116
|
+
hotkey: 'Ctrl+V',
|
|
117
|
+
disabled: false,
|
|
118
|
+
onclick: () => this.clone(),
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
destroy() {
|
|
125
|
+
console.log('pluginDestroy');
|
|
126
|
+
window.removeEventListener('paste', (e) => this.pasteListener(e));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
initPaste() {
|
|
130
|
+
window.addEventListener('paste', (e) => this.pasteListener(e));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async pasteListener(event: any) {
|
|
134
|
+
const canvas = this.canvas;
|
|
135
|
+
if (document.activeElement === document.body) {
|
|
136
|
+
event.preventDefault(); // 阻止默认粘贴行为
|
|
137
|
+
} else {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const items = (event.clipboardData || event.originalEvent.clipboardData)
|
|
142
|
+
.items;
|
|
143
|
+
const fileAccept =
|
|
144
|
+
'.pdf,.psd,.cdr,.ai,.svg,.jpg,.jpeg,.png,.webp,.json';
|
|
145
|
+
for (const item of items) {
|
|
146
|
+
if (item.kind === 'file') {
|
|
147
|
+
const file = item.getAsFile();
|
|
148
|
+
const curFileSuffix: string | undefined = file.name
|
|
149
|
+
.split('.')
|
|
150
|
+
.pop();
|
|
151
|
+
if (!fileAccept.split(',').includes(`.${curFileSuffix}`))
|
|
152
|
+
return;
|
|
153
|
+
if (curFileSuffix === 'svg') {
|
|
154
|
+
const svgFile = await utils.getImgStr(file);
|
|
155
|
+
if (!svgFile) throw new Error('file is undefined');
|
|
156
|
+
fabric.loadSVGFromURL(
|
|
157
|
+
svgFile as string,
|
|
158
|
+
(objects, options) => {
|
|
159
|
+
const item = fabric.util.groupSVGElements(objects, {
|
|
160
|
+
...options,
|
|
161
|
+
name: 'defaultSVG',
|
|
162
|
+
id: uuid(),
|
|
163
|
+
});
|
|
164
|
+
canvas.add(item).centerObject(item).renderAll();
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
// if (curFileSuffix === 'json') {
|
|
169
|
+
// const dataText = await getImageText(file);
|
|
170
|
+
// const template = JSON.parse(dataText);
|
|
171
|
+
// addTemplate(template);
|
|
172
|
+
// }
|
|
173
|
+
if (item.type.indexOf('image/') === 0) {
|
|
174
|
+
// 这是一个图片文件
|
|
175
|
+
const imageUrl = URL.createObjectURL(file);
|
|
176
|
+
const imgEl = document.createElement('img');
|
|
177
|
+
imgEl.src = imageUrl;
|
|
178
|
+
// 插入页面
|
|
179
|
+
document.body.appendChild(imgEl);
|
|
180
|
+
imgEl.onload = () => {
|
|
181
|
+
// 创建图片对象
|
|
182
|
+
const imgInstance = new fabric.Image(imgEl, {
|
|
183
|
+
id: uuid(),
|
|
184
|
+
name: '图片1',
|
|
185
|
+
left: 100,
|
|
186
|
+
top: 100,
|
|
187
|
+
});
|
|
188
|
+
// 设置缩放
|
|
189
|
+
canvas.add(imgInstance);
|
|
190
|
+
canvas.setActiveObject(imgInstance);
|
|
191
|
+
canvas.renderAll();
|
|
192
|
+
// 删除页面中的图片元素
|
|
193
|
+
imgEl.remove();
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
} else if (
|
|
197
|
+
item.kind === 'string' &&
|
|
198
|
+
item.type.indexOf('text/plain') === 0
|
|
199
|
+
) {
|
|
200
|
+
// 文本数据
|
|
201
|
+
item.getAsString((text: any) => {
|
|
202
|
+
// 插入到文本框
|
|
203
|
+
const activeObject =
|
|
204
|
+
canvas.getActiveObject() as fabric.Textbox;
|
|
205
|
+
// 如果是激活的文字把复制的内容插入到对应光标位置
|
|
206
|
+
if (
|
|
207
|
+
activeObject &&
|
|
208
|
+
(activeObject.type === 'textbox' ||
|
|
209
|
+
activeObject.type === 'i-text') &&
|
|
210
|
+
activeObject.text
|
|
211
|
+
) {
|
|
212
|
+
const cursorPosition = activeObject.selectionStart;
|
|
213
|
+
const textBeforeCursorPosition =
|
|
214
|
+
activeObject.text.substring(0, cursorPosition);
|
|
215
|
+
const textAfterCursorPosition =
|
|
216
|
+
activeObject.text.substring(
|
|
217
|
+
cursorPosition as number
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// 更新文本对象的文本
|
|
221
|
+
activeObject.set(
|
|
222
|
+
'text',
|
|
223
|
+
textBeforeCursorPosition +
|
|
224
|
+
text +
|
|
225
|
+
textAfterCursorPosition
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
// 重新设置光标的位置
|
|
229
|
+
activeObject.selectionStart =
|
|
230
|
+
cursorPosition + text.length;
|
|
231
|
+
activeObject.selectionEnd =
|
|
232
|
+
cursorPosition + text.length;
|
|
233
|
+
|
|
234
|
+
// 重新渲染画布展示更新后的文本
|
|
235
|
+
activeObject.dirty = true;
|
|
236
|
+
canvas.renderAll();
|
|
237
|
+
} else {
|
|
238
|
+
const fabricText = new fabric.IText(text, {
|
|
239
|
+
left: 100,
|
|
240
|
+
top: 100,
|
|
241
|
+
fontSize: 80,
|
|
242
|
+
id: uuid(),
|
|
243
|
+
});
|
|
244
|
+
canvas.add(fabricText);
|
|
245
|
+
canvas.setActiveObject(fabricText);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// 复制浏览器外的元素时,清空暂存的画布内粘贴元素
|
|
251
|
+
if (items.length) this.cache = null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export default CopyPlugin;
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import { fabric } from '@hprint/core';
|
|
2
|
-
import type { IEditor, IPluginTempl } from '@hprint/core';
|
|
3
|
-
|
|
4
|
-
type IPlugin = Pick<DeleteHotKeyPlugin, 'del'>;
|
|
5
|
-
|
|
6
|
-
declare module '@hprint/core' {
|
|
7
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
8
|
-
interface IEditor extends IPlugin {}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
class DeleteHotKeyPlugin implements IPluginTempl {
|
|
12
|
-
static pluginName = 'DeleteHotKeyPlugin';
|
|
13
|
-
static apis = ['del'];
|
|
14
|
-
hotkeys: string[] = ['backspace'];
|
|
15
|
-
constructor(
|
|
16
|
-
public canvas: fabric.Canvas,
|
|
17
|
-
public editor: IEditor
|
|
18
|
-
) {}
|
|
19
|
-
|
|
20
|
-
// 快捷键扩展回调
|
|
21
|
-
hotkeyEvent(eventName: string, e: KeyboardEvent) {
|
|
22
|
-
if (e.type === 'keydown' && eventName === 'backspace') {
|
|
23
|
-
this.del();
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
del() {
|
|
28
|
-
const { canvas } = this;
|
|
29
|
-
const activeObject = canvas.getActiveObjects();
|
|
30
|
-
if (activeObject) {
|
|
31
|
-
activeObject.map((item) => canvas.remove(item));
|
|
32
|
-
canvas.requestRenderAll();
|
|
33
|
-
canvas.discardActiveObject();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
contextMenu() {
|
|
38
|
-
const activeObject = this.canvas.getActiveObject();
|
|
39
|
-
if (activeObject) {
|
|
40
|
-
return [
|
|
41
|
-
null,
|
|
42
|
-
{
|
|
43
|
-
text: '删除',
|
|
44
|
-
hotkey: 'Backspace',
|
|
45
|
-
disabled: false,
|
|
46
|
-
onclick: () => this.del(),
|
|
47
|
-
},
|
|
48
|
-
];
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
destroy() {
|
|
53
|
-
console.log('pluginDestroy');
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export default DeleteHotKeyPlugin;
|
|
1
|
+
import { fabric } from '@hprint/core';
|
|
2
|
+
import type { IEditor, IPluginTempl } from '@hprint/core';
|
|
3
|
+
|
|
4
|
+
type IPlugin = Pick<DeleteHotKeyPlugin, 'del'>;
|
|
5
|
+
|
|
6
|
+
declare module '@hprint/core' {
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
8
|
+
interface IEditor extends IPlugin {}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class DeleteHotKeyPlugin implements IPluginTempl {
|
|
12
|
+
static pluginName = 'DeleteHotKeyPlugin';
|
|
13
|
+
static apis = ['del'];
|
|
14
|
+
hotkeys: string[] = ['backspace'];
|
|
15
|
+
constructor(
|
|
16
|
+
public canvas: fabric.Canvas,
|
|
17
|
+
public editor: IEditor
|
|
18
|
+
) {}
|
|
19
|
+
|
|
20
|
+
// 快捷键扩展回调
|
|
21
|
+
hotkeyEvent(eventName: string, e: KeyboardEvent) {
|
|
22
|
+
if (e.type === 'keydown' && eventName === 'backspace') {
|
|
23
|
+
this.del();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
del() {
|
|
28
|
+
const { canvas } = this;
|
|
29
|
+
const activeObject = canvas.getActiveObjects();
|
|
30
|
+
if (activeObject) {
|
|
31
|
+
activeObject.map((item) => canvas.remove(item));
|
|
32
|
+
canvas.requestRenderAll();
|
|
33
|
+
canvas.discardActiveObject();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
contextMenu() {
|
|
38
|
+
const activeObject = this.canvas.getActiveObject();
|
|
39
|
+
if (activeObject) {
|
|
40
|
+
return [
|
|
41
|
+
null,
|
|
42
|
+
{
|
|
43
|
+
text: '删除',
|
|
44
|
+
hotkey: 'Backspace',
|
|
45
|
+
disabled: false,
|
|
46
|
+
onclick: () => this.del(),
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
destroy() {
|
|
53
|
+
console.log('pluginDestroy');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default DeleteHotKeyPlugin;
|