@pooder/kit 4.1.0 → 4.2.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/.test-dist/src/CanvasService.js +83 -0
- package/.test-dist/src/ViewportSystem.js +75 -0
- package/.test-dist/src/background.js +203 -0
- package/.test-dist/src/constraints.js +153 -0
- package/.test-dist/src/coordinate.js +74 -0
- package/.test-dist/src/dieline.js +758 -0
- package/.test-dist/src/feature.js +687 -0
- package/.test-dist/src/featureComplete.js +31 -0
- package/.test-dist/src/featureDraft.js +31 -0
- package/.test-dist/src/film.js +167 -0
- package/.test-dist/src/geometry.js +292 -0
- package/.test-dist/src/image.js +421 -0
- package/.test-dist/src/index.js +31 -0
- package/.test-dist/src/mirror.js +104 -0
- package/.test-dist/src/ruler.js +383 -0
- package/.test-dist/src/tracer.js +448 -0
- package/.test-dist/src/units.js +30 -0
- package/.test-dist/src/white-ink.js +310 -0
- package/.test-dist/tests/run.js +60 -0
- package/CHANGELOG.md +6 -0
- package/dist/index.d.mts +50 -5
- package/dist/index.d.ts +50 -5
- package/dist/index.js +544 -297
- package/dist/index.mjs +541 -296
- package/package.json +3 -2
- package/src/CanvasService.ts +7 -0
- package/src/ViewportSystem.ts +92 -0
- package/src/constraints.ts +53 -4
- package/src/dieline.ts +169 -85
- package/src/feature.ts +217 -150
- package/src/featureComplete.ts +45 -0
- package/src/index.ts +1 -0
- package/src/ruler.ts +26 -18
- package/src/units.ts +27 -0
- package/tests/run.ts +81 -0
- package/tsconfig.test.json +15 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ImageTool = void 0;
|
|
4
|
+
const core_1 = require("@pooder/core");
|
|
5
|
+
const fabric_1 = require("fabric");
|
|
6
|
+
class ImageTool {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.id = "pooder.kit.image";
|
|
9
|
+
this.metadata = {
|
|
10
|
+
name: "ImageTool",
|
|
11
|
+
};
|
|
12
|
+
this.items = [];
|
|
13
|
+
this.objectMap = new Map();
|
|
14
|
+
this.loadResolvers = new Map();
|
|
15
|
+
this.isUpdatingConfig = false;
|
|
16
|
+
this.isToolActive = false;
|
|
17
|
+
this.onToolActivated = (event) => {
|
|
18
|
+
this.isToolActive = event.id === this.id;
|
|
19
|
+
this.updateInteractivity();
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
activate(context) {
|
|
23
|
+
this.context = context;
|
|
24
|
+
this.canvasService = context.services.get("CanvasService");
|
|
25
|
+
if (!this.canvasService) {
|
|
26
|
+
console.warn("CanvasService not found for ImageTool");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Listen to tool activation
|
|
30
|
+
context.eventBus.on("tool:activated", this.onToolActivated);
|
|
31
|
+
const configService = context.services.get("ConfigurationService");
|
|
32
|
+
if (configService) {
|
|
33
|
+
// Load initial config
|
|
34
|
+
this.items = configService.get("image.items", []) || [];
|
|
35
|
+
// Listen for changes
|
|
36
|
+
configService.onAnyChange((e) => {
|
|
37
|
+
if (this.isUpdatingConfig)
|
|
38
|
+
return;
|
|
39
|
+
if (e.key === "image.items") {
|
|
40
|
+
this.items = e.value || [];
|
|
41
|
+
this.updateImages();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
this.ensureLayer();
|
|
46
|
+
this.updateImages();
|
|
47
|
+
}
|
|
48
|
+
deactivate(context) {
|
|
49
|
+
context.eventBus.off("tool:activated", this.onToolActivated);
|
|
50
|
+
if (this.canvasService) {
|
|
51
|
+
const layer = this.canvasService.getLayer("user");
|
|
52
|
+
if (layer) {
|
|
53
|
+
this.objectMap.forEach((obj) => {
|
|
54
|
+
layer.remove(obj);
|
|
55
|
+
});
|
|
56
|
+
this.objectMap.clear();
|
|
57
|
+
this.canvasService.requestRenderAll();
|
|
58
|
+
}
|
|
59
|
+
this.canvasService = undefined;
|
|
60
|
+
this.context = undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
updateInteractivity() {
|
|
64
|
+
this.objectMap.forEach((obj) => {
|
|
65
|
+
obj.set({
|
|
66
|
+
selectable: this.isToolActive,
|
|
67
|
+
evented: this.isToolActive,
|
|
68
|
+
hasControls: this.isToolActive,
|
|
69
|
+
hasBorders: this.isToolActive,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
this.canvasService?.requestRenderAll();
|
|
73
|
+
}
|
|
74
|
+
contribute() {
|
|
75
|
+
return {
|
|
76
|
+
[core_1.ContributionPointIds.CONFIGURATIONS]: [
|
|
77
|
+
{
|
|
78
|
+
id: "image.items",
|
|
79
|
+
type: "array",
|
|
80
|
+
label: "Images",
|
|
81
|
+
default: [],
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
[core_1.ContributionPointIds.COMMANDS]: [
|
|
85
|
+
{
|
|
86
|
+
command: "addImage",
|
|
87
|
+
title: "Add Image",
|
|
88
|
+
handler: async (url, options) => {
|
|
89
|
+
const id = this.generateId();
|
|
90
|
+
const newItem = {
|
|
91
|
+
id,
|
|
92
|
+
url,
|
|
93
|
+
opacity: 1,
|
|
94
|
+
...options,
|
|
95
|
+
};
|
|
96
|
+
const promise = new Promise((resolve) => {
|
|
97
|
+
this.loadResolvers.set(id, () => resolve(id));
|
|
98
|
+
});
|
|
99
|
+
this.updateConfig([...this.items, newItem]);
|
|
100
|
+
return promise;
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
command: "fitImageToArea",
|
|
105
|
+
title: "Fit Image to Area",
|
|
106
|
+
handler: (id, area) => {
|
|
107
|
+
const item = this.items.find((i) => i.id === id);
|
|
108
|
+
const obj = this.objectMap.get(id);
|
|
109
|
+
if (item && obj && obj.width && obj.height) {
|
|
110
|
+
const scale = Math.max(area.width / obj.width, area.height / obj.height);
|
|
111
|
+
this.updateImageInConfig(id, {
|
|
112
|
+
scale,
|
|
113
|
+
left: area.left ?? 0.5,
|
|
114
|
+
top: area.top ?? 0.5,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
command: "removeImage",
|
|
121
|
+
title: "Remove Image",
|
|
122
|
+
handler: (id) => {
|
|
123
|
+
const newItems = this.items.filter((item) => item.id !== id);
|
|
124
|
+
if (newItems.length !== this.items.length) {
|
|
125
|
+
this.updateConfig(newItems);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
command: "updateImage",
|
|
131
|
+
title: "Update Image",
|
|
132
|
+
handler: (id, updates) => {
|
|
133
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
134
|
+
if (index !== -1) {
|
|
135
|
+
const newItems = [...this.items];
|
|
136
|
+
newItems[index] = { ...newItems[index], ...updates };
|
|
137
|
+
this.updateConfig(newItems);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
command: "clearImages",
|
|
143
|
+
title: "Clear Images",
|
|
144
|
+
handler: () => {
|
|
145
|
+
this.updateConfig([]);
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
command: "bringToFront",
|
|
150
|
+
title: "Bring Image to Front",
|
|
151
|
+
handler: (id) => {
|
|
152
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
153
|
+
if (index !== -1 && index < this.items.length - 1) {
|
|
154
|
+
const newItems = [...this.items];
|
|
155
|
+
const [item] = newItems.splice(index, 1);
|
|
156
|
+
newItems.push(item);
|
|
157
|
+
this.updateConfig(newItems);
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
command: "sendToBack",
|
|
163
|
+
title: "Send Image to Back",
|
|
164
|
+
handler: (id) => {
|
|
165
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
166
|
+
if (index > 0) {
|
|
167
|
+
const newItems = [...this.items];
|
|
168
|
+
const [item] = newItems.splice(index, 1);
|
|
169
|
+
newItems.unshift(item);
|
|
170
|
+
this.updateConfig(newItems);
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
generateId() {
|
|
178
|
+
return Math.random().toString(36).substring(2, 9);
|
|
179
|
+
}
|
|
180
|
+
updateConfig(newItems, skipCanvasUpdate = false) {
|
|
181
|
+
if (!this.context)
|
|
182
|
+
return;
|
|
183
|
+
this.isUpdatingConfig = true;
|
|
184
|
+
this.items = newItems;
|
|
185
|
+
const configService = this.context.services.get("ConfigurationService");
|
|
186
|
+
if (configService) {
|
|
187
|
+
configService.update("image.items", newItems);
|
|
188
|
+
}
|
|
189
|
+
// Update canvas immediately to reflect changes locally before config event comes back
|
|
190
|
+
// (Optional, but good for responsiveness)
|
|
191
|
+
if (!skipCanvasUpdate) {
|
|
192
|
+
this.updateImages();
|
|
193
|
+
}
|
|
194
|
+
// Reset flag after a short delay to allow config propagation
|
|
195
|
+
setTimeout(() => {
|
|
196
|
+
this.isUpdatingConfig = false;
|
|
197
|
+
}, 50);
|
|
198
|
+
}
|
|
199
|
+
ensureLayer() {
|
|
200
|
+
if (!this.canvasService)
|
|
201
|
+
return;
|
|
202
|
+
let userLayer = this.canvasService.getLayer("user");
|
|
203
|
+
if (!userLayer) {
|
|
204
|
+
userLayer = this.canvasService.createLayer("user", {
|
|
205
|
+
width: this.canvasService.canvas.width,
|
|
206
|
+
height: this.canvasService.canvas.height,
|
|
207
|
+
left: 0,
|
|
208
|
+
top: 0,
|
|
209
|
+
originX: "left",
|
|
210
|
+
originY: "top",
|
|
211
|
+
selectable: false,
|
|
212
|
+
evented: true,
|
|
213
|
+
subTargetCheck: true,
|
|
214
|
+
interactive: true,
|
|
215
|
+
});
|
|
216
|
+
// Try to insert below dieline-overlay
|
|
217
|
+
const dielineLayer = this.canvasService.getLayer("dieline-overlay");
|
|
218
|
+
if (dielineLayer) {
|
|
219
|
+
const index = this.canvasService.canvas
|
|
220
|
+
.getObjects()
|
|
221
|
+
.indexOf(dielineLayer);
|
|
222
|
+
// If dieline is at 0, move user to 0 (dieline shifts to 1)
|
|
223
|
+
if (index >= 0) {
|
|
224
|
+
this.canvasService.canvas.moveObjectTo(userLayer, index);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
// Ensure background is behind
|
|
229
|
+
const bgLayer = this.canvasService.getLayer("background");
|
|
230
|
+
if (bgLayer) {
|
|
231
|
+
this.canvasService.canvas.sendObjectToBack(bgLayer);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
this.canvasService.requestRenderAll();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
getLayoutInfo() {
|
|
238
|
+
const canvasW = this.canvasService?.canvas.width || 800;
|
|
239
|
+
const canvasH = this.canvasService?.canvas.height || 600;
|
|
240
|
+
return {
|
|
241
|
+
layoutScale: 1,
|
|
242
|
+
layoutOffsetX: 0,
|
|
243
|
+
layoutOffsetY: 0,
|
|
244
|
+
visualWidth: canvasW,
|
|
245
|
+
visualHeight: canvasH,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
updateImages() {
|
|
249
|
+
if (!this.canvasService)
|
|
250
|
+
return;
|
|
251
|
+
const layer = this.canvasService.getLayer("user");
|
|
252
|
+
if (!layer) {
|
|
253
|
+
console.warn("[ImageTool] User layer not found");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
// 1. Remove objects that are no longer in items
|
|
257
|
+
const currentIds = new Set(this.items.map((i) => i.id));
|
|
258
|
+
for (const [id, obj] of this.objectMap) {
|
|
259
|
+
if (!currentIds.has(id)) {
|
|
260
|
+
layer.remove(obj);
|
|
261
|
+
this.objectMap.delete(id);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// 2. Add or Update objects
|
|
265
|
+
const layout = this.getLayoutInfo();
|
|
266
|
+
this.items.forEach((item, index) => {
|
|
267
|
+
let obj = this.objectMap.get(item.id);
|
|
268
|
+
// Check if URL changed, if so remove object to force reload
|
|
269
|
+
// We assume Fabric object has getSrc() or we check data.url if we stored it
|
|
270
|
+
// Since we don't store url on object easily accessible without casting,
|
|
271
|
+
// let's rely on checking if we need to reload.
|
|
272
|
+
// Actually, standard Fabric Image doesn't expose src easily on type without casting to any.
|
|
273
|
+
if (obj && obj.getSrc) {
|
|
274
|
+
const currentSrc = obj.getSrc();
|
|
275
|
+
if (currentSrc !== item.url) {
|
|
276
|
+
layer.remove(obj);
|
|
277
|
+
this.objectMap.delete(item.id);
|
|
278
|
+
obj = undefined;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (!obj) {
|
|
282
|
+
// New object, load it
|
|
283
|
+
this.loadImage(item, layer, layout);
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
// Existing object, update properties
|
|
287
|
+
// We remove and re-add to ensure coordinates are correctly converted
|
|
288
|
+
// from absolute (updateObjectProperties) to relative (layer.add)
|
|
289
|
+
layer.remove(obj);
|
|
290
|
+
this.updateObjectProperties(obj, item, layout);
|
|
291
|
+
layer.add(obj);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
layer.dirty = true;
|
|
295
|
+
this.canvasService.requestRenderAll();
|
|
296
|
+
}
|
|
297
|
+
updateObjectProperties(obj, item, layout) {
|
|
298
|
+
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, } = layout;
|
|
299
|
+
const updates = {};
|
|
300
|
+
// Opacity
|
|
301
|
+
if (obj.opacity !== item.opacity)
|
|
302
|
+
updates.opacity = item.opacity;
|
|
303
|
+
// Angle
|
|
304
|
+
if (item.angle !== undefined && obj.angle !== item.angle)
|
|
305
|
+
updates.angle = item.angle;
|
|
306
|
+
// Position (Normalized -> Absolute)
|
|
307
|
+
if (item.left !== undefined) {
|
|
308
|
+
const globalLeft = layoutOffsetX + item.left * visualWidth;
|
|
309
|
+
if (Math.abs(obj.left - globalLeft) > 1)
|
|
310
|
+
updates.left = globalLeft;
|
|
311
|
+
}
|
|
312
|
+
if (item.top !== undefined) {
|
|
313
|
+
const globalTop = layoutOffsetY + item.top * visualHeight;
|
|
314
|
+
if (Math.abs(obj.top - globalTop) > 1)
|
|
315
|
+
updates.top = globalTop;
|
|
316
|
+
}
|
|
317
|
+
// Scale
|
|
318
|
+
if (item.scale !== undefined) {
|
|
319
|
+
const targetScale = item.scale * layoutScale;
|
|
320
|
+
if (Math.abs(obj.scaleX - targetScale) > 0.001) {
|
|
321
|
+
updates.scaleX = targetScale;
|
|
322
|
+
updates.scaleY = targetScale;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// Center origin if not set
|
|
326
|
+
if (obj.originX !== "center") {
|
|
327
|
+
updates.originX = "center";
|
|
328
|
+
updates.originY = "center";
|
|
329
|
+
// Adjust position because origin changed (Fabric logic)
|
|
330
|
+
// For simplicity, we just set it, next cycle will fix pos if needed,
|
|
331
|
+
// or we can calculate the shift. Ideally we set origin on creation.
|
|
332
|
+
}
|
|
333
|
+
if (Object.keys(updates).length > 0) {
|
|
334
|
+
obj.set(updates);
|
|
335
|
+
obj.setCoords();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
loadImage(item, layer, layout) {
|
|
339
|
+
fabric_1.Image.fromURL(item.url, { crossOrigin: "anonymous" })
|
|
340
|
+
.then((image) => {
|
|
341
|
+
// Double check if item still exists
|
|
342
|
+
if (!this.items.find((i) => i.id === item.id))
|
|
343
|
+
return;
|
|
344
|
+
image.set({
|
|
345
|
+
originX: "center",
|
|
346
|
+
originY: "center",
|
|
347
|
+
data: { id: item.id },
|
|
348
|
+
uniformScaling: true,
|
|
349
|
+
lockScalingFlip: true,
|
|
350
|
+
selectable: this.isToolActive,
|
|
351
|
+
evented: this.isToolActive,
|
|
352
|
+
hasControls: this.isToolActive,
|
|
353
|
+
hasBorders: this.isToolActive,
|
|
354
|
+
});
|
|
355
|
+
image.setControlsVisibility({
|
|
356
|
+
mt: false,
|
|
357
|
+
mb: false,
|
|
358
|
+
ml: false,
|
|
359
|
+
mr: false,
|
|
360
|
+
});
|
|
361
|
+
// Initial Layout
|
|
362
|
+
let { scale, left, top } = item;
|
|
363
|
+
if (scale === undefined) {
|
|
364
|
+
scale = 1; // Default scale if not provided and not fitted yet
|
|
365
|
+
item.scale = scale;
|
|
366
|
+
}
|
|
367
|
+
if (left === undefined && top === undefined) {
|
|
368
|
+
left = 0.5;
|
|
369
|
+
top = 0.5;
|
|
370
|
+
item.left = left;
|
|
371
|
+
item.top = top;
|
|
372
|
+
}
|
|
373
|
+
// Apply Props
|
|
374
|
+
this.updateObjectProperties(image, item, layout);
|
|
375
|
+
layer.add(image);
|
|
376
|
+
this.objectMap.set(item.id, image);
|
|
377
|
+
// Notify addImage that load is complete
|
|
378
|
+
const resolver = this.loadResolvers.get(item.id);
|
|
379
|
+
if (resolver) {
|
|
380
|
+
resolver();
|
|
381
|
+
this.loadResolvers.delete(item.id);
|
|
382
|
+
}
|
|
383
|
+
// Bind Events
|
|
384
|
+
image.on("modified", (e) => {
|
|
385
|
+
this.handleObjectModified(item.id, image);
|
|
386
|
+
});
|
|
387
|
+
layer.dirty = true;
|
|
388
|
+
this.canvasService?.requestRenderAll();
|
|
389
|
+
// Save defaults if we set them
|
|
390
|
+
if (item.scale !== scale || item.left !== left || item.top !== top) {
|
|
391
|
+
this.updateImageInConfig(item.id, { scale, left, top }, true);
|
|
392
|
+
}
|
|
393
|
+
})
|
|
394
|
+
.catch((err) => {
|
|
395
|
+
console.error("Failed to load image", item.url, err);
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
handleObjectModified(id, image) {
|
|
399
|
+
const layout = this.getLayoutInfo();
|
|
400
|
+
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, } = layout;
|
|
401
|
+
const matrix = image.calcTransformMatrix();
|
|
402
|
+
const globalPoint = fabric_1.util.transformPoint(new fabric_1.Point(0, 0), matrix);
|
|
403
|
+
const updates = {};
|
|
404
|
+
// Normalize Position
|
|
405
|
+
updates.left = (globalPoint.x - layoutOffsetX) / visualWidth;
|
|
406
|
+
updates.top = (globalPoint.y - layoutOffsetY) / visualHeight;
|
|
407
|
+
updates.angle = image.angle;
|
|
408
|
+
// Scale
|
|
409
|
+
updates.scale = image.scaleX / layoutScale;
|
|
410
|
+
this.updateImageInConfig(id, updates, true);
|
|
411
|
+
}
|
|
412
|
+
updateImageInConfig(id, updates, skipCanvasUpdate = false) {
|
|
413
|
+
const index = this.items.findIndex((i) => i.id === id);
|
|
414
|
+
if (index !== -1) {
|
|
415
|
+
const newItems = [...this.items];
|
|
416
|
+
newItems[index] = { ...newItems[index], ...updates };
|
|
417
|
+
this.updateConfig(newItems, skipCanvasUpdate);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
exports.ImageTool = ImageTool;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.CanvasService = void 0;
|
|
21
|
+
__exportStar(require("./background"), exports);
|
|
22
|
+
__exportStar(require("./dieline"), exports);
|
|
23
|
+
__exportStar(require("./film"), exports);
|
|
24
|
+
__exportStar(require("./feature"), exports);
|
|
25
|
+
__exportStar(require("./image"), exports);
|
|
26
|
+
__exportStar(require("./white-ink"), exports);
|
|
27
|
+
__exportStar(require("./ruler"), exports);
|
|
28
|
+
__exportStar(require("./mirror"), exports);
|
|
29
|
+
__exportStar(require("./units"), exports);
|
|
30
|
+
var CanvasService_1 = require("./CanvasService");
|
|
31
|
+
Object.defineProperty(exports, "CanvasService", { enumerable: true, get: function () { return __importDefault(CanvasService_1).default; } });
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MirrorTool = void 0;
|
|
4
|
+
const core_1 = require("@pooder/core");
|
|
5
|
+
class MirrorTool {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.id = "pooder.kit.mirror";
|
|
8
|
+
this.metadata = {
|
|
9
|
+
name: "MirrorTool",
|
|
10
|
+
};
|
|
11
|
+
this.enabled = false;
|
|
12
|
+
if (options) {
|
|
13
|
+
Object.assign(this, options);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
toJSON() {
|
|
17
|
+
return {
|
|
18
|
+
enabled: this.enabled,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
loadFromJSON(json) {
|
|
22
|
+
this.enabled = json.enabled;
|
|
23
|
+
}
|
|
24
|
+
activate(context) {
|
|
25
|
+
this.canvasService = context.services.get("CanvasService");
|
|
26
|
+
if (!this.canvasService) {
|
|
27
|
+
console.warn("CanvasService not found for MirrorTool");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const configService = context.services.get("ConfigurationService");
|
|
31
|
+
if (configService) {
|
|
32
|
+
// Load initial config
|
|
33
|
+
this.enabled = configService.get("mirror.enabled", this.enabled);
|
|
34
|
+
// Listen for changes
|
|
35
|
+
configService.onAnyChange((e) => {
|
|
36
|
+
if (e.key === "mirror.enabled") {
|
|
37
|
+
this.applyMirror(e.value);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// Initialize with current state (if enabled was persisted)
|
|
42
|
+
if (this.enabled) {
|
|
43
|
+
this.applyMirror(true);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
deactivate(context) {
|
|
47
|
+
this.applyMirror(false);
|
|
48
|
+
this.canvasService = undefined;
|
|
49
|
+
}
|
|
50
|
+
contribute() {
|
|
51
|
+
return {
|
|
52
|
+
[core_1.ContributionPointIds.CONFIGURATIONS]: [
|
|
53
|
+
{
|
|
54
|
+
id: "mirror.enabled",
|
|
55
|
+
type: "boolean",
|
|
56
|
+
label: "Enable Mirror",
|
|
57
|
+
default: false,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
[core_1.ContributionPointIds.COMMANDS]: [
|
|
61
|
+
{
|
|
62
|
+
command: "setMirror",
|
|
63
|
+
title: "Set Mirror",
|
|
64
|
+
handler: (enabled) => {
|
|
65
|
+
this.applyMirror(enabled);
|
|
66
|
+
return true;
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
applyMirror(enabled) {
|
|
73
|
+
if (!this.canvasService)
|
|
74
|
+
return;
|
|
75
|
+
const canvas = this.canvasService.canvas;
|
|
76
|
+
if (!canvas)
|
|
77
|
+
return;
|
|
78
|
+
const width = canvas.width || 800;
|
|
79
|
+
// Fabric.js v6+ uses viewportTransform property
|
|
80
|
+
let vpt = canvas.viewportTransform || [1, 0, 0, 1, 0, 0];
|
|
81
|
+
// Create a copy to avoid mutating the reference directly before setting
|
|
82
|
+
vpt = [...vpt];
|
|
83
|
+
// If we are enabling and currently not flipped (scaleX > 0)
|
|
84
|
+
// Or disabling and currently flipped (scaleX < 0)
|
|
85
|
+
const isFlipped = vpt[0] < 0;
|
|
86
|
+
if (enabled && !isFlipped) {
|
|
87
|
+
// Flip scale X
|
|
88
|
+
vpt[0] = -vpt[0]; // Flip scale
|
|
89
|
+
vpt[4] = width - vpt[4]; // Adjust pan X
|
|
90
|
+
canvas.setViewportTransform(vpt);
|
|
91
|
+
canvas.requestRenderAll();
|
|
92
|
+
this.enabled = true;
|
|
93
|
+
}
|
|
94
|
+
else if (!enabled && isFlipped) {
|
|
95
|
+
// Restore
|
|
96
|
+
vpt[0] = -vpt[0]; // Unflip scale
|
|
97
|
+
vpt[4] = width - vpt[4]; // Restore pan X
|
|
98
|
+
canvas.setViewportTransform(vpt);
|
|
99
|
+
canvas.requestRenderAll();
|
|
100
|
+
this.enabled = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
exports.MirrorTool = MirrorTool;
|