@hprint/plugins 0.0.2 → 0.0.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/package.json +3 -3
- package/src/plugins/AlignGuidLinePlugin.ts +1152 -1152
- package/src/plugins/GroupAlignPlugin.ts +365 -365
- package/src/plugins/LockPlugin.ts +242 -242
- package/src/plugins/ResizePlugin.ts +278 -278
- package/src/plugins/RulerPlugin.ts +78 -78
- package/src/plugins/UnitPlugin.ts +348 -348
- package/src/plugins/WaterMarkPlugin.ts +257 -257
- package/src/utils/ruler/ruler.ts +936 -936
|
@@ -1,348 +1,348 @@
|
|
|
1
|
-
import type { IEditor, IPluginTempl } from '@hprint/core';
|
|
2
|
-
import { LengthConvert } from '@hprint/shared';
|
|
3
|
-
import { syncMmFromObject } from '../utils/units';
|
|
4
|
-
import { fabric } from '@hprint/core';
|
|
5
|
-
import { throttle } from 'lodash-es';
|
|
6
|
-
|
|
7
|
-
type IPlugin = Pick<
|
|
8
|
-
UnitPlugin,
|
|
9
|
-
| 'getUnit'
|
|
10
|
-
| 'setUnit'
|
|
11
|
-
| 'getSizeByUnit'
|
|
12
|
-
| 'setSizeByUnit'
|
|
13
|
-
| 'getOriginSize'
|
|
14
|
-
| 'syncOriginSizeByUnit'
|
|
15
|
-
| 'applyObjectPx'
|
|
16
|
-
| 'applyObjectMm'
|
|
17
|
-
| 'applyObjectInch'
|
|
18
|
-
| 'applyObjectByUnit'
|
|
19
|
-
>;
|
|
20
|
-
|
|
21
|
-
type TUnit = 'px' | 'mm' | 'inch';
|
|
22
|
-
|
|
23
|
-
declare module '@hprint/core' {
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
25
|
-
interface IEditor extends IPlugin { }
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
class UnitPlugin implements IPluginTempl {
|
|
29
|
-
static pluginName = 'UnitPlugin';
|
|
30
|
-
// static events = ['sizeChange'];
|
|
31
|
-
static apis = [
|
|
32
|
-
'getUnit',
|
|
33
|
-
'setUnit',
|
|
34
|
-
'getSizeByUnit',
|
|
35
|
-
'setSizeByUnit',
|
|
36
|
-
'getOriginSize',
|
|
37
|
-
'getPrecision',
|
|
38
|
-
'syncOriginSizeByUnit',
|
|
39
|
-
'applyObjectPx',
|
|
40
|
-
'applyObjectMm',
|
|
41
|
-
'applyObjectInch',
|
|
42
|
-
'applyObjectByUnit',
|
|
43
|
-
];
|
|
44
|
-
unit: TUnit = 'px';
|
|
45
|
-
precision?: number;
|
|
46
|
-
_originSize: Record<string, { width: number, height: number }> = { mm: { width: 0, height: 0 } };
|
|
47
|
-
constructor(
|
|
48
|
-
public canvas: fabric.Canvas,
|
|
49
|
-
public editor: IEditor,
|
|
50
|
-
options?: {
|
|
51
|
-
unit?: TUnit;
|
|
52
|
-
precision?: number;
|
|
53
|
-
}
|
|
54
|
-
) {
|
|
55
|
-
this.init(options);
|
|
56
|
-
this._bindEvents();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
hookSaveBefore() {
|
|
60
|
-
return new Promise((resolve) => {
|
|
61
|
-
resolve(true);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
hookSaveAfter() {
|
|
66
|
-
return new Promise((resolve) => {
|
|
67
|
-
resolve(true);
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
init(options?: { unit?: TUnit; precision?: number }) {
|
|
72
|
-
if (options?.unit) this.unit = options?.unit;
|
|
73
|
-
if (options?.precision) this.precision = options?.precision;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
setUnit(unit: TUnit) {
|
|
77
|
-
if (this.unit === unit) return;
|
|
78
|
-
this.unit = unit;
|
|
79
|
-
this.editor.emit('unitChange', unit);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
getUnit() {
|
|
83
|
-
return this.unit;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
getPrecision() {
|
|
87
|
-
return this.precision;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
getSizeByUnit(pxValue: number, unit?: TUnit, dpi?: number) {
|
|
91
|
-
const targetUnit = unit ?? this.editor.getUnit();
|
|
92
|
-
if (targetUnit === 'px') return pxValue;
|
|
93
|
-
if (targetUnit === 'mm') return LengthConvert.pxToMm(pxValue, dpi, { direct: true });
|
|
94
|
-
if (targetUnit === 'inch') {
|
|
95
|
-
const mm = LengthConvert.pxToMm(pxValue, dpi, { direct: true });
|
|
96
|
-
return mm / LengthConvert.CONSTANTS.INCH_TO_MM;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
_toPrecisionValue(value: number) {
|
|
101
|
-
if (this.precision === undefined) return value;
|
|
102
|
-
const factor = Math.pow(10, this.precision);
|
|
103
|
-
return Math.round(value * factor) / factor;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
_formatOriginUnitValues<T extends { [k: string]: number | undefined }>(
|
|
107
|
-
vals: T,
|
|
108
|
-
obj?: fabric.Object,
|
|
109
|
-
unit?: 'mm' | 'inch'
|
|
110
|
-
): T {
|
|
111
|
-
const result: Record<string, number | undefined> = {};
|
|
112
|
-
for (const key in vals) {
|
|
113
|
-
const v = vals[key];
|
|
114
|
-
result[key] = v === undefined ? undefined : this._toPrecisionValue(v);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Preserve ALL existing fields from _originSize[unit] to prevent data loss
|
|
118
|
-
if (obj && unit) {
|
|
119
|
-
const existingUnit = (obj as any)._originSize?.[unit] || {};
|
|
120
|
-
// Merge existing fields with new values, new values take precedence
|
|
121
|
-
Object.keys(existingUnit).forEach((key) => {
|
|
122
|
-
if (!(key in result)) {
|
|
123
|
-
result[key] = existingUnit[key];
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return result as T;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
applyObjectPx(
|
|
132
|
-
obj: fabric.Object,
|
|
133
|
-
opts: {
|
|
134
|
-
left?: number;
|
|
135
|
-
top?: number;
|
|
136
|
-
width?: number;
|
|
137
|
-
height?: number;
|
|
138
|
-
strokeWidth?: number;
|
|
139
|
-
fontSize?: number;
|
|
140
|
-
}
|
|
141
|
-
) {
|
|
142
|
-
const { left, top, width, height, strokeWidth, fontSize } = opts;
|
|
143
|
-
// fontSize必须在width之前,否则可能宽度设置不正确
|
|
144
|
-
if (fontSize !== undefined) obj.set('fontSize', fontSize);
|
|
145
|
-
if (strokeWidth !== undefined) obj.set('strokeWidth', strokeWidth);
|
|
146
|
-
if (width !== undefined) obj.set('width', width);
|
|
147
|
-
if (height !== undefined) obj.set('height', height);
|
|
148
|
-
if (left !== undefined) obj.set('left', left);
|
|
149
|
-
if (top !== undefined) obj.set('top', top);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
applyObjectMm(
|
|
153
|
-
obj: fabric.Object,
|
|
154
|
-
mm: {
|
|
155
|
-
left?: number;
|
|
156
|
-
top?: number;
|
|
157
|
-
width?: number;
|
|
158
|
-
height?: number;
|
|
159
|
-
strokeWidth?: number;
|
|
160
|
-
fontSize?: number;
|
|
161
|
-
},
|
|
162
|
-
dpi?: number
|
|
163
|
-
) {
|
|
164
|
-
const toPx = (v: number | undefined) =>
|
|
165
|
-
v === undefined ? undefined : LengthConvert.mmToPx(v, dpi, { direct: true });
|
|
166
|
-
this.applyObjectPx(obj, {
|
|
167
|
-
left: toPx(mm.left),
|
|
168
|
-
top: toPx(mm.top),
|
|
169
|
-
width: toPx(mm.width),
|
|
170
|
-
height: toPx(mm.height),
|
|
171
|
-
strokeWidth: toPx(mm.strokeWidth),
|
|
172
|
-
fontSize: toPx(mm.fontSize),
|
|
173
|
-
});
|
|
174
|
-
const formatted = this._formatOriginUnitValues(mm, obj, 'mm');
|
|
175
|
-
(obj as any)._originSize = {
|
|
176
|
-
...(obj as any)._originSize,
|
|
177
|
-
mm: formatted
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
applyObjectInch(
|
|
182
|
-
obj: fabric.Object,
|
|
183
|
-
inch: {
|
|
184
|
-
left?: number;
|
|
185
|
-
top?: number;
|
|
186
|
-
width?: number;
|
|
187
|
-
height?: number;
|
|
188
|
-
strokeWidth?: number;
|
|
189
|
-
fontSize?: number;
|
|
190
|
-
},
|
|
191
|
-
dpi?: number
|
|
192
|
-
) {
|
|
193
|
-
const toMm = (v: number | undefined) =>
|
|
194
|
-
v === undefined ? undefined : v * LengthConvert.CONSTANTS.INCH_TO_MM;
|
|
195
|
-
this.applyObjectMm(
|
|
196
|
-
obj,
|
|
197
|
-
{
|
|
198
|
-
left: toMm(inch.left),
|
|
199
|
-
top: toMm(inch.top),
|
|
200
|
-
width: toMm(inch.width),
|
|
201
|
-
height: toMm(inch.height),
|
|
202
|
-
strokeWidth: toMm(inch.strokeWidth),
|
|
203
|
-
fontSize: toMm(inch.fontSize),
|
|
204
|
-
},
|
|
205
|
-
dpi
|
|
206
|
-
);
|
|
207
|
-
const formatted = this._formatOriginUnitValues(inch, obj, 'inch');
|
|
208
|
-
(obj as any)._originSize = {
|
|
209
|
-
...(obj as any)._originSize,
|
|
210
|
-
inch: formatted
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
applyObjectByUnit(
|
|
215
|
-
obj: fabric.Object,
|
|
216
|
-
opts: {
|
|
217
|
-
left?: number;
|
|
218
|
-
top?: number;
|
|
219
|
-
width?: number;
|
|
220
|
-
height?: number;
|
|
221
|
-
strokeWidth?: number;
|
|
222
|
-
fontSize?: number;
|
|
223
|
-
},
|
|
224
|
-
dpi?: number
|
|
225
|
-
) {
|
|
226
|
-
const unit = this.getUnit();
|
|
227
|
-
if (unit === 'mm') return this.applyObjectMm(obj, opts, dpi);
|
|
228
|
-
if (unit === 'inch') return this.applyObjectInch(obj, opts, dpi);
|
|
229
|
-
return this.applyObjectPx(obj, opts);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// mm
|
|
233
|
-
setSizeMm(widthMm: number, heightMm: number, dpi?: number) {
|
|
234
|
-
const width = LengthConvert.mmToPx(widthMm, dpi, { direct: true });
|
|
235
|
-
const height = LengthConvert.mmToPx(heightMm, dpi, { direct: true });
|
|
236
|
-
this.editor.setSize(width, height);
|
|
237
|
-
this._syncOriginSize(widthMm, heightMm);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
setSizeByUnit(width: number, height: number, options: { dpi: number, slient?: boolean }) {
|
|
241
|
-
const unit = (this.editor as any).getUnit?.() || 'px';
|
|
242
|
-
if (unit === 'mm') {
|
|
243
|
-
return this.setSizeMm(width, height, options?.dpi);
|
|
244
|
-
}
|
|
245
|
-
if (unit === 'inch') {
|
|
246
|
-
this._syncOriginSize(width, height);
|
|
247
|
-
const wmm = width * LengthConvert.CONSTANTS.INCH_TO_MM;
|
|
248
|
-
const hmm = height * LengthConvert.CONSTANTS.INCH_TO_MM;
|
|
249
|
-
return this.setSizeMm(wmm, hmm, options?.dpi);
|
|
250
|
-
}
|
|
251
|
-
this.editor.setSize(width, height, { slient: options.slient });
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
getOriginSize(dpi?: number) {
|
|
255
|
-
const unit = this.getUnit();
|
|
256
|
-
const origin = (this.canvas as any)._originSize || {};
|
|
257
|
-
const originMm: { width?: number; height?: number } = origin.mm || {};
|
|
258
|
-
|
|
259
|
-
if (unit === 'px') {
|
|
260
|
-
return {
|
|
261
|
-
width: this.canvas.getWidth(),
|
|
262
|
-
height: this.canvas.getHeight(),
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
const ensureMmWidth = originMm.width !== undefined
|
|
266
|
-
? originMm.width
|
|
267
|
-
: LengthConvert.pxToMm(this.canvas.getWidth(), dpi, { direct: true });
|
|
268
|
-
const ensureMmHeight = originMm.height !== undefined
|
|
269
|
-
? originMm.height
|
|
270
|
-
: LengthConvert.pxToMm(this.canvas.getHeight(), dpi, { direct: true });
|
|
271
|
-
|
|
272
|
-
if (unit === 'mm') {
|
|
273
|
-
return this._originSize.mm ?? {
|
|
274
|
-
width: ensureMmWidth,
|
|
275
|
-
height: ensureMmHeight,
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// inch
|
|
280
|
-
return this._originSize.inch ?? {
|
|
281
|
-
width: ensureMmWidth / LengthConvert.CONSTANTS.INCH_TO_MM,
|
|
282
|
-
height: ensureMmHeight / LengthConvert.CONSTANTS.INCH_TO_MM,
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
_syncOriginSize(width?: number, height?: number) {
|
|
287
|
-
const unit = this.getUnit();
|
|
288
|
-
if (unit === 'px') return;
|
|
289
|
-
this._originSize[unit] = this._originSize[unit] || { width: 0, height: 0 };
|
|
290
|
-
if (width !== undefined) this._originSize[unit].width = this._toPrecisionValue(width);
|
|
291
|
-
if (height !== undefined) this._originSize[unit].height = this._toPrecisionValue(height);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
syncOriginSizeByUnit(width?: number, height?: number) {
|
|
295
|
-
const unit = this.getUnit();
|
|
296
|
-
if (unit === 'mm') {
|
|
297
|
-
if (width !== undefined) {
|
|
298
|
-
const v = LengthConvert.pxToMm(width, undefined, { direct: true });
|
|
299
|
-
this._originSize[unit].width = this._toPrecisionValue(v);
|
|
300
|
-
}
|
|
301
|
-
if (height !== undefined) {
|
|
302
|
-
const v = LengthConvert.pxToMm(height, undefined, { direct: true });
|
|
303
|
-
this._originSize[unit].height = this._toPrecisionValue(v);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
_bindEvents() {
|
|
309
|
-
const throttledSync = throttle((obj: fabric.Object) => {
|
|
310
|
-
syncMmFromObject(obj, undefined, this.precision);
|
|
311
|
-
}, 30);
|
|
312
|
-
|
|
313
|
-
this.canvas.on('object:modified', (e: any) => {
|
|
314
|
-
const target = e.target as fabric.Object | undefined;
|
|
315
|
-
if (target) syncMmFromObject(target, undefined, this.precision);
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
this.canvas.on('object:moving', (e: any) => {
|
|
319
|
-
const target = e.target as fabric.Object | undefined;
|
|
320
|
-
if (target) throttledSync(target);
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
this.canvas.on('object:scaling', (e: any) => {
|
|
324
|
-
const target = e.target as fabric.Object | undefined;
|
|
325
|
-
if (target) throttledSync(target);
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
this.canvas.on('object:rotating', (e: any) => {
|
|
329
|
-
const target = e.target as fabric.Object | undefined;
|
|
330
|
-
if (target) throttledSync(target);
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
this.editor.on?.('sizeChange', (event: { width: number, height: number }) => {
|
|
334
|
-
const unit = this.getUnit();
|
|
335
|
-
if (unit === 'px') return;
|
|
336
|
-
if (unit === 'mm') {
|
|
337
|
-
this._syncOriginSize(event.width, event.height);
|
|
338
|
-
return
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
destroy() {
|
|
344
|
-
console.log('pluginDestroy');
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
export default UnitPlugin;
|
|
1
|
+
import type { IEditor, IPluginTempl } from '@hprint/core';
|
|
2
|
+
import { LengthConvert } from '@hprint/shared';
|
|
3
|
+
import { syncMmFromObject } from '../utils/units';
|
|
4
|
+
import { fabric } from '@hprint/core';
|
|
5
|
+
import { throttle } from 'lodash-es';
|
|
6
|
+
|
|
7
|
+
type IPlugin = Pick<
|
|
8
|
+
UnitPlugin,
|
|
9
|
+
| 'getUnit'
|
|
10
|
+
| 'setUnit'
|
|
11
|
+
| 'getSizeByUnit'
|
|
12
|
+
| 'setSizeByUnit'
|
|
13
|
+
| 'getOriginSize'
|
|
14
|
+
| 'syncOriginSizeByUnit'
|
|
15
|
+
| 'applyObjectPx'
|
|
16
|
+
| 'applyObjectMm'
|
|
17
|
+
| 'applyObjectInch'
|
|
18
|
+
| 'applyObjectByUnit'
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
type TUnit = 'px' | 'mm' | 'inch';
|
|
22
|
+
|
|
23
|
+
declare module '@hprint/core' {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
25
|
+
interface IEditor extends IPlugin { }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class UnitPlugin implements IPluginTempl {
|
|
29
|
+
static pluginName = 'UnitPlugin';
|
|
30
|
+
// static events = ['sizeChange'];
|
|
31
|
+
static apis = [
|
|
32
|
+
'getUnit',
|
|
33
|
+
'setUnit',
|
|
34
|
+
'getSizeByUnit',
|
|
35
|
+
'setSizeByUnit',
|
|
36
|
+
'getOriginSize',
|
|
37
|
+
'getPrecision',
|
|
38
|
+
'syncOriginSizeByUnit',
|
|
39
|
+
'applyObjectPx',
|
|
40
|
+
'applyObjectMm',
|
|
41
|
+
'applyObjectInch',
|
|
42
|
+
'applyObjectByUnit',
|
|
43
|
+
];
|
|
44
|
+
unit: TUnit = 'px';
|
|
45
|
+
precision?: number;
|
|
46
|
+
_originSize: Record<string, { width: number, height: number }> = { mm: { width: 0, height: 0 } };
|
|
47
|
+
constructor(
|
|
48
|
+
public canvas: fabric.Canvas,
|
|
49
|
+
public editor: IEditor,
|
|
50
|
+
options?: {
|
|
51
|
+
unit?: TUnit;
|
|
52
|
+
precision?: number;
|
|
53
|
+
}
|
|
54
|
+
) {
|
|
55
|
+
this.init(options);
|
|
56
|
+
this._bindEvents();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
hookSaveBefore() {
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
resolve(true);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
hookSaveAfter() {
|
|
66
|
+
return new Promise((resolve) => {
|
|
67
|
+
resolve(true);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
init(options?: { unit?: TUnit; precision?: number }) {
|
|
72
|
+
if (options?.unit) this.unit = options?.unit;
|
|
73
|
+
if (options?.precision) this.precision = options?.precision;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
setUnit(unit: TUnit) {
|
|
77
|
+
if (this.unit === unit) return;
|
|
78
|
+
this.unit = unit;
|
|
79
|
+
this.editor.emit('unitChange', unit);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getUnit() {
|
|
83
|
+
return this.unit;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getPrecision() {
|
|
87
|
+
return this.precision;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
getSizeByUnit(pxValue: number, unit?: TUnit, dpi?: number) {
|
|
91
|
+
const targetUnit = unit ?? this.editor.getUnit();
|
|
92
|
+
if (targetUnit === 'px') return pxValue;
|
|
93
|
+
if (targetUnit === 'mm') return LengthConvert.pxToMm(pxValue, dpi, { direct: true });
|
|
94
|
+
if (targetUnit === 'inch') {
|
|
95
|
+
const mm = LengthConvert.pxToMm(pxValue, dpi, { direct: true });
|
|
96
|
+
return mm / LengthConvert.CONSTANTS.INCH_TO_MM;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
_toPrecisionValue(value: number) {
|
|
101
|
+
if (this.precision === undefined) return value;
|
|
102
|
+
const factor = Math.pow(10, this.precision);
|
|
103
|
+
return Math.round(value * factor) / factor;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
_formatOriginUnitValues<T extends { [k: string]: number | undefined }>(
|
|
107
|
+
vals: T,
|
|
108
|
+
obj?: fabric.Object,
|
|
109
|
+
unit?: 'mm' | 'inch'
|
|
110
|
+
): T {
|
|
111
|
+
const result: Record<string, number | undefined> = {};
|
|
112
|
+
for (const key in vals) {
|
|
113
|
+
const v = vals[key];
|
|
114
|
+
result[key] = v === undefined ? undefined : this._toPrecisionValue(v);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Preserve ALL existing fields from _originSize[unit] to prevent data loss
|
|
118
|
+
if (obj && unit) {
|
|
119
|
+
const existingUnit = (obj as any)._originSize?.[unit] || {};
|
|
120
|
+
// Merge existing fields with new values, new values take precedence
|
|
121
|
+
Object.keys(existingUnit).forEach((key) => {
|
|
122
|
+
if (!(key in result)) {
|
|
123
|
+
result[key] = existingUnit[key];
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return result as T;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
applyObjectPx(
|
|
132
|
+
obj: fabric.Object,
|
|
133
|
+
opts: {
|
|
134
|
+
left?: number;
|
|
135
|
+
top?: number;
|
|
136
|
+
width?: number;
|
|
137
|
+
height?: number;
|
|
138
|
+
strokeWidth?: number;
|
|
139
|
+
fontSize?: number;
|
|
140
|
+
}
|
|
141
|
+
) {
|
|
142
|
+
const { left, top, width, height, strokeWidth, fontSize } = opts;
|
|
143
|
+
// fontSize必须在width之前,否则可能宽度设置不正确
|
|
144
|
+
if (fontSize !== undefined) obj.set('fontSize', fontSize);
|
|
145
|
+
if (strokeWidth !== undefined) obj.set('strokeWidth', strokeWidth);
|
|
146
|
+
if (width !== undefined) obj.set('width', width);
|
|
147
|
+
if (height !== undefined) obj.set('height', height);
|
|
148
|
+
if (left !== undefined) obj.set('left', left);
|
|
149
|
+
if (top !== undefined) obj.set('top', top);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
applyObjectMm(
|
|
153
|
+
obj: fabric.Object,
|
|
154
|
+
mm: {
|
|
155
|
+
left?: number;
|
|
156
|
+
top?: number;
|
|
157
|
+
width?: number;
|
|
158
|
+
height?: number;
|
|
159
|
+
strokeWidth?: number;
|
|
160
|
+
fontSize?: number;
|
|
161
|
+
},
|
|
162
|
+
dpi?: number
|
|
163
|
+
) {
|
|
164
|
+
const toPx = (v: number | undefined) =>
|
|
165
|
+
v === undefined ? undefined : LengthConvert.mmToPx(v, dpi, { direct: true });
|
|
166
|
+
this.applyObjectPx(obj, {
|
|
167
|
+
left: toPx(mm.left),
|
|
168
|
+
top: toPx(mm.top),
|
|
169
|
+
width: toPx(mm.width),
|
|
170
|
+
height: toPx(mm.height),
|
|
171
|
+
strokeWidth: toPx(mm.strokeWidth),
|
|
172
|
+
fontSize: toPx(mm.fontSize),
|
|
173
|
+
});
|
|
174
|
+
const formatted = this._formatOriginUnitValues(mm, obj, 'mm');
|
|
175
|
+
(obj as any)._originSize = {
|
|
176
|
+
...(obj as any)._originSize,
|
|
177
|
+
mm: formatted
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
applyObjectInch(
|
|
182
|
+
obj: fabric.Object,
|
|
183
|
+
inch: {
|
|
184
|
+
left?: number;
|
|
185
|
+
top?: number;
|
|
186
|
+
width?: number;
|
|
187
|
+
height?: number;
|
|
188
|
+
strokeWidth?: number;
|
|
189
|
+
fontSize?: number;
|
|
190
|
+
},
|
|
191
|
+
dpi?: number
|
|
192
|
+
) {
|
|
193
|
+
const toMm = (v: number | undefined) =>
|
|
194
|
+
v === undefined ? undefined : v * LengthConvert.CONSTANTS.INCH_TO_MM;
|
|
195
|
+
this.applyObjectMm(
|
|
196
|
+
obj,
|
|
197
|
+
{
|
|
198
|
+
left: toMm(inch.left),
|
|
199
|
+
top: toMm(inch.top),
|
|
200
|
+
width: toMm(inch.width),
|
|
201
|
+
height: toMm(inch.height),
|
|
202
|
+
strokeWidth: toMm(inch.strokeWidth),
|
|
203
|
+
fontSize: toMm(inch.fontSize),
|
|
204
|
+
},
|
|
205
|
+
dpi
|
|
206
|
+
);
|
|
207
|
+
const formatted = this._formatOriginUnitValues(inch, obj, 'inch');
|
|
208
|
+
(obj as any)._originSize = {
|
|
209
|
+
...(obj as any)._originSize,
|
|
210
|
+
inch: formatted
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
applyObjectByUnit(
|
|
215
|
+
obj: fabric.Object,
|
|
216
|
+
opts: {
|
|
217
|
+
left?: number;
|
|
218
|
+
top?: number;
|
|
219
|
+
width?: number;
|
|
220
|
+
height?: number;
|
|
221
|
+
strokeWidth?: number;
|
|
222
|
+
fontSize?: number;
|
|
223
|
+
},
|
|
224
|
+
dpi?: number
|
|
225
|
+
) {
|
|
226
|
+
const unit = this.getUnit();
|
|
227
|
+
if (unit === 'mm') return this.applyObjectMm(obj, opts, dpi);
|
|
228
|
+
if (unit === 'inch') return this.applyObjectInch(obj, opts, dpi);
|
|
229
|
+
return this.applyObjectPx(obj, opts);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// mm
|
|
233
|
+
setSizeMm(widthMm: number, heightMm: number, dpi?: number) {
|
|
234
|
+
const width = LengthConvert.mmToPx(widthMm, dpi, { direct: true });
|
|
235
|
+
const height = LengthConvert.mmToPx(heightMm, dpi, { direct: true });
|
|
236
|
+
this.editor.setSize(width, height);
|
|
237
|
+
this._syncOriginSize(widthMm, heightMm);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
setSizeByUnit(width: number, height: number, options: { dpi: number, slient?: boolean }) {
|
|
241
|
+
const unit = (this.editor as any).getUnit?.() || 'px';
|
|
242
|
+
if (unit === 'mm') {
|
|
243
|
+
return this.setSizeMm(width, height, options?.dpi);
|
|
244
|
+
}
|
|
245
|
+
if (unit === 'inch') {
|
|
246
|
+
this._syncOriginSize(width, height);
|
|
247
|
+
const wmm = width * LengthConvert.CONSTANTS.INCH_TO_MM;
|
|
248
|
+
const hmm = height * LengthConvert.CONSTANTS.INCH_TO_MM;
|
|
249
|
+
return this.setSizeMm(wmm, hmm, options?.dpi);
|
|
250
|
+
}
|
|
251
|
+
this.editor.setSize(width, height, { slient: options.slient });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
getOriginSize(dpi?: number) {
|
|
255
|
+
const unit = this.getUnit();
|
|
256
|
+
const origin = (this.canvas as any)._originSize || {};
|
|
257
|
+
const originMm: { width?: number; height?: number } = origin.mm || {};
|
|
258
|
+
|
|
259
|
+
if (unit === 'px') {
|
|
260
|
+
return {
|
|
261
|
+
width: this.canvas.getWidth(),
|
|
262
|
+
height: this.canvas.getHeight(),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const ensureMmWidth = originMm.width !== undefined
|
|
266
|
+
? originMm.width
|
|
267
|
+
: LengthConvert.pxToMm(this.canvas.getWidth(), dpi, { direct: true });
|
|
268
|
+
const ensureMmHeight = originMm.height !== undefined
|
|
269
|
+
? originMm.height
|
|
270
|
+
: LengthConvert.pxToMm(this.canvas.getHeight(), dpi, { direct: true });
|
|
271
|
+
|
|
272
|
+
if (unit === 'mm') {
|
|
273
|
+
return this._originSize.mm ?? {
|
|
274
|
+
width: ensureMmWidth,
|
|
275
|
+
height: ensureMmHeight,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// inch
|
|
280
|
+
return this._originSize.inch ?? {
|
|
281
|
+
width: ensureMmWidth / LengthConvert.CONSTANTS.INCH_TO_MM,
|
|
282
|
+
height: ensureMmHeight / LengthConvert.CONSTANTS.INCH_TO_MM,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
_syncOriginSize(width?: number, height?: number) {
|
|
287
|
+
const unit = this.getUnit();
|
|
288
|
+
if (unit === 'px') return;
|
|
289
|
+
this._originSize[unit] = this._originSize[unit] || { width: 0, height: 0 };
|
|
290
|
+
if (width !== undefined) this._originSize[unit].width = this._toPrecisionValue(width);
|
|
291
|
+
if (height !== undefined) this._originSize[unit].height = this._toPrecisionValue(height);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
syncOriginSizeByUnit(width?: number, height?: number) {
|
|
295
|
+
const unit = this.getUnit();
|
|
296
|
+
if (unit === 'mm') {
|
|
297
|
+
if (width !== undefined) {
|
|
298
|
+
const v = LengthConvert.pxToMm(width, undefined, { direct: true });
|
|
299
|
+
this._originSize[unit].width = this._toPrecisionValue(v);
|
|
300
|
+
}
|
|
301
|
+
if (height !== undefined) {
|
|
302
|
+
const v = LengthConvert.pxToMm(height, undefined, { direct: true });
|
|
303
|
+
this._originSize[unit].height = this._toPrecisionValue(v);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
_bindEvents() {
|
|
309
|
+
const throttledSync = throttle((obj: fabric.Object) => {
|
|
310
|
+
syncMmFromObject(obj, undefined, this.precision);
|
|
311
|
+
}, 30);
|
|
312
|
+
|
|
313
|
+
this.canvas.on('object:modified', (e: any) => {
|
|
314
|
+
const target = e.target as fabric.Object | undefined;
|
|
315
|
+
if (target) syncMmFromObject(target, undefined, this.precision);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
this.canvas.on('object:moving', (e: any) => {
|
|
319
|
+
const target = e.target as fabric.Object | undefined;
|
|
320
|
+
if (target) throttledSync(target);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
this.canvas.on('object:scaling', (e: any) => {
|
|
324
|
+
const target = e.target as fabric.Object | undefined;
|
|
325
|
+
if (target) throttledSync(target);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
this.canvas.on('object:rotating', (e: any) => {
|
|
329
|
+
const target = e.target as fabric.Object | undefined;
|
|
330
|
+
if (target) throttledSync(target);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
this.editor.on?.('sizeChange', (event: { width: number, height: number }) => {
|
|
334
|
+
const unit = this.getUnit();
|
|
335
|
+
if (unit === 'px') return;
|
|
336
|
+
if (unit === 'mm') {
|
|
337
|
+
this._syncOriginSize(event.width, event.height);
|
|
338
|
+
return
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
destroy() {
|
|
344
|
+
console.log('pluginDestroy');
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export default UnitPlugin;
|