@hprint/plugins 0.0.1-alpha.0
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.css +1 -0
- package/dist/index.js +478 -0
- package/dist/index.mjs +41731 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/objects/Arrow.d.ts +2 -0
- package/dist/src/objects/Arrow.d.ts.map +1 -0
- package/dist/src/objects/ThinTailArrow.d.ts +2 -0
- package/dist/src/objects/ThinTailArrow.d.ts.map +1 -0
- package/dist/src/plugins/AddBaseTypePlugin.d.ts +26 -0
- package/dist/src/plugins/AddBaseTypePlugin.d.ts.map +1 -0
- package/dist/src/plugins/AlignGuidLinePlugin.d.ts +16 -0
- package/dist/src/plugins/AlignGuidLinePlugin.d.ts.map +1 -0
- package/dist/src/plugins/BarCodePlugin.d.ts +68 -0
- package/dist/src/plugins/BarCodePlugin.d.ts.map +1 -0
- package/dist/src/plugins/CenterAlignPlugin.d.ts +29 -0
- package/dist/src/plugins/CenterAlignPlugin.d.ts.map +1 -0
- package/dist/src/plugins/ControlsPlugin.d.ts +11 -0
- package/dist/src/plugins/ControlsPlugin.d.ts.map +1 -0
- package/dist/src/plugins/ControlsRotatePlugin.d.ts +11 -0
- package/dist/src/plugins/ControlsRotatePlugin.d.ts.map +1 -0
- package/dist/src/plugins/CopyPlugin.d.ts +30 -0
- package/dist/src/plugins/CopyPlugin.d.ts.map +1 -0
- package/dist/src/plugins/CreateElementPlugin.d.ts +121 -0
- package/dist/src/plugins/CreateElementPlugin.d.ts.map +1 -0
- package/dist/src/plugins/DeleteHotKeyPlugin.d.ts +25 -0
- package/dist/src/plugins/DeleteHotKeyPlugin.d.ts.map +1 -0
- package/dist/src/plugins/DrawLinePlugin.d.ts +26 -0
- package/dist/src/plugins/DrawLinePlugin.d.ts.map +1 -0
- package/dist/src/plugins/DrawPolygonPlugin.d.ts +41 -0
- package/dist/src/plugins/DrawPolygonPlugin.d.ts.map +1 -0
- package/dist/src/plugins/DringPlugin.d.ts +33 -0
- package/dist/src/plugins/DringPlugin.d.ts.map +1 -0
- package/dist/src/plugins/FlipPlugin.d.ts +26 -0
- package/dist/src/plugins/FlipPlugin.d.ts.map +1 -0
- package/dist/src/plugins/FontPlugin.d.ts +33 -0
- package/dist/src/plugins/FontPlugin.d.ts.map +1 -0
- package/dist/src/plugins/FreeDrawPlugin.d.ts +23 -0
- package/dist/src/plugins/FreeDrawPlugin.d.ts.map +1 -0
- package/dist/src/plugins/GroupAlignPlugin.d.ts +24 -0
- package/dist/src/plugins/GroupAlignPlugin.d.ts.map +1 -0
- package/dist/src/plugins/GroupPlugin.d.ts +24 -0
- package/dist/src/plugins/GroupPlugin.d.ts.map +1 -0
- package/dist/src/plugins/GroupTextEditorPlugin.d.ts +18 -0
- package/dist/src/plugins/GroupTextEditorPlugin.d.ts.map +1 -0
- package/dist/src/plugins/HistoryPlugin.d.ts +30 -0
- package/dist/src/plugins/HistoryPlugin.d.ts.map +1 -0
- package/dist/src/plugins/ImageStroke.d.ts +18 -0
- package/dist/src/plugins/ImageStroke.d.ts.map +1 -0
- package/dist/src/plugins/LayerPlugin.d.ts +31 -0
- package/dist/src/plugins/LayerPlugin.d.ts.map +1 -0
- package/dist/src/plugins/LockPlugin.d.ts +27 -0
- package/dist/src/plugins/LockPlugin.d.ts.map +1 -0
- package/dist/src/plugins/MaskPlugin.d.ts +38 -0
- package/dist/src/plugins/MaskPlugin.d.ts.map +1 -0
- package/dist/src/plugins/MaterialPlugin.d.ts +45 -0
- package/dist/src/plugins/MaterialPlugin.d.ts.map +1 -0
- package/dist/src/plugins/MiddleMousePlugin.d.ts +18 -0
- package/dist/src/plugins/MiddleMousePlugin.d.ts.map +1 -0
- package/dist/src/plugins/MoveHotKeyPlugin.d.ts +12 -0
- package/dist/src/plugins/MoveHotKeyPlugin.d.ts.map +1 -0
- package/dist/src/plugins/PathTextPlugin.d.ts +30 -0
- package/dist/src/plugins/PathTextPlugin.d.ts.map +1 -0
- package/dist/src/plugins/PolygonModifyPlugin.d.ts +28 -0
- package/dist/src/plugins/PolygonModifyPlugin.d.ts.map +1 -0
- package/dist/src/plugins/PrintPlugin.d.ts +39 -0
- package/dist/src/plugins/PrintPlugin.d.ts.map +1 -0
- package/dist/src/plugins/PsdPlugin.d.ts +17 -0
- package/dist/src/plugins/PsdPlugin.d.ts.map +1 -0
- package/dist/src/plugins/QrCodePlugin.d.ts +137 -0
- package/dist/src/plugins/QrCodePlugin.d.ts.map +1 -0
- package/dist/src/plugins/ResizePlugin.d.ts +44 -0
- package/dist/src/plugins/ResizePlugin.d.ts.map +1 -0
- package/dist/src/plugins/RulerPlugin.d.ts +24 -0
- package/dist/src/plugins/RulerPlugin.d.ts.map +1 -0
- package/dist/src/plugins/SimpleClipImagePlugin.d.ts +18 -0
- package/dist/src/plugins/SimpleClipImagePlugin.d.ts.map +1 -0
- package/dist/src/plugins/UnitPlugin.d.ts +84 -0
- package/dist/src/plugins/UnitPlugin.d.ts.map +1 -0
- package/dist/src/plugins/WaterMarkPlugin.d.ts +40 -0
- package/dist/src/plugins/WaterMarkPlugin.d.ts.map +1 -0
- package/dist/src/plugins/WorkspacePlugin.d.ts +57 -0
- package/dist/src/plugins/WorkspacePlugin.d.ts.map +1 -0
- package/dist/src/types/eventType.d.ts +11 -0
- package/dist/src/types/eventType.d.ts.map +1 -0
- package/dist/src/utils/psd.d.ts +3 -0
- package/dist/src/utils/psd.d.ts.map +1 -0
- package/dist/src/utils/ruler/guideline.d.ts +4 -0
- package/dist/src/utils/ruler/guideline.d.ts.map +1 -0
- package/dist/src/utils/ruler/index.d.ts +5 -0
- package/dist/src/utils/ruler/index.d.ts.map +1 -0
- package/dist/src/utils/ruler/ruler.d.ts +147 -0
- package/dist/src/utils/ruler/ruler.d.ts.map +1 -0
- package/dist/src/utils/ruler/utils.d.ts +50 -0
- package/dist/src/utils/ruler/utils.d.ts.map +1 -0
- package/dist/src/utils/units.d.ts +22 -0
- package/dist/src/utils/units.d.ts.map +1 -0
- package/package.json +51 -0
- package/src/assets/edgecontrol.svg +17 -0
- package/src/assets/lock.svg +7 -0
- package/src/assets/middlecontrol.svg +17 -0
- package/src/assets/middlecontrolhoz.svg +17 -0
- package/src/assets/rotateicon.svg +20 -0
- package/src/assets/style/resizePlugin.css +27 -0
- package/src/index.ts +121 -0
- package/src/objects/Arrow.js +47 -0
- package/src/objects/ThinTailArrow.js +50 -0
- package/src/plugins/AddBaseTypePlugin.ts +107 -0
- package/src/plugins/AlignGuidLinePlugin.ts +1141 -0
- package/src/plugins/BarCodePlugin.ts +860 -0
- package/src/plugins/CenterAlignPlugin.ts +133 -0
- package/src/plugins/ControlsPlugin.ts +251 -0
- package/src/plugins/ControlsRotatePlugin.ts +111 -0
- package/src/plugins/CopyPlugin.ts +255 -0
- package/src/plugins/CreateElementPlugin.ts +548 -0
- package/src/plugins/DeleteHotKeyPlugin.ts +57 -0
- package/src/plugins/DrawLinePlugin.ts +162 -0
- package/src/plugins/DrawPolygonPlugin.ts +205 -0
- package/src/plugins/DringPlugin.ts +125 -0
- package/src/plugins/FlipPlugin.ts +59 -0
- package/src/plugins/FontPlugin.ts +165 -0
- package/src/plugins/FreeDrawPlugin.ts +49 -0
- package/src/plugins/GroupAlignPlugin.ts +365 -0
- package/src/plugins/GroupPlugin.ts +82 -0
- package/src/plugins/GroupTextEditorPlugin.ts +198 -0
- package/src/plugins/HistoryPlugin.ts +181 -0
- package/src/plugins/ImageStroke.ts +121 -0
- package/src/plugins/LayerPlugin.ts +108 -0
- package/src/plugins/LockPlugin.ts +240 -0
- package/src/plugins/MaskPlugin.ts +155 -0
- package/src/plugins/MaterialPlugin.ts +224 -0
- package/src/plugins/MiddleMousePlugin.ts +45 -0
- package/src/plugins/MoveHotKeyPlugin.ts +46 -0
- package/src/plugins/PathTextPlugin.ts +89 -0
- package/src/plugins/PolygonModifyPlugin.ts +224 -0
- package/src/plugins/PrintPlugin.ts +81 -0
- package/src/plugins/PsdPlugin.ts +52 -0
- package/src/plugins/QrCodePlugin.ts +393 -0
- package/src/plugins/ResizePlugin.ts +274 -0
- package/src/plugins/RulerPlugin.ts +78 -0
- package/src/plugins/SimpleClipImagePlugin.ts +244 -0
- package/src/plugins/UnitPlugin.ts +327 -0
- package/src/plugins/WaterMarkPlugin.ts +257 -0
- package/src/plugins/WorkspacePlugin.ts +307 -0
- package/src/types/eventType.ts +11 -0
- package/src/utils/psd.js +432 -0
- package/src/utils/ruler/guideline.ts +145 -0
- package/src/utils/ruler/index.ts +91 -0
- package/src/utils/ruler/ruler.ts +924 -0
- package/src/utils/ruler/utils.ts +162 -0
- package/src/utils/units.ts +133 -0
- package/tsconfig.json +10 -0
- package/vite.config.ts +29 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
// 由于这个文件使用了较多其他插件的方法,所以这个插件应当最后加载
|
|
2
|
+
import { fabric } from '@hprint/core';
|
|
3
|
+
import type { IEditor, IPluginTempl } from '@hprint/core';
|
|
4
|
+
import { getUnit, convertSingle, processOptions, formatOriginValues } from '../utils/units';
|
|
5
|
+
|
|
6
|
+
type IPlugin = Pick<
|
|
7
|
+
CreateElementPlugin,
|
|
8
|
+
| 'createRect'
|
|
9
|
+
| 'createText'
|
|
10
|
+
| 'createIText'
|
|
11
|
+
| 'createLine'
|
|
12
|
+
| 'createEllipse'
|
|
13
|
+
| 'createPolygon'
|
|
14
|
+
| 'createImageFromURL'
|
|
15
|
+
| 'createImage'
|
|
16
|
+
| 'createBarcode'
|
|
17
|
+
| 'createQrcode'
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
declare module '@hprint/core' {
|
|
21
|
+
interface IEditor extends IPlugin { }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class CreateElementPlugin implements IPluginTempl {
|
|
25
|
+
static pluginName = 'CreateElementPlugin';
|
|
26
|
+
static apis = [
|
|
27
|
+
'createRect',
|
|
28
|
+
'createText',
|
|
29
|
+
'createLine',
|
|
30
|
+
'createIText',
|
|
31
|
+
'createEllipse',
|
|
32
|
+
'createPolygon',
|
|
33
|
+
'createImageFromURL',
|
|
34
|
+
'createImage',
|
|
35
|
+
'createBarcode',
|
|
36
|
+
'createQrcode',
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
static lengthFieldConfigs: Array<{ field: string; dealMethod: 'single' | 'points' }> = [
|
|
40
|
+
{ field: 'left', dealMethod: 'single' },
|
|
41
|
+
{ field: 'top', dealMethod: 'single' },
|
|
42
|
+
{ field: 'width', dealMethod: 'single' },
|
|
43
|
+
{ field: 'height', dealMethod: 'single' },
|
|
44
|
+
{ field: 'fontSize', dealMethod: 'single' },
|
|
45
|
+
{ field: 'strokeWidth', dealMethod: 'single' },
|
|
46
|
+
{ field: 'rx', dealMethod: 'single' },
|
|
47
|
+
{ field: 'ry', dealMethod: 'single' },
|
|
48
|
+
{ field: 'boxWidth', dealMethod: 'single' },
|
|
49
|
+
{ field: 'points', dealMethod: 'points' },
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
public canvas: fabric.Canvas,
|
|
54
|
+
public editor: IEditor
|
|
55
|
+
) { }
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
private _processPoints(points: Array<{ x: number; y: number }>, dpi?: number): { processed: Array<{ x: number; y: number }>; originByUnit: Record<string, Record<string, any>> } {
|
|
60
|
+
const hasCfg = CreateElementPlugin.lengthFieldConfigs.some(
|
|
61
|
+
(c) => c.field === 'points' && c.dealMethod === 'points'
|
|
62
|
+
);
|
|
63
|
+
const unit = getUnit(this.editor);
|
|
64
|
+
if (!hasCfg) {
|
|
65
|
+
return { processed: points, originByUnit: { [unit]: {} } };
|
|
66
|
+
}
|
|
67
|
+
const processed = points.map((p) => ({ x: convertSingle(p.x, unit, dpi), y: convertSingle(p.y, unit, dpi) }));
|
|
68
|
+
const originUnit = { points } as Record<string, any>;
|
|
69
|
+
return { processed, originByUnit: { [unit]: originUnit } };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 覆盖指定对象实例的 set 方法,仅在本插件创建的元素上生效
|
|
74
|
+
*/
|
|
75
|
+
private addSetAndSyncByUnit(obj: fabric.Object) {
|
|
76
|
+
const originalSet = obj.set.bind(obj);
|
|
77
|
+
const editorRef = this.editor;
|
|
78
|
+
const singleFields = CreateElementPlugin.lengthFieldConfigs
|
|
79
|
+
.filter((c) => c.dealMethod === 'single')
|
|
80
|
+
.map((c) => c.field);
|
|
81
|
+
const hasPointsField = CreateElementPlugin.lengthFieldConfigs.some(
|
|
82
|
+
(c) => c.field === 'points' && c.dealMethod === 'points'
|
|
83
|
+
);
|
|
84
|
+
const mergeOrigin = (target: any, unit: string, origin: Record<string, any>) => {
|
|
85
|
+
const prev = target._originSize || {};
|
|
86
|
+
const precision = (editorRef as any).getPrecision?.();
|
|
87
|
+
const formatted = formatOriginValues(origin, precision);
|
|
88
|
+
const mergedUnit = { ...(prev[unit] || {}), ...formatted };
|
|
89
|
+
target._originSize = { ...prev, [unit]: mergedUnit };
|
|
90
|
+
};
|
|
91
|
+
(obj as any).setByUnit = function (key: any, value?: any) {
|
|
92
|
+
const unit = getUnit(editorRef);
|
|
93
|
+
const dpi = 96;
|
|
94
|
+
const isTransforming = !!(this.canvas && (this.canvas as any)._currentTransform);
|
|
95
|
+
if (typeof key === 'string') {
|
|
96
|
+
const field = key as keyof fabric.Object;
|
|
97
|
+
if (singleFields.includes(field)) {
|
|
98
|
+
if (isTransforming) {
|
|
99
|
+
return originalSet(field, value);
|
|
100
|
+
}
|
|
101
|
+
if (value !== undefined) {
|
|
102
|
+
const processedVal = convertSingle(value, unit, dpi);
|
|
103
|
+
mergeOrigin(this, unit, { [field]: value });
|
|
104
|
+
return originalSet(field, processedVal);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (field === 'points' && hasPointsField && Array.isArray(value)) {
|
|
108
|
+
if (isTransforming) {
|
|
109
|
+
return originalSet(field, value);
|
|
110
|
+
}
|
|
111
|
+
const pts = (value as Array<{ x: number; y: number }>).map((p) => ({
|
|
112
|
+
x: convertSingle(p.x, unit, dpi),
|
|
113
|
+
y: convertSingle(p.y, unit, dpi),
|
|
114
|
+
}));
|
|
115
|
+
mergeOrigin(this, unit, { points: value });
|
|
116
|
+
return originalSet(field, pts);
|
|
117
|
+
}
|
|
118
|
+
return originalSet(key, value);
|
|
119
|
+
}
|
|
120
|
+
if (key && typeof key === 'object') {
|
|
121
|
+
const opts = { ...key } as Record<string, any>;
|
|
122
|
+
if (hasPointsField && Array.isArray(opts.points)) {
|
|
123
|
+
if (isTransforming) {
|
|
124
|
+
return originalSet(opts);
|
|
125
|
+
}
|
|
126
|
+
const pts = (opts.points as Array<{ x: number; y: number }>).map((p) => ({
|
|
127
|
+
x: convertSingle(p.x, unit, dpi),
|
|
128
|
+
y: convertSingle(p.y, unit, dpi),
|
|
129
|
+
}));
|
|
130
|
+
mergeOrigin(this, unit, { points: opts.points });
|
|
131
|
+
opts.points = pts;
|
|
132
|
+
}
|
|
133
|
+
if (isTransforming) {
|
|
134
|
+
return originalSet(opts);
|
|
135
|
+
}
|
|
136
|
+
const { processed, originByUnit } = processOptions(opts, unit, dpi, singleFields);
|
|
137
|
+
const originUnit = originByUnit[unit] || {};
|
|
138
|
+
if (Object.keys(originUnit).length) mergeOrigin(this, unit, originUnit);
|
|
139
|
+
return originalSet({ ...opts, ...processed });
|
|
140
|
+
}
|
|
141
|
+
return originalSet(key, value);
|
|
142
|
+
};
|
|
143
|
+
(obj as any).syncOriginSizeByUnit = function (fieldsOrDpi?: any, dpi?: number) {
|
|
144
|
+
const unit = getUnit(editorRef);
|
|
145
|
+
if (unit === 'px') return;
|
|
146
|
+
const hasFieldsArray = Array.isArray(fieldsOrDpi);
|
|
147
|
+
const dpiVal = hasFieldsArray ? (dpi ?? 96) : (fieldsOrDpi ?? 96);
|
|
148
|
+
const ratio = convertSingle(1, unit, dpiVal) || 1;
|
|
149
|
+
const origin: Record<string, any> = {};
|
|
150
|
+
const targetFields: string[] =
|
|
151
|
+
hasFieldsArray && (fieldsOrDpi as string[])?.length ? (fieldsOrDpi as string[]) : singleFields;
|
|
152
|
+
targetFields.forEach((field) => {
|
|
153
|
+
if (field === 'points') return;
|
|
154
|
+
const isImage = (this as any).type === 'image';
|
|
155
|
+
let valPx: number | undefined;
|
|
156
|
+
if (isImage && (field === 'width' || field === 'height')) {
|
|
157
|
+
const base = field === 'width' ? (this as any).width : (this as any).height;
|
|
158
|
+
const scale = field === 'width' ? ((this as any).scaleX ?? 1) : ((this as any).scaleY ?? 1);
|
|
159
|
+
if (typeof base === 'number' && !isNaN(base)) {
|
|
160
|
+
valPx = base * scale;
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
const currentVal = (this as any).get ? (this as any).get(field) : (this as any)[field];
|
|
164
|
+
if (typeof currentVal === 'number' && !isNaN(currentVal)) {
|
|
165
|
+
valPx = currentVal;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (typeof valPx === 'number' && !isNaN(valPx)) {
|
|
169
|
+
origin[field] = editorRef.getSizeByUnit(valPx);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const shouldSyncPoints =
|
|
173
|
+
hasPointsField &&
|
|
174
|
+
Array.isArray((this as any).points) &&
|
|
175
|
+
((hasFieldsArray && (fieldsOrDpi as string[]).includes('points')) || !hasFieldsArray);
|
|
176
|
+
if (shouldSyncPoints) {
|
|
177
|
+
const pts = ((this as any).points as Array<{ x: number; y: number }>).map((p) => ({
|
|
178
|
+
x: p.x / ratio,
|
|
179
|
+
y: p.y / ratio,
|
|
180
|
+
}));
|
|
181
|
+
origin.points = pts;
|
|
182
|
+
}
|
|
183
|
+
if (Object.keys(origin).length) {
|
|
184
|
+
mergeOrigin(this, unit, origin);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
createRect(
|
|
190
|
+
opts: {
|
|
191
|
+
left?: number;
|
|
192
|
+
top?: number;
|
|
193
|
+
width?: number;
|
|
194
|
+
height?: number;
|
|
195
|
+
strokeWidth?: number;
|
|
196
|
+
fill?: string;
|
|
197
|
+
},
|
|
198
|
+
dpi?: number
|
|
199
|
+
): fabric.Rect {
|
|
200
|
+
const unit = getUnit(this.editor);
|
|
201
|
+
const singleFields = CreateElementPlugin.lengthFieldConfigs.filter((c) => c.dealMethod === 'single').map((c) => c.field);
|
|
202
|
+
const { processed, originByUnit } = processOptions(opts, unit, dpi, singleFields);
|
|
203
|
+
const precision = (this.editor as any).getPrecision?.();
|
|
204
|
+
const formattedOrigin = { [unit]: formatOriginValues(originByUnit[unit] || {}, precision) };
|
|
205
|
+
const rect = new fabric.Rect({ ...opts, ...processed });
|
|
206
|
+
(rect as any)._originSize = formattedOrigin;
|
|
207
|
+
this.addSetAndSyncByUnit(rect);
|
|
208
|
+
return rect;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
createText(
|
|
212
|
+
text: string,
|
|
213
|
+
opts: {
|
|
214
|
+
left?: number;
|
|
215
|
+
top?: number;
|
|
216
|
+
width?: number;
|
|
217
|
+
height?: number;
|
|
218
|
+
fontSize?: number;
|
|
219
|
+
strokeWidth?: number;
|
|
220
|
+
fill?: string;
|
|
221
|
+
fontFamily?: string;
|
|
222
|
+
splitByGrapheme?: boolean;
|
|
223
|
+
},
|
|
224
|
+
dpi?: number
|
|
225
|
+
): fabric.Textbox {
|
|
226
|
+
const unit = getUnit(this.editor);
|
|
227
|
+
const singleFields = CreateElementPlugin.lengthFieldConfigs.filter((c) => c.dealMethod === 'single').map((c) => c.field);
|
|
228
|
+
const { processed, originByUnit } = processOptions(opts, unit, dpi, singleFields);
|
|
229
|
+
const precision = (this.editor as any).getPrecision?.();
|
|
230
|
+
const formattedOrigin = { [unit]: formatOriginValues(originByUnit[unit] || {}, precision) };
|
|
231
|
+
const tb = new fabric.Textbox(text, { ...opts, ...processed });
|
|
232
|
+
(tb as any)._originSize = formattedOrigin;
|
|
233
|
+
this.addSetAndSyncByUnit(tb);
|
|
234
|
+
return tb;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
createIText(
|
|
238
|
+
text: string,
|
|
239
|
+
opts: {
|
|
240
|
+
left?: number;
|
|
241
|
+
top?: number;
|
|
242
|
+
width?: number;
|
|
243
|
+
height?: number;
|
|
244
|
+
fontSize?: number;
|
|
245
|
+
strokeWidth?: number;
|
|
246
|
+
fill?: string;
|
|
247
|
+
fontFamily?: string;
|
|
248
|
+
},
|
|
249
|
+
dpi?: number
|
|
250
|
+
): fabric.IText {
|
|
251
|
+
const unit = getUnit(this.editor);
|
|
252
|
+
const singleFields = CreateElementPlugin.lengthFieldConfigs.filter((c) => c.dealMethod === 'single').map((c) => c.field);
|
|
253
|
+
const { processed, originByUnit } = processOptions(opts, unit, dpi, singleFields);
|
|
254
|
+
const precision = (this.editor as any).getPrecision?.();
|
|
255
|
+
const formattedOrigin = { [unit]: formatOriginValues(originByUnit[unit] || {}, precision) };
|
|
256
|
+
const tb = new fabric.IText(text, { ...opts, ...processed });
|
|
257
|
+
(tb as any)._originSize = formattedOrigin;
|
|
258
|
+
this.addSetAndSyncByUnit(tb);
|
|
259
|
+
return tb;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
createLine(
|
|
263
|
+
points: Array<{ x: number; y: number }>,
|
|
264
|
+
opts?: { strokeWidth?: number; stroke?: string },
|
|
265
|
+
dpi?: number
|
|
266
|
+
): fabric.Line {
|
|
267
|
+
const unit = getUnit(this.editor);
|
|
268
|
+
const { processed: pts, originByUnit: originPoints } = this._processPoints(
|
|
269
|
+
points,
|
|
270
|
+
dpi
|
|
271
|
+
);
|
|
272
|
+
const singleFields = CreateElementPlugin.lengthFieldConfigs.filter((c) => c.dealMethod === 'single').map((c) => c.field);
|
|
273
|
+
const { processed: optProcessed, originByUnit: originOpts } =
|
|
274
|
+
processOptions(opts || {}, unit, dpi, singleFields);
|
|
275
|
+
|
|
276
|
+
const line = new fabric.Line(
|
|
277
|
+
[pts[0].x, pts[0].y, pts[1].x, pts[1].y],
|
|
278
|
+
{
|
|
279
|
+
...opts,
|
|
280
|
+
strokeWidth:
|
|
281
|
+
optProcessed.strokeWidth !== undefined
|
|
282
|
+
? optProcessed.strokeWidth
|
|
283
|
+
: undefined,
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
const precision = (this.editor as any).getPrecision?.();
|
|
288
|
+
const mergedOrigin = {
|
|
289
|
+
[unit]: {
|
|
290
|
+
...formatOriginValues(originOpts[unit] || {}, precision),
|
|
291
|
+
...formatOriginValues(originPoints[unit] || {}, precision),
|
|
292
|
+
},
|
|
293
|
+
} as Record<string, any>;
|
|
294
|
+
(line as any)._originSize = mergedOrigin;
|
|
295
|
+
this.addSetAndSyncByUnit(line);
|
|
296
|
+
return line;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
createEllipse(
|
|
300
|
+
opts: {
|
|
301
|
+
left?: number;
|
|
302
|
+
top?: number;
|
|
303
|
+
rx?: number;
|
|
304
|
+
ry?: number;
|
|
305
|
+
fill?: string;
|
|
306
|
+
strokeWidth?: number;
|
|
307
|
+
},
|
|
308
|
+
dpi?: number
|
|
309
|
+
): fabric.Ellipse {
|
|
310
|
+
const unit = getUnit(this.editor);
|
|
311
|
+
const singleFields = CreateElementPlugin.lengthFieldConfigs.filter((c) => c.dealMethod === 'single').map((c) => c.field);
|
|
312
|
+
const { processed, originByUnit } = processOptions(opts, unit, dpi, singleFields);
|
|
313
|
+
const precision = (this.editor as any).getPrecision?.();
|
|
314
|
+
const formattedOrigin = { [unit]: formatOriginValues(originByUnit[unit] || {}, precision) };
|
|
315
|
+
const ell = new fabric.Ellipse({ ...opts, ...processed });
|
|
316
|
+
(ell as any)._originSize = formattedOrigin;
|
|
317
|
+
this.addSetAndSyncByUnit(ell);
|
|
318
|
+
return ell;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
createPolygon(
|
|
322
|
+
points: Array<{ x: number; y: number }>,
|
|
323
|
+
opts?: { fill?: string; strokeWidth?: number },
|
|
324
|
+
dpi?: number
|
|
325
|
+
): fabric.Polygon {
|
|
326
|
+
const unit = getUnit(this.editor);
|
|
327
|
+
const { processed: pts, originByUnit: originPoints } = this._processPoints(points, dpi);
|
|
328
|
+
const singleFields = CreateElementPlugin.lengthFieldConfigs.filter((c) => c.dealMethod === 'single').map((c) => c.field);
|
|
329
|
+
const { processed: optProcessed, originByUnit: originOpts } = processOptions(opts || {}, unit, dpi, singleFields);
|
|
330
|
+
const poly = new fabric.Polygon(pts, {
|
|
331
|
+
fill: opts?.fill,
|
|
332
|
+
});
|
|
333
|
+
if (opts?.strokeWidth !== undefined) {
|
|
334
|
+
const sw = convertSingle(opts.strokeWidth, unit, dpi);
|
|
335
|
+
poly.set('strokeWidth', sw!);
|
|
336
|
+
}
|
|
337
|
+
poly.set({ ...(opts || {}), ...optProcessed });
|
|
338
|
+
const precision = (this.editor as any).getPrecision?.();
|
|
339
|
+
const mergedOrigin = {
|
|
340
|
+
[unit]: {
|
|
341
|
+
...formatOriginValues(originOpts[unit] || {}, precision),
|
|
342
|
+
...formatOriginValues(originPoints[unit] || {}, precision),
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
(poly as any)._originSize = mergedOrigin;
|
|
346
|
+
this.addSetAndSyncByUnit(poly);
|
|
347
|
+
return poly;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
async createImageFromURL(
|
|
351
|
+
url: string,
|
|
352
|
+
opts?: {
|
|
353
|
+
left?: number;
|
|
354
|
+
top?: number;
|
|
355
|
+
width?: number;
|
|
356
|
+
height?: number;
|
|
357
|
+
},
|
|
358
|
+
dpi?: number
|
|
359
|
+
): Promise<fabric.Image> {
|
|
360
|
+
return new Promise((resolve) => {
|
|
361
|
+
fabric.Image.fromURL(
|
|
362
|
+
url,
|
|
363
|
+
(img) => {
|
|
364
|
+
const unit = getUnit(this.editor);
|
|
365
|
+
const precision = (this.editor as any).getPrecision?.();
|
|
366
|
+
this.addSetAndSyncByUnit(img);
|
|
367
|
+
(img as any).off?.('scaled');
|
|
368
|
+
(img as any).off?.('modified');
|
|
369
|
+
(img as any).on?.('scaled', () => {
|
|
370
|
+
(img as any).syncOriginSizeByUnit?.(['width', 'height']);
|
|
371
|
+
});
|
|
372
|
+
(img as any).on?.('modified', () => {
|
|
373
|
+
(img as any).syncOriginSizeByUnit?.(['width', 'height']);
|
|
374
|
+
});
|
|
375
|
+
if (opts) {
|
|
376
|
+
const singleFields = CreateElementPlugin.lengthFieldConfigs.filter((c) => c.dealMethod === 'single').map((c) => c.field);
|
|
377
|
+
const { originByUnit } = processOptions(opts, unit, dpi, singleFields);
|
|
378
|
+
img.set({ ...opts });
|
|
379
|
+
const formattedOrigin = { [unit]: formatOriginValues(originByUnit[unit] || {}, precision) };
|
|
380
|
+
(img as any)._originSize = formattedOrigin;
|
|
381
|
+
}
|
|
382
|
+
const noWidth = !opts?.width;
|
|
383
|
+
const noHeight = !opts?.height;
|
|
384
|
+
if (noWidth && noHeight) {
|
|
385
|
+
const workspace = (this.editor as any).getWorkspase?.();
|
|
386
|
+
const workspaceWidth = workspace?.width ?? this.canvas.getWidth() ?? img.width ?? 0;
|
|
387
|
+
const naturalWidth = img.width ?? 0;
|
|
388
|
+
const naturalHeight = img.height ?? 0;
|
|
389
|
+
const targetWidthPx = workspaceWidth / 2;
|
|
390
|
+
const scale = naturalWidth > 0 ? targetWidthPx / naturalWidth : 1;
|
|
391
|
+
img.set({ scaleX: scale, scaleY: scale });
|
|
392
|
+
const originVals = {
|
|
393
|
+
width: (this.editor as any).getSizeByUnit?.(targetWidthPx),
|
|
394
|
+
height: (this.editor as any).getSizeByUnit?.(naturalHeight * scale),
|
|
395
|
+
};
|
|
396
|
+
const formatted = { [unit]: formatOriginValues(originVals, precision) };
|
|
397
|
+
(img as any)._originSize = formatted;
|
|
398
|
+
}
|
|
399
|
+
resolve(img);
|
|
400
|
+
},
|
|
401
|
+
{ crossOrigin: 'anonymous' }
|
|
402
|
+
);
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
async createImage(
|
|
407
|
+
source: string | File,
|
|
408
|
+
opts?: {
|
|
409
|
+
left?: number;
|
|
410
|
+
top?: number;
|
|
411
|
+
width?: number;
|
|
412
|
+
height?: number;
|
|
413
|
+
},
|
|
414
|
+
dpi?: number
|
|
415
|
+
): Promise<fabric.Image> {
|
|
416
|
+
return new Promise((resolve) => {
|
|
417
|
+
let url: string;
|
|
418
|
+
let shouldRevoke = false;
|
|
419
|
+
if (typeof source === 'string') {
|
|
420
|
+
const trimmed = source.trim();
|
|
421
|
+
if (trimmed.startsWith('data:')) {
|
|
422
|
+
url = trimmed;
|
|
423
|
+
} else {
|
|
424
|
+
url = 'data:image/png;base64,' + trimmed;
|
|
425
|
+
}
|
|
426
|
+
} else {
|
|
427
|
+
const objectUrl = URL.createObjectURL(source);
|
|
428
|
+
url = objectUrl;
|
|
429
|
+
shouldRevoke = true;
|
|
430
|
+
}
|
|
431
|
+
const fromUrlOptions: Record<string, any> | undefined =
|
|
432
|
+
typeof source === 'string' ? { crossOrigin: 'anonymous' } : undefined;
|
|
433
|
+
fabric.Image.fromURL(
|
|
434
|
+
url,
|
|
435
|
+
(img) => {
|
|
436
|
+
const unit = getUnit(this.editor);
|
|
437
|
+
const precision = (this.editor as any).getPrecision?.();
|
|
438
|
+
this.addSetAndSyncByUnit(img);
|
|
439
|
+
(img as any).off?.('scaled');
|
|
440
|
+
(img as any).off?.('modified');
|
|
441
|
+
(img as any).on?.('scaled', () => {
|
|
442
|
+
(img as any).syncOriginSizeByUnit?.(['width', 'height']);
|
|
443
|
+
});
|
|
444
|
+
(img as any).on?.('modified', () => {
|
|
445
|
+
(img as any).syncOriginSizeByUnit?.(['width', 'height']);
|
|
446
|
+
});
|
|
447
|
+
if (opts) {
|
|
448
|
+
const singleFields = CreateElementPlugin.lengthFieldConfigs
|
|
449
|
+
.filter((c) => c.dealMethod === 'single')
|
|
450
|
+
.map((c) => c.field);
|
|
451
|
+
const { originByUnit } = processOptions(opts, unit, dpi, singleFields);
|
|
452
|
+
img.set({ ...opts });
|
|
453
|
+
const formattedOrigin = {
|
|
454
|
+
[unit]: formatOriginValues(originByUnit[unit] || {}, precision),
|
|
455
|
+
};
|
|
456
|
+
(img as any)._originSize = formattedOrigin;
|
|
457
|
+
}
|
|
458
|
+
const noWidth = !opts?.width;
|
|
459
|
+
const noHeight = !opts?.height;
|
|
460
|
+
if (noWidth && noHeight) {
|
|
461
|
+
const workspace = (this.editor as any).getWorkspase?.();
|
|
462
|
+
const workspaceWidth = workspace?.width ?? this.canvas.getWidth() ?? img.width ?? 0;
|
|
463
|
+
const naturalWidth = img.width ?? 0;
|
|
464
|
+
const naturalHeight = img.height ?? 0;
|
|
465
|
+
const targetWidthPx = workspaceWidth / 2;
|
|
466
|
+
const scale = naturalWidth > 0 ? targetWidthPx / naturalWidth : 1;
|
|
467
|
+
img.set({ scaleX: scale, scaleY: scale });
|
|
468
|
+
const originVals = {
|
|
469
|
+
width: (this.editor as any).getSizeByUnit?.(targetWidthPx),
|
|
470
|
+
height: (this.editor as any).getSizeByUnit?.(naturalHeight * scale),
|
|
471
|
+
};
|
|
472
|
+
const formatted = { [unit]: formatOriginValues(originVals, precision) };
|
|
473
|
+
(img as any)._originSize = formatted;
|
|
474
|
+
}
|
|
475
|
+
if (shouldRevoke) {
|
|
476
|
+
try {
|
|
477
|
+
URL.revokeObjectURL(url);
|
|
478
|
+
} catch (e) {
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
resolve(img);
|
|
482
|
+
},
|
|
483
|
+
fromUrlOptions
|
|
484
|
+
);
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
async createBarcode(
|
|
489
|
+
barcodeValue: string,
|
|
490
|
+
opts?: {
|
|
491
|
+
left?: number;
|
|
492
|
+
top?: number;
|
|
493
|
+
height?: number;
|
|
494
|
+
boxWidth?: number;
|
|
495
|
+
fontSize?: number;
|
|
496
|
+
format?: string;
|
|
497
|
+
textAlign?: string;
|
|
498
|
+
textPosition?: string;
|
|
499
|
+
background?: string;
|
|
500
|
+
lineColor?: string;
|
|
501
|
+
displayValue?: boolean;
|
|
502
|
+
margin?: number;
|
|
503
|
+
width?: number;
|
|
504
|
+
},
|
|
505
|
+
dpi?: number
|
|
506
|
+
): Promise<fabric.Image> {
|
|
507
|
+
const img = await (this.editor as any).addBarcode?.(barcodeValue, opts, dpi);
|
|
508
|
+
if (img) {
|
|
509
|
+
this.addSetAndSyncByUnit(img);
|
|
510
|
+
}
|
|
511
|
+
return img;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* 创建二维码元素,委托调用编辑器的 addQrCode,并支持单位转换与原始尺寸存储
|
|
516
|
+
*/
|
|
517
|
+
async createQrcode(
|
|
518
|
+
codeValue: string,
|
|
519
|
+
opts?: {
|
|
520
|
+
left?: number;
|
|
521
|
+
top?: number;
|
|
522
|
+
width?: number;
|
|
523
|
+
height?: number;
|
|
524
|
+
margin?: number;
|
|
525
|
+
errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
|
|
526
|
+
dotsColor?: string;
|
|
527
|
+
dotsType?: string;
|
|
528
|
+
cornersSquareColor?: string;
|
|
529
|
+
cornersSquareType?: string;
|
|
530
|
+
cornersDotColor?: string;
|
|
531
|
+
cornersDotType?: string;
|
|
532
|
+
background?: string;
|
|
533
|
+
},
|
|
534
|
+
dpi?: number
|
|
535
|
+
): Promise<fabric.Image> {
|
|
536
|
+
const img = await (this.editor as any).addQrCode?.(codeValue, opts, dpi);
|
|
537
|
+
if (img) {
|
|
538
|
+
this.addSetAndSyncByUnit(img);
|
|
539
|
+
}
|
|
540
|
+
return img;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
destroy() {
|
|
544
|
+
console.log('pluginDestroy');
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
export default CreateElementPlugin;
|
|
@@ -0,0 +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;
|