@hprint/plugins 0.0.7 → 0.0.9-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.js +44 -44
- package/dist/index.mjs +6957 -6550
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/plugins/ActualContentLayoutPlugin.d.ts +29 -0
- package/dist/src/plugins/ActualContentLayoutPlugin.d.ts.map +1 -0
- package/dist/src/plugins/CopyPlugin.d.ts.map +1 -1
- package/dist/src/plugins/ImageTextListPlugin.d.ts +68 -0
- package/dist/src/plugins/ImageTextListPlugin.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/assets/style/resizePlugin.css +27 -27
- package/src/index.ts +11 -5
- package/src/objects/Arrow.js +47 -47
- package/src/objects/ThinTailArrow.js +50 -50
- package/src/plugins/ActualContentLayoutPlugin.ts +276 -0
- package/src/plugins/ControlsPlugin.ts +413 -413
- package/src/plugins/ControlsRotatePlugin.ts +111 -111
- package/src/plugins/CopyPlugin.ts +260 -258
- 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/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/ImageTextListPlugin.ts +540 -0
- package/src/plugins/LayerPlugin.ts +108 -108
- 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/SimpleClipImagePlugin.ts +244 -244
- 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/utils.ts +162 -162
- package/tsconfig.json +10 -10
- package/vite.config.ts +29 -29
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { fabric } from '@hprint/core';
|
|
2
|
+
import type { IEditor, IPluginTempl } from '@hprint/core';
|
|
3
|
+
|
|
4
|
+
export interface ActualContentLayoutSettings {
|
|
5
|
+
actualContentLayout?: boolean;
|
|
6
|
+
overflowMode?: 'clip' | 'expand';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type IPlugin = Pick<ActualContentLayoutPlugin, 'applyActualContentLayout'>;
|
|
10
|
+
|
|
11
|
+
declare module '@hprint/core' {
|
|
12
|
+
interface IEditor extends IPlugin {}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type LayoutEntry = {
|
|
16
|
+
object: fabric.Object;
|
|
17
|
+
index: number;
|
|
18
|
+
originalTop: number;
|
|
19
|
+
originalBottom: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
class ActualContentLayoutPlugin implements IPluginTempl {
|
|
23
|
+
static pluginName = 'ActualContentLayoutPlugin';
|
|
24
|
+
static apis = ['applyActualContentLayout'];
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
public canvas: fabric.Canvas,
|
|
28
|
+
public editor: IEditor
|
|
29
|
+
) {}
|
|
30
|
+
|
|
31
|
+
private layoutOrigins = new WeakMap<
|
|
32
|
+
fabric.Object,
|
|
33
|
+
{ top: number; height: number }
|
|
34
|
+
>();
|
|
35
|
+
|
|
36
|
+
async hookTransformObjectEnd(...args: unknown[]) {
|
|
37
|
+
const { originObject, fabricObject } = args[0] as {
|
|
38
|
+
originObject: any;
|
|
39
|
+
fabricObject: fabric.Object;
|
|
40
|
+
};
|
|
41
|
+
if (!this.isPrintableObject(originObject)) return;
|
|
42
|
+
|
|
43
|
+
const mmPerPx = Number(this.editor.getSizeByUnit?.(1, 'mm')) || 1;
|
|
44
|
+
this.layoutOrigins.set(fabricObject, {
|
|
45
|
+
top: this.getOriginalTop(originObject, fabricObject, mmPerPx),
|
|
46
|
+
height: this.getOriginalHeight(
|
|
47
|
+
originObject,
|
|
48
|
+
fabricObject,
|
|
49
|
+
mmPerPx
|
|
50
|
+
),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
applyActualContentLayout(templateContent: any, templateHeight: number) {
|
|
55
|
+
const settings = (templateContent?.templateSettings ||
|
|
56
|
+
{}) as ActualContentLayoutSettings;
|
|
57
|
+
if (!settings.actualContentLayout) return templateHeight;
|
|
58
|
+
|
|
59
|
+
const fabricObjects = this.canvas
|
|
60
|
+
.getObjects()
|
|
61
|
+
.filter(this.isPrintableObject);
|
|
62
|
+
const mmPerPx = Number(this.editor.getSizeByUnit?.(1, 'mm')) || 1;
|
|
63
|
+
|
|
64
|
+
fabricObjects.forEach((object) => this.preparePrintLayoutObject(object));
|
|
65
|
+
|
|
66
|
+
const entries = fabricObjects.map((object, index) => {
|
|
67
|
+
const origin = this.layoutOrigins.get(object);
|
|
68
|
+
const originalTop =
|
|
69
|
+
origin?.top ?? Number(object.top || 0) * mmPerPx;
|
|
70
|
+
const originalHeight =
|
|
71
|
+
origin?.height ??
|
|
72
|
+
Number(object.getScaledHeight?.() || object.height || 0) *
|
|
73
|
+
mmPerPx;
|
|
74
|
+
return {
|
|
75
|
+
object,
|
|
76
|
+
index,
|
|
77
|
+
originalTop,
|
|
78
|
+
originalBottom: originalTop + originalHeight,
|
|
79
|
+
};
|
|
80
|
+
}) as LayoutEntry[];
|
|
81
|
+
|
|
82
|
+
entries.sort(
|
|
83
|
+
(a, b) => a.originalTop - b.originalTop || a.index - b.index
|
|
84
|
+
);
|
|
85
|
+
const rows: LayoutEntry[][] = [];
|
|
86
|
+
const sameRowTolerance = 0.01;
|
|
87
|
+
entries.forEach((entry) => {
|
|
88
|
+
const row = rows[rows.length - 1];
|
|
89
|
+
if (
|
|
90
|
+
row &&
|
|
91
|
+
Math.abs(row[0].originalTop - entry.originalTop) <=
|
|
92
|
+
sameRowTolerance
|
|
93
|
+
) {
|
|
94
|
+
row.push(entry);
|
|
95
|
+
} else {
|
|
96
|
+
rows.push([entry]);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
let previousOriginalBottom: number | undefined;
|
|
101
|
+
let previousActualBottom: number | undefined;
|
|
102
|
+
let pendingGap = 0;
|
|
103
|
+
let lastVisibleOriginalBottom = 0;
|
|
104
|
+
|
|
105
|
+
rows.forEach((row) => {
|
|
106
|
+
const rowOriginalTop = row[0].originalTop;
|
|
107
|
+
const rowOriginalBottom = Math.max(
|
|
108
|
+
...row.map((entry) => entry.originalBottom)
|
|
109
|
+
);
|
|
110
|
+
if (previousOriginalBottom !== undefined) {
|
|
111
|
+
pendingGap += Math.max(
|
|
112
|
+
0,
|
|
113
|
+
rowOriginalTop - previousOriginalBottom
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
previousOriginalBottom = rowOriginalBottom;
|
|
117
|
+
|
|
118
|
+
const visibleEntries = row.filter(
|
|
119
|
+
(entry) => !this.isEmptyLayoutObject(entry.object)
|
|
120
|
+
);
|
|
121
|
+
if (!visibleEntries.length) return;
|
|
122
|
+
|
|
123
|
+
const targetTop =
|
|
124
|
+
previousActualBottom === undefined
|
|
125
|
+
? rowOriginalTop
|
|
126
|
+
: previousActualBottom + pendingGap;
|
|
127
|
+
visibleEntries.forEach((entry) => {
|
|
128
|
+
entry.object.set('top', targetTop / mmPerPx);
|
|
129
|
+
entry.object.setCoords();
|
|
130
|
+
});
|
|
131
|
+
previousActualBottom = Math.max(
|
|
132
|
+
...visibleEntries.map(
|
|
133
|
+
(entry) =>
|
|
134
|
+
(Number(entry.object.top || 0) +
|
|
135
|
+
this.getActualLayoutHeight(entry.object)) *
|
|
136
|
+
mmPerPx
|
|
137
|
+
)
|
|
138
|
+
);
|
|
139
|
+
lastVisibleOriginalBottom = rowOriginalBottom;
|
|
140
|
+
pendingGap = 0;
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
this.canvas.requestRenderAll();
|
|
144
|
+
if (
|
|
145
|
+
settings.overflowMode !== 'expand' ||
|
|
146
|
+
previousActualBottom === undefined
|
|
147
|
+
) {
|
|
148
|
+
return templateHeight;
|
|
149
|
+
}
|
|
150
|
+
const bottomSpace = Math.max(
|
|
151
|
+
0,
|
|
152
|
+
templateHeight - lastVisibleOriginalBottom
|
|
153
|
+
);
|
|
154
|
+
return Math.max(
|
|
155
|
+
templateHeight,
|
|
156
|
+
previousActualBottom + bottomSpace
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private getOriginalTop(
|
|
161
|
+
source: any,
|
|
162
|
+
object: fabric.Object,
|
|
163
|
+
mmPerPx: number
|
|
164
|
+
) {
|
|
165
|
+
const top = Number(source?.top);
|
|
166
|
+
if (Number.isFinite(top)) return top * mmPerPx;
|
|
167
|
+
return this.getOriginMmValue(
|
|
168
|
+
source,
|
|
169
|
+
'top',
|
|
170
|
+
Number(object.top || 0) * mmPerPx
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private getOriginalHeight(
|
|
175
|
+
source: any,
|
|
176
|
+
object: fabric.Object,
|
|
177
|
+
mmPerPx: number
|
|
178
|
+
) {
|
|
179
|
+
const height = Number(source?.height);
|
|
180
|
+
const scaleY = Number(source?.scaleY ?? 1);
|
|
181
|
+
if (Number.isFinite(height) && Number.isFinite(scaleY)) {
|
|
182
|
+
return Math.abs(height * scaleY) * mmPerPx;
|
|
183
|
+
}
|
|
184
|
+
return this.getOriginMmValue(
|
|
185
|
+
source,
|
|
186
|
+
'height',
|
|
187
|
+
Number(object.getScaledHeight?.() || object.height || 0) *
|
|
188
|
+
mmPerPx
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private getOriginMmValue(
|
|
193
|
+
source: any,
|
|
194
|
+
field: 'top' | 'height',
|
|
195
|
+
fallback: number
|
|
196
|
+
) {
|
|
197
|
+
const originalValue = source?._originSize?.mm?.[field];
|
|
198
|
+
if (
|
|
199
|
+
originalValue === undefined ||
|
|
200
|
+
originalValue === null ||
|
|
201
|
+
originalValue === ''
|
|
202
|
+
) {
|
|
203
|
+
return fallback;
|
|
204
|
+
}
|
|
205
|
+
const value = Number(originalValue);
|
|
206
|
+
return Number.isFinite(value) ? value : fallback;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private preparePrintLayoutObject(object: any) {
|
|
210
|
+
if (object?.extensionType !== 'imageTextList') return;
|
|
211
|
+
if (object.extension?._clipContent === true) return;
|
|
212
|
+
|
|
213
|
+
// Design canvases can opt into clipping, but print/layout canvases should
|
|
214
|
+
// measure and render the natural image-text content height.
|
|
215
|
+
if (object.clipPath) object.set('clipPath', undefined);
|
|
216
|
+
object.set({
|
|
217
|
+
objectCaching: false,
|
|
218
|
+
dirty: true,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private isPrintableObject(object: any) {
|
|
223
|
+
return (
|
|
224
|
+
object?.id !== 'workspace' &&
|
|
225
|
+
object?.id !== 'coverMask' &&
|
|
226
|
+
object?.type !== 'GuideLine'
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private isEmptyLayoutObject(object: any) {
|
|
231
|
+
if (object?.visible === false) return true;
|
|
232
|
+
const field = object?.extension?._field_;
|
|
233
|
+
if (!field) return false;
|
|
234
|
+
if (object.type === 'textbox') {
|
|
235
|
+
return String(object.text ?? '') === '';
|
|
236
|
+
}
|
|
237
|
+
if (['barcode', 'qrcode'].includes(object.extensionType)) {
|
|
238
|
+
return String(object.extension?.value ?? '') === '';
|
|
239
|
+
}
|
|
240
|
+
if (object.extensionType === 'imageTextList') {
|
|
241
|
+
return (
|
|
242
|
+
!Array.isArray(object.extension?.items) ||
|
|
243
|
+
object.extension.items.length === 0
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private getActualLayoutHeight(object: any) {
|
|
250
|
+
if (object?.extensionType !== 'imageTextList') {
|
|
251
|
+
return Number(
|
|
252
|
+
object.getScaledHeight?.() || object.height || 0
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const children = object.getObjects?.() || object._objects || [];
|
|
257
|
+
const contentChildren = children.slice(1);
|
|
258
|
+
if (!contentChildren.length) return 0;
|
|
259
|
+
|
|
260
|
+
const groupHeight = Number(object.height || 0);
|
|
261
|
+
const groupScaleY = Math.abs(Number(object.scaleY ?? 1));
|
|
262
|
+
const contentBottom = Math.max(
|
|
263
|
+
...contentChildren.map(
|
|
264
|
+
(child: any) =>
|
|
265
|
+
Number(child.top || 0) +
|
|
266
|
+
groupHeight / 2 +
|
|
267
|
+
Number(
|
|
268
|
+
child.getScaledHeight?.() || child.height || 0
|
|
269
|
+
)
|
|
270
|
+
)
|
|
271
|
+
);
|
|
272
|
+
return Math.max(0, contentBottom) * groupScaleY;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export default ActualContentLayoutPlugin;
|