@pooder/kit 1.0.0 → 3.0.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/CHANGELOG.md +22 -0
- package/dist/index.d.mts +250 -115
- package/dist/index.d.ts +250 -115
- package/dist/index.js +2177 -831
- package/dist/index.mjs +2182 -826
- package/package.json +3 -2
- package/src/CanvasService.ts +65 -0
- package/src/background.ts +230 -172
- package/src/coordinate.ts +49 -0
- package/src/dieline.ts +780 -421
- package/src/film.ts +194 -156
- package/src/geometry.ts +464 -244
- package/src/hole.ts +629 -413
- package/src/image.ts +504 -147
- package/src/index.ts +9 -7
- package/src/mirror.ts +128 -0
- package/src/ruler.ts +325 -239
- package/src/tracer.ts +372 -0
- package/src/white-ink.ts +373 -301
- package/tsconfig.json +13 -13
package/src/image.ts
CHANGED
|
@@ -1,147 +1,504 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
1
|
+
import {
|
|
2
|
+
CommandContribution,
|
|
3
|
+
ConfigurationContribution,
|
|
4
|
+
ConfigurationService,
|
|
5
|
+
ContributionPointIds,
|
|
6
|
+
Extension,
|
|
7
|
+
ExtensionContext,
|
|
8
|
+
} from "@pooder/core";
|
|
9
|
+
import { FabricImage as Image, Point, util } from "fabric";
|
|
10
|
+
import CanvasService from "./CanvasService";
|
|
11
|
+
import { Coordinate } from "./coordinate";
|
|
12
|
+
|
|
13
|
+
export class ImageTool implements Extension {
|
|
14
|
+
id = "pooder.kit.image";
|
|
15
|
+
|
|
16
|
+
metadata = {
|
|
17
|
+
name: "ImageTool",
|
|
18
|
+
};
|
|
19
|
+
private _loadingUrl: string | null = null;
|
|
20
|
+
|
|
21
|
+
private url: string = "";
|
|
22
|
+
private opacity: number = 1;
|
|
23
|
+
private width?: number;
|
|
24
|
+
private height?: number;
|
|
25
|
+
private angle?: number;
|
|
26
|
+
private left?: number;
|
|
27
|
+
private top?: number;
|
|
28
|
+
|
|
29
|
+
private canvasService?: CanvasService;
|
|
30
|
+
private context?: ExtensionContext;
|
|
31
|
+
|
|
32
|
+
constructor(
|
|
33
|
+
options?: Partial<{
|
|
34
|
+
url: string;
|
|
35
|
+
opacity: number;
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
angle: number;
|
|
39
|
+
left: number;
|
|
40
|
+
top: number;
|
|
41
|
+
}>,
|
|
42
|
+
) {
|
|
43
|
+
if (options) {
|
|
44
|
+
Object.assign(this, options);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
activate(context: ExtensionContext) {
|
|
49
|
+
this.context = context;
|
|
50
|
+
this.canvasService = context.services.get<CanvasService>("CanvasService");
|
|
51
|
+
if (!this.canvasService) {
|
|
52
|
+
console.warn("CanvasService not found for ImageTool");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const configService = context.services.get<any>("ConfigurationService");
|
|
57
|
+
if (configService) {
|
|
58
|
+
// Load initial config
|
|
59
|
+
this.url = configService.get("image.url", this.url);
|
|
60
|
+
this.opacity = configService.get("image.opacity", this.opacity);
|
|
61
|
+
this.width = configService.get("image.width", this.width);
|
|
62
|
+
this.height = configService.get("image.height", this.height);
|
|
63
|
+
this.angle = configService.get("image.angle", this.angle);
|
|
64
|
+
this.left = configService.get("image.left", this.left);
|
|
65
|
+
this.top = configService.get("image.top", this.top);
|
|
66
|
+
|
|
67
|
+
// Listen for changes
|
|
68
|
+
configService.onAnyChange((e: { key: string; value: any }) => {
|
|
69
|
+
if (e.key.startsWith("image.")) {
|
|
70
|
+
const prop = e.key.split(".")[1];
|
|
71
|
+
console.log(
|
|
72
|
+
`[ImageTool] Config change detected: ${e.key} -> ${e.value}`,
|
|
73
|
+
);
|
|
74
|
+
if (prop && prop in this) {
|
|
75
|
+
(this as any)[prop] = e.value;
|
|
76
|
+
this.updateImage();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.ensureLayer();
|
|
83
|
+
this.updateImage();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
deactivate(context: ExtensionContext) {
|
|
87
|
+
if (this.canvasService) {
|
|
88
|
+
const layer = this.canvasService.getLayer("user");
|
|
89
|
+
if (layer) {
|
|
90
|
+
const userImage = this.canvasService.getObject("user-image", "user");
|
|
91
|
+
if (userImage) {
|
|
92
|
+
layer.remove(userImage);
|
|
93
|
+
this.canvasService.requestRenderAll();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
this.canvasService = undefined;
|
|
97
|
+
this.context = undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
contribute() {
|
|
102
|
+
return {
|
|
103
|
+
[ContributionPointIds.CONFIGURATIONS]: [
|
|
104
|
+
{
|
|
105
|
+
id: "image.url",
|
|
106
|
+
type: "string",
|
|
107
|
+
label: "Image URL",
|
|
108
|
+
default: this.url,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "image.opacity",
|
|
112
|
+
type: "number",
|
|
113
|
+
label: "Opacity",
|
|
114
|
+
min: 0,
|
|
115
|
+
max: 1,
|
|
116
|
+
step: 0.1,
|
|
117
|
+
default: this.opacity,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "image.width",
|
|
121
|
+
type: "number",
|
|
122
|
+
label: "Width",
|
|
123
|
+
min: 0,
|
|
124
|
+
max: 5000,
|
|
125
|
+
default: this.width,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: "image.height",
|
|
129
|
+
type: "number",
|
|
130
|
+
label: "Height",
|
|
131
|
+
min: 0,
|
|
132
|
+
max: 5000,
|
|
133
|
+
default: this.height,
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
id: "image.angle",
|
|
137
|
+
type: "number",
|
|
138
|
+
label: "Rotation",
|
|
139
|
+
min: 0,
|
|
140
|
+
max: 360,
|
|
141
|
+
default: this.angle,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: "image.left",
|
|
145
|
+
type: "number",
|
|
146
|
+
label: "Left (Normalized)",
|
|
147
|
+
min: 0,
|
|
148
|
+
max: 1,
|
|
149
|
+
default: this.left,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: "image.top",
|
|
153
|
+
type: "number",
|
|
154
|
+
label: "Top (Normalized)",
|
|
155
|
+
min: 0,
|
|
156
|
+
max: 1,
|
|
157
|
+
default: this.top,
|
|
158
|
+
},
|
|
159
|
+
] as ConfigurationContribution[],
|
|
160
|
+
[ContributionPointIds.COMMANDS]: [
|
|
161
|
+
{
|
|
162
|
+
command: "setUserImage",
|
|
163
|
+
title: "Set User Image",
|
|
164
|
+
handler: (
|
|
165
|
+
url: string,
|
|
166
|
+
opacity: number,
|
|
167
|
+
width?: number,
|
|
168
|
+
height?: number,
|
|
169
|
+
angle?: number,
|
|
170
|
+
left?: number,
|
|
171
|
+
top?: number,
|
|
172
|
+
) => {
|
|
173
|
+
if (
|
|
174
|
+
this.url === url &&
|
|
175
|
+
this.opacity === opacity &&
|
|
176
|
+
this.width === width &&
|
|
177
|
+
this.height === height &&
|
|
178
|
+
this.angle === angle &&
|
|
179
|
+
this.left === left &&
|
|
180
|
+
this.top === top
|
|
181
|
+
)
|
|
182
|
+
return true;
|
|
183
|
+
|
|
184
|
+
this.url = url;
|
|
185
|
+
this.opacity = opacity;
|
|
186
|
+
this.width = width;
|
|
187
|
+
this.height = height;
|
|
188
|
+
this.angle = angle;
|
|
189
|
+
this.left = left;
|
|
190
|
+
this.top = top;
|
|
191
|
+
|
|
192
|
+
// Direct update
|
|
193
|
+
this.updateImage();
|
|
194
|
+
|
|
195
|
+
return true;
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
] as CommandContribution[],
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private ensureLayer() {
|
|
203
|
+
if (!this.canvasService) return;
|
|
204
|
+
let userLayer = this.canvasService.getLayer("user");
|
|
205
|
+
if (!userLayer) {
|
|
206
|
+
userLayer = this.canvasService.createLayer("user", {
|
|
207
|
+
width: this.canvasService.canvas.width,
|
|
208
|
+
height: this.canvasService.canvas.height,
|
|
209
|
+
left: 0,
|
|
210
|
+
top: 0,
|
|
211
|
+
originX: "left",
|
|
212
|
+
originY: "top",
|
|
213
|
+
selectable: false,
|
|
214
|
+
evented: true,
|
|
215
|
+
subTargetCheck: true,
|
|
216
|
+
interactive: true,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Try to insert below dieline-overlay
|
|
220
|
+
const dielineLayer = this.canvasService.getLayer("dieline-overlay");
|
|
221
|
+
if (dielineLayer) {
|
|
222
|
+
const index = this.canvasService.canvas
|
|
223
|
+
.getObjects()
|
|
224
|
+
.indexOf(dielineLayer);
|
|
225
|
+
// If dieline is at 0, move user to 0 (dieline shifts to 1)
|
|
226
|
+
if (index >= 0) {
|
|
227
|
+
this.canvasService.canvas.moveObjectTo(userLayer, index);
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
// Ensure background is behind
|
|
231
|
+
const bgLayer = this.canvasService.getLayer("background");
|
|
232
|
+
if (bgLayer) {
|
|
233
|
+
this.canvasService.canvas.sendObjectToBack(bgLayer);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
this.canvasService.requestRenderAll();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private updateImage() {
|
|
241
|
+
if (!this.canvasService) return;
|
|
242
|
+
let { url, opacity, width, height, angle, left, top } = this;
|
|
243
|
+
|
|
244
|
+
const layer = this.canvasService.getLayer("user");
|
|
245
|
+
if (!layer) {
|
|
246
|
+
console.warn("[ImageTool] User layer not found");
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const userImage = this.canvasService.getObject("user-image", "user") as any;
|
|
251
|
+
|
|
252
|
+
if (this._loadingUrl === url) return;
|
|
253
|
+
|
|
254
|
+
if (userImage) {
|
|
255
|
+
const currentSrc = userImage.getSrc?.() || userImage._element?.src;
|
|
256
|
+
|
|
257
|
+
if (currentSrc !== url) {
|
|
258
|
+
this.loadImage(layer);
|
|
259
|
+
} else {
|
|
260
|
+
const updates: any = {};
|
|
261
|
+
const canvasW = this.canvasService.canvas.width || 800;
|
|
262
|
+
const canvasH = this.canvasService.canvas.height || 600;
|
|
263
|
+
const centerX = canvasW / 2;
|
|
264
|
+
const centerY = canvasH / 2;
|
|
265
|
+
|
|
266
|
+
if (userImage.opacity !== opacity) updates.opacity = opacity;
|
|
267
|
+
if (angle !== undefined && userImage.angle !== angle)
|
|
268
|
+
updates.angle = angle;
|
|
269
|
+
|
|
270
|
+
if (userImage.originX !== "center") {
|
|
271
|
+
userImage.set({
|
|
272
|
+
originX: "center",
|
|
273
|
+
originY: "center",
|
|
274
|
+
left: userImage.left + (userImage.width * userImage.scaleX) / 2,
|
|
275
|
+
top: userImage.top + (userImage.height * userImage.scaleY) / 2,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (left !== undefined) {
|
|
280
|
+
const globalLeft = Coordinate.toAbsolute(left, canvasW);
|
|
281
|
+
const localLeft = globalLeft - centerX;
|
|
282
|
+
if (Math.abs(userImage.left - localLeft) > 1)
|
|
283
|
+
updates.left = localLeft;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (top !== undefined) {
|
|
287
|
+
const globalTop = Coordinate.toAbsolute(top, canvasH);
|
|
288
|
+
const localTop = globalTop - centerY;
|
|
289
|
+
if (Math.abs(userImage.top - localTop) > 1) updates.top = localTop;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (width !== undefined && userImage.width)
|
|
293
|
+
updates.scaleX = width / userImage.width;
|
|
294
|
+
if (height !== undefined && userImage.height)
|
|
295
|
+
updates.scaleY = height / userImage.height;
|
|
296
|
+
|
|
297
|
+
if (Object.keys(updates).length > 0) {
|
|
298
|
+
userImage.set(updates);
|
|
299
|
+
layer.dirty = true;
|
|
300
|
+
this.canvasService.requestRenderAll();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
this.loadImage(layer);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private loadImage(layer: any) {
|
|
309
|
+
if (!this.canvasService) return;
|
|
310
|
+
const { url } = this;
|
|
311
|
+
if (!url) return; // Don't load if empty
|
|
312
|
+
this._loadingUrl = url;
|
|
313
|
+
|
|
314
|
+
Image.fromURL(url, { crossOrigin: "anonymous" })
|
|
315
|
+
.then((image) => {
|
|
316
|
+
if (this._loadingUrl !== url) return;
|
|
317
|
+
this._loadingUrl = null;
|
|
318
|
+
|
|
319
|
+
let { opacity, width, height, angle, left, top } = this;
|
|
320
|
+
|
|
321
|
+
// Auto-scale and center if not set
|
|
322
|
+
if (this.context) {
|
|
323
|
+
const configService = this.context.services.get<ConfigurationService>(
|
|
324
|
+
"ConfigurationService",
|
|
325
|
+
)!;
|
|
326
|
+
const dielineWidth = configService.get("dieline.width");
|
|
327
|
+
const dielineHeight = configService.get("dieline.height");
|
|
328
|
+
|
|
329
|
+
console.log(
|
|
330
|
+
"[ImageTool] Dieline config debug:",
|
|
331
|
+
{
|
|
332
|
+
widthVal: dielineWidth,
|
|
333
|
+
heightVal: dielineHeight,
|
|
334
|
+
// Debug: dump all keys to see what is available
|
|
335
|
+
allKeys: Array.from(
|
|
336
|
+
(configService as any).configValues?.keys() || [],
|
|
337
|
+
),
|
|
338
|
+
},
|
|
339
|
+
configService,
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
if (width === undefined && height === undefined) {
|
|
343
|
+
// Scale to fit dieline
|
|
344
|
+
const scale = Math.min(
|
|
345
|
+
dielineWidth / (image.width || 1),
|
|
346
|
+
dielineHeight / (image.height || 1),
|
|
347
|
+
);
|
|
348
|
+
width = (image.width || 1) * scale;
|
|
349
|
+
height = (image.height || 1) * scale;
|
|
350
|
+
this.width = width;
|
|
351
|
+
this.height = height;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (left === undefined && top === undefined) {
|
|
355
|
+
// Default to Dieline Position if available, otherwise Center (0.5)
|
|
356
|
+
const dielinePos = configService?.get("dieline.position");
|
|
357
|
+
if (dielinePos) {
|
|
358
|
+
this.left = dielinePos.x;
|
|
359
|
+
this.top = dielinePos.y;
|
|
360
|
+
} else {
|
|
361
|
+
this.left = 0.5;
|
|
362
|
+
this.top = 0.5;
|
|
363
|
+
}
|
|
364
|
+
left = this.left;
|
|
365
|
+
top = this.top;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const existingImage = this.canvasService!.getObject(
|
|
370
|
+
"user-image",
|
|
371
|
+
"user",
|
|
372
|
+
) as any;
|
|
373
|
+
|
|
374
|
+
if (existingImage) {
|
|
375
|
+
const defaultLeft = existingImage.left;
|
|
376
|
+
const defaultTop = existingImage.top;
|
|
377
|
+
const defaultAngle = existingImage.angle;
|
|
378
|
+
const defaultScaleX = existingImage.scaleX;
|
|
379
|
+
const defaultScaleY = existingImage.scaleY;
|
|
380
|
+
|
|
381
|
+
const canvasW = this.canvasService?.canvas.width || 800;
|
|
382
|
+
const canvasH = this.canvasService?.canvas.height || 600;
|
|
383
|
+
const centerX = canvasW / 2;
|
|
384
|
+
const centerY = canvasH / 2;
|
|
385
|
+
|
|
386
|
+
let targetLeft = left !== undefined ? left : defaultLeft;
|
|
387
|
+
let targetTop = top !== undefined ? top : defaultTop;
|
|
388
|
+
|
|
389
|
+
// Log for debugging
|
|
390
|
+
const configService = this.context?.services.get<any>(
|
|
391
|
+
"ConfigurationService",
|
|
392
|
+
);
|
|
393
|
+
console.log("[ImageTool] Loading EXISTING image...", {
|
|
394
|
+
canvasW,
|
|
395
|
+
canvasH,
|
|
396
|
+
centerX,
|
|
397
|
+
centerY,
|
|
398
|
+
incomingLeft: left,
|
|
399
|
+
incomingTop: top,
|
|
400
|
+
dielinePos: configService?.get("dieline.position"),
|
|
401
|
+
existingImage: !!existingImage,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
if (left !== undefined) {
|
|
405
|
+
const globalLeft = Coordinate.toAbsolute(left, canvasW);
|
|
406
|
+
targetLeft = globalLeft; // Layer is absolute, do not subtract center
|
|
407
|
+
console.log("[ImageTool] Calculated targetLeft", {
|
|
408
|
+
globalLeft,
|
|
409
|
+
targetLeft,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
if (top !== undefined) {
|
|
413
|
+
const globalTop = Coordinate.toAbsolute(top, canvasH);
|
|
414
|
+
targetTop = globalTop; // Layer is absolute, do not subtract center
|
|
415
|
+
console.log("[ImageTool] Calculated targetTop", {
|
|
416
|
+
globalTop,
|
|
417
|
+
targetTop,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
image.set({
|
|
422
|
+
originX: "center", // Use center origin for easier positioning
|
|
423
|
+
originY: "center",
|
|
424
|
+
left: targetLeft,
|
|
425
|
+
top: targetTop,
|
|
426
|
+
angle: angle !== undefined ? angle : defaultAngle,
|
|
427
|
+
scaleX:
|
|
428
|
+
width !== undefined && image.width
|
|
429
|
+
? width / image.width
|
|
430
|
+
: defaultScaleX,
|
|
431
|
+
scaleY:
|
|
432
|
+
height !== undefined && image.height
|
|
433
|
+
? height / image.height
|
|
434
|
+
: defaultScaleY,
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
layer.remove(existingImage);
|
|
438
|
+
} else {
|
|
439
|
+
// New image
|
|
440
|
+
image.set({
|
|
441
|
+
originX: "center",
|
|
442
|
+
originY: "center",
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
if (width !== undefined && image.width)
|
|
446
|
+
image.scaleX = width / image.width;
|
|
447
|
+
if (height !== undefined && image.height)
|
|
448
|
+
image.scaleY = height / image.height;
|
|
449
|
+
if (angle !== undefined) image.angle = angle;
|
|
450
|
+
|
|
451
|
+
const canvasW = this.canvasService?.canvas.width || 800;
|
|
452
|
+
const canvasH = this.canvasService?.canvas.height || 600;
|
|
453
|
+
const centerX = canvasW / 2;
|
|
454
|
+
const centerY = canvasH / 2;
|
|
455
|
+
|
|
456
|
+
if (left !== undefined) {
|
|
457
|
+
image.left = Coordinate.toAbsolute(left, canvasW); // Layer is absolute
|
|
458
|
+
} else {
|
|
459
|
+
image.left = centerX; // Default to center of canvas
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (top !== undefined) {
|
|
463
|
+
image.top = Coordinate.toAbsolute(top, canvasH); // Layer is absolute
|
|
464
|
+
} else {
|
|
465
|
+
image.top = centerY; // Default to center of canvas
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
image.set({
|
|
470
|
+
opacity: opacity !== undefined ? opacity : 1,
|
|
471
|
+
data: {
|
|
472
|
+
id: "user-image",
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
layer.add(image);
|
|
476
|
+
|
|
477
|
+
// Bind events to keep options in sync
|
|
478
|
+
image.on("modified", (e: any) => {
|
|
479
|
+
const matrix = image.calcTransformMatrix();
|
|
480
|
+
const globalPoint = util.transformPoint(new Point(0, 0), matrix);
|
|
481
|
+
const canvasW = this.canvasService?.canvas.width || 800;
|
|
482
|
+
const canvasH = this.canvasService?.canvas.height || 600;
|
|
483
|
+
|
|
484
|
+
this.left = Coordinate.toNormalized(globalPoint.x, canvasW);
|
|
485
|
+
this.top = Coordinate.toNormalized(globalPoint.y, canvasH);
|
|
486
|
+
this.angle = e.target.angle;
|
|
487
|
+
|
|
488
|
+
if (image.width) this.width = e.target.width * e.target.scaleX;
|
|
489
|
+
if (image.height) this.height = e.target.height * e.target.scaleY;
|
|
490
|
+
|
|
491
|
+
if (this.context) {
|
|
492
|
+
this.context.eventBus.emit("update");
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
layer.dirty = true;
|
|
497
|
+
this.canvasService!.requestRenderAll();
|
|
498
|
+
})
|
|
499
|
+
.catch((err) => {
|
|
500
|
+
if (this._loadingUrl === url) this._loadingUrl = null;
|
|
501
|
+
console.error("Failed to load image", url, err);
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
1
|
+
export * from "./background";
|
|
2
|
+
export * from "./dieline";
|
|
3
|
+
export * from "./film";
|
|
4
|
+
export * from "./hole";
|
|
5
|
+
export * from "./image";
|
|
6
|
+
export * from "./white-ink";
|
|
7
|
+
export * from "./ruler";
|
|
8
|
+
export * from "./mirror";
|
|
9
|
+
export { default as CanvasService } from "./CanvasService";
|