@pooder/kit 3.4.0 → 4.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 +17 -0
- package/dist/index.d.mts +62 -56
- package/dist/index.d.ts +62 -56
- package/dist/index.js +978 -862
- package/dist/index.mjs +977 -861
- package/package.json +2 -2
- package/src/CanvasService.ts +25 -1
- package/src/background.ts +230 -230
- package/src/coordinate.ts +106 -106
- package/src/dieline.ts +272 -218
- package/src/feature.ts +767 -0
- package/src/film.ts +194 -194
- package/src/geometry.ts +172 -375
- package/src/image.ts +512 -471
- package/src/index.ts +1 -1
- package/src/mirror.ts +128 -128
- package/src/ruler.ts +500 -500
- package/src/tracer.ts +570 -486
- package/src/white-ink.ts +373 -373
- package/src/hole.ts +0 -786
package/dist/index.js
CHANGED
|
@@ -33,8 +33,8 @@ __export(index_exports, {
|
|
|
33
33
|
BackgroundTool: () => BackgroundTool,
|
|
34
34
|
CanvasService: () => CanvasService,
|
|
35
35
|
DielineTool: () => DielineTool,
|
|
36
|
+
FeatureTool: () => FeatureTool,
|
|
36
37
|
FilmTool: () => FilmTool,
|
|
37
|
-
HoleTool: () => HoleTool,
|
|
38
38
|
ImageTool: () => ImageTool,
|
|
39
39
|
MirrorTool: () => MirrorTool,
|
|
40
40
|
RulerTool: () => RulerTool,
|
|
@@ -248,6 +248,7 @@ var import_core2 = require("@pooder/core");
|
|
|
248
248
|
var import_fabric2 = require("fabric");
|
|
249
249
|
|
|
250
250
|
// src/tracer.ts
|
|
251
|
+
var import_paper = __toESM(require("paper"));
|
|
251
252
|
var ImageTracer = class {
|
|
252
253
|
/**
|
|
253
254
|
* Main entry point: Traces an image URL to an SVG path string.
|
|
@@ -255,7 +256,7 @@ var ImageTracer = class {
|
|
|
255
256
|
* @param options Configuration options.
|
|
256
257
|
*/
|
|
257
258
|
static async trace(imageUrl, options = {}) {
|
|
258
|
-
var _a, _b, _c, _d, _e;
|
|
259
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
259
260
|
const img = await this.loadImage(imageUrl);
|
|
260
261
|
const width = img.width;
|
|
261
262
|
const height = img.height;
|
|
@@ -272,23 +273,37 @@ var ImageTracer = class {
|
|
|
272
273
|
Math.floor(Math.max(width, height) * 0.02)
|
|
273
274
|
);
|
|
274
275
|
const radius = (_b = options.morphologyRadius) != null ? _b : adaptiveRadius;
|
|
275
|
-
|
|
276
|
+
const expand = (_c = options.expand) != null ? _c : 0;
|
|
277
|
+
const padding = radius + expand + 2;
|
|
278
|
+
const paddedWidth = width + padding * 2;
|
|
279
|
+
const paddedHeight = height + padding * 2;
|
|
280
|
+
let mask = this.createMask(imageData, threshold, padding, paddedWidth, paddedHeight);
|
|
276
281
|
if (radius > 0) {
|
|
277
|
-
mask = this.
|
|
278
|
-
mask = this.
|
|
279
|
-
|
|
282
|
+
mask = this.circularMorphology(mask, paddedWidth, paddedHeight, radius, "closing");
|
|
283
|
+
mask = this.fillHoles(mask, paddedWidth, paddedHeight);
|
|
284
|
+
const smoothRadius = Math.max(2, Math.floor(radius * 0.3));
|
|
285
|
+
mask = this.circularMorphology(mask, paddedWidth, paddedHeight, smoothRadius, "closing");
|
|
286
|
+
} else {
|
|
287
|
+
mask = this.fillHoles(mask, paddedWidth, paddedHeight);
|
|
288
|
+
}
|
|
289
|
+
if (expand > 0) {
|
|
290
|
+
mask = this.circularMorphology(mask, paddedWidth, paddedHeight, expand, "dilate");
|
|
280
291
|
}
|
|
281
|
-
const allContourPoints = this.traceAllContours(mask,
|
|
292
|
+
const allContourPoints = this.traceAllContours(mask, paddedWidth, paddedHeight);
|
|
282
293
|
if (allContourPoints.length === 0) {
|
|
283
|
-
const w = (
|
|
284
|
-
const h = (
|
|
294
|
+
const w = (_d = options.scaleToWidth) != null ? _d : width;
|
|
295
|
+
const h = (_e = options.scaleToHeight) != null ? _e : height;
|
|
285
296
|
return `M 0 0 L ${w} 0 L ${w} ${h} L 0 ${h} Z`;
|
|
286
297
|
}
|
|
287
298
|
const primaryContour = allContourPoints.sort(
|
|
288
299
|
(a, b) => b.length - a.length
|
|
289
300
|
)[0];
|
|
301
|
+
const unpaddedPoints = primaryContour.map((p) => ({
|
|
302
|
+
x: p.x - padding,
|
|
303
|
+
y: p.y - padding
|
|
304
|
+
}));
|
|
290
305
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
291
|
-
for (const p of
|
|
306
|
+
for (const p of unpaddedPoints) {
|
|
292
307
|
if (p.x < minX) minX = p.x;
|
|
293
308
|
if (p.y < minY) minY = p.y;
|
|
294
309
|
if (p.x > maxX) maxX = p.x;
|
|
@@ -300,95 +315,119 @@ var ImageTracer = class {
|
|
|
300
315
|
width: maxX - minX,
|
|
301
316
|
height: maxY - minY
|
|
302
317
|
};
|
|
303
|
-
let finalPoints =
|
|
318
|
+
let finalPoints = unpaddedPoints;
|
|
304
319
|
if (options.scaleToWidth && options.scaleToHeight) {
|
|
305
320
|
finalPoints = this.scalePoints(
|
|
306
|
-
|
|
321
|
+
unpaddedPoints,
|
|
307
322
|
options.scaleToWidth,
|
|
308
323
|
options.scaleToHeight,
|
|
309
324
|
globalBounds
|
|
310
325
|
);
|
|
311
326
|
}
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
(
|
|
315
|
-
|
|
316
|
-
|
|
327
|
+
const useSmoothing = options.smoothing !== false;
|
|
328
|
+
if (useSmoothing) {
|
|
329
|
+
return this.pointsToSVGPaper(finalPoints, (_f = options.simplifyTolerance) != null ? _f : 2.5);
|
|
330
|
+
} else {
|
|
331
|
+
const simplifiedPoints = this.douglasPeucker(
|
|
332
|
+
finalPoints,
|
|
333
|
+
(_g = options.simplifyTolerance) != null ? _g : 2
|
|
334
|
+
);
|
|
335
|
+
return this.pointsToSVG(simplifiedPoints);
|
|
336
|
+
}
|
|
317
337
|
}
|
|
318
|
-
static createMask(imageData, threshold) {
|
|
338
|
+
static createMask(imageData, threshold, padding, paddedWidth, paddedHeight) {
|
|
319
339
|
const { width, height, data } = imageData;
|
|
320
|
-
const mask = new Uint8Array(
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const a = data[idx + 3];
|
|
327
|
-
if (a > threshold && !(r > 240 && g > 240 && b > 240)) {
|
|
328
|
-
mask[i] = 1;
|
|
329
|
-
} else {
|
|
330
|
-
mask[i] = 0;
|
|
340
|
+
const mask = new Uint8Array(paddedWidth * paddedHeight);
|
|
341
|
+
let hasTransparency = false;
|
|
342
|
+
for (let i = 3; i < data.length; i += 4) {
|
|
343
|
+
if (data[i] < 255) {
|
|
344
|
+
hasTransparency = true;
|
|
345
|
+
break;
|
|
331
346
|
}
|
|
332
347
|
}
|
|
333
|
-
return mask;
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Fast 1D-separable Dilation
|
|
337
|
-
*/
|
|
338
|
-
static dilate(mask, width, height, radius) {
|
|
339
|
-
const horizontal = new Uint8Array(width * height);
|
|
340
348
|
for (let y = 0; y < height; y++) {
|
|
341
|
-
let
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
349
|
+
for (let x = 0; x < width; x++) {
|
|
350
|
+
const srcIdx = (y * width + x) * 4;
|
|
351
|
+
const r = data[srcIdx];
|
|
352
|
+
const g = data[srcIdx + 1];
|
|
353
|
+
const b = data[srcIdx + 2];
|
|
354
|
+
const a = data[srcIdx + 3];
|
|
355
|
+
const destIdx = (y + padding) * paddedWidth + (x + padding);
|
|
356
|
+
if (hasTransparency) {
|
|
357
|
+
if (a > threshold) {
|
|
358
|
+
mask[destIdx] = 1;
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
if (!(r > 240 && g > 240 && b > 240)) {
|
|
362
|
+
mask[destIdx] = 1;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
357
365
|
}
|
|
358
366
|
}
|
|
359
|
-
return
|
|
367
|
+
return mask;
|
|
360
368
|
}
|
|
361
369
|
/**
|
|
362
|
-
* Fast
|
|
370
|
+
* Fast circular morphology using a distance-transform inspired separable approach.
|
|
371
|
+
* O(N * R) complexity, where R is the radius.
|
|
363
372
|
*/
|
|
364
|
-
static
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
let
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
373
|
+
static circularMorphology(mask, width, height, radius, op) {
|
|
374
|
+
const dilate = (m, r) => {
|
|
375
|
+
const horizontalDist = new Int32Array(width * height);
|
|
376
|
+
for (let y = 0; y < height; y++) {
|
|
377
|
+
let lastSolid = -r * 2;
|
|
378
|
+
for (let x = 0; x < width; x++) {
|
|
379
|
+
if (m[y * width + x]) lastSolid = x;
|
|
380
|
+
horizontalDist[y * width + x] = x - lastSolid;
|
|
381
|
+
}
|
|
382
|
+
lastSolid = width + r * 2;
|
|
383
|
+
for (let x = width - 1; x >= 0; x--) {
|
|
384
|
+
if (m[y * width + x]) lastSolid = x;
|
|
385
|
+
horizontalDist[y * width + x] = Math.min(
|
|
386
|
+
horizontalDist[y * width + x],
|
|
387
|
+
lastSolid - x
|
|
388
|
+
);
|
|
374
389
|
}
|
|
375
390
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
391
|
+
const result = new Uint8Array(width * height);
|
|
392
|
+
const r2 = r * r;
|
|
393
|
+
for (let x = 0; x < width; x++) {
|
|
394
|
+
for (let y = 0; y < height; y++) {
|
|
395
|
+
let found = false;
|
|
396
|
+
const minY = Math.max(0, y - r);
|
|
397
|
+
const maxY = Math.min(height - 1, y + r);
|
|
398
|
+
for (let dy = minY; dy <= maxY; dy++) {
|
|
399
|
+
const dY = dy - y;
|
|
400
|
+
const hDist = horizontalDist[dy * width + x];
|
|
401
|
+
if (hDist * hDist + dY * dY <= r2) {
|
|
402
|
+
found = true;
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (found) result[y * width + x] = 1;
|
|
388
407
|
}
|
|
389
408
|
}
|
|
409
|
+
return result;
|
|
410
|
+
};
|
|
411
|
+
const erode = (m, r) => {
|
|
412
|
+
const inverted = new Uint8Array(m.length);
|
|
413
|
+
for (let i = 0; i < m.length; i++) inverted[i] = m[i] ? 0 : 1;
|
|
414
|
+
const dilatedInverted = dilate(inverted, r);
|
|
415
|
+
const result = new Uint8Array(m.length);
|
|
416
|
+
for (let i = 0; i < m.length; i++) result[i] = dilatedInverted[i] ? 0 : 1;
|
|
417
|
+
return result;
|
|
418
|
+
};
|
|
419
|
+
switch (op) {
|
|
420
|
+
case "dilate":
|
|
421
|
+
return dilate(mask, radius);
|
|
422
|
+
case "erode":
|
|
423
|
+
return erode(mask, radius);
|
|
424
|
+
case "closing":
|
|
425
|
+
return erode(dilate(mask, radius), radius);
|
|
426
|
+
case "opening":
|
|
427
|
+
return dilate(erode(mask, radius), radius);
|
|
428
|
+
default:
|
|
429
|
+
return mask;
|
|
390
430
|
}
|
|
391
|
-
return vertical;
|
|
392
431
|
}
|
|
393
432
|
/**
|
|
394
433
|
* Fills internal holes in the binary mask using flood fill from edges.
|
|
@@ -588,6 +627,23 @@ var ImageTracer = class {
|
|
|
588
627
|
const tail = points.slice(1);
|
|
589
628
|
return `M ${head.x} ${head.y} ` + tail.map((p) => `L ${p.x} ${p.y}`).join(" ") + " Z";
|
|
590
629
|
}
|
|
630
|
+
static ensurePaper() {
|
|
631
|
+
if (!import_paper.default.project) {
|
|
632
|
+
import_paper.default.setup(new import_paper.default.Size(100, 100));
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
static pointsToSVGPaper(points, tolerance) {
|
|
636
|
+
if (points.length < 3) return this.pointsToSVG(points);
|
|
637
|
+
this.ensurePaper();
|
|
638
|
+
const path = new import_paper.default.Path({
|
|
639
|
+
segments: points.map((p) => [p.x, p.y]),
|
|
640
|
+
closed: true
|
|
641
|
+
});
|
|
642
|
+
path.simplify(tolerance);
|
|
643
|
+
const data = path.pathData;
|
|
644
|
+
path.remove();
|
|
645
|
+
return data;
|
|
646
|
+
}
|
|
591
647
|
};
|
|
592
648
|
|
|
593
649
|
// src/coordinate.ts
|
|
@@ -662,96 +718,45 @@ var Coordinate = class {
|
|
|
662
718
|
};
|
|
663
719
|
|
|
664
720
|
// src/geometry.ts
|
|
665
|
-
var
|
|
666
|
-
function
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
const bottom = y + height / 2;
|
|
675
|
-
switch (hole.anchor) {
|
|
676
|
-
case "top-left":
|
|
677
|
-
bx = left;
|
|
678
|
-
by = top;
|
|
679
|
-
break;
|
|
680
|
-
case "top-center":
|
|
681
|
-
bx = x;
|
|
682
|
-
by = top;
|
|
683
|
-
break;
|
|
684
|
-
case "top-right":
|
|
685
|
-
bx = right;
|
|
686
|
-
by = top;
|
|
687
|
-
break;
|
|
688
|
-
case "center-left":
|
|
689
|
-
bx = left;
|
|
690
|
-
by = y;
|
|
691
|
-
break;
|
|
692
|
-
case "center":
|
|
693
|
-
bx = x;
|
|
694
|
-
by = y;
|
|
695
|
-
break;
|
|
696
|
-
case "center-right":
|
|
697
|
-
bx = right;
|
|
698
|
-
by = y;
|
|
699
|
-
break;
|
|
700
|
-
case "bottom-left":
|
|
701
|
-
bx = left;
|
|
702
|
-
by = bottom;
|
|
703
|
-
break;
|
|
704
|
-
case "bottom-center":
|
|
705
|
-
bx = x;
|
|
706
|
-
by = bottom;
|
|
707
|
-
break;
|
|
708
|
-
case "bottom-right":
|
|
709
|
-
bx = right;
|
|
710
|
-
by = bottom;
|
|
711
|
-
break;
|
|
712
|
-
}
|
|
713
|
-
return {
|
|
714
|
-
x: bx + (hole.offsetX || 0),
|
|
715
|
-
y: by + (hole.offsetY || 0)
|
|
716
|
-
};
|
|
717
|
-
} else if (hole.x !== void 0 && hole.y !== void 0) {
|
|
718
|
-
const { x, width, y, height } = geometry;
|
|
719
|
-
return {
|
|
720
|
-
x: hole.x * width + (x - width / 2) + (hole.offsetX || 0),
|
|
721
|
-
y: hole.y * height + (y - height / 2) + (hole.offsetY || 0)
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
return { x: 0, y: 0 };
|
|
721
|
+
var import_paper2 = __toESM(require("paper"));
|
|
722
|
+
function resolveFeaturePosition(feature, geometry) {
|
|
723
|
+
const { x, y, width, height } = geometry;
|
|
724
|
+
const left = x - width / 2;
|
|
725
|
+
const top = y - height / 2;
|
|
726
|
+
return {
|
|
727
|
+
x: left + feature.x * width,
|
|
728
|
+
y: top + feature.y * height
|
|
729
|
+
};
|
|
725
730
|
}
|
|
726
731
|
function ensurePaper(width, height) {
|
|
727
|
-
if (!
|
|
728
|
-
|
|
732
|
+
if (!import_paper2.default.project) {
|
|
733
|
+
import_paper2.default.setup(new import_paper2.default.Size(width, height));
|
|
729
734
|
} else {
|
|
730
|
-
|
|
735
|
+
import_paper2.default.view.viewSize = new import_paper2.default.Size(width, height);
|
|
731
736
|
}
|
|
732
737
|
}
|
|
733
738
|
function createBaseShape(options) {
|
|
734
739
|
const { shape, width, height, radius, x, y, pathData } = options;
|
|
735
|
-
const center = new
|
|
740
|
+
const center = new import_paper2.default.Point(x, y);
|
|
736
741
|
if (shape === "rect") {
|
|
737
|
-
return new
|
|
742
|
+
return new import_paper2.default.Path.Rectangle({
|
|
738
743
|
point: [x - width / 2, y - height / 2],
|
|
739
744
|
size: [Math.max(0, width), Math.max(0, height)],
|
|
740
745
|
radius: Math.max(0, radius)
|
|
741
746
|
});
|
|
742
747
|
} else if (shape === "circle") {
|
|
743
748
|
const r = Math.min(width, height) / 2;
|
|
744
|
-
return new
|
|
749
|
+
return new import_paper2.default.Path.Circle({
|
|
745
750
|
center,
|
|
746
751
|
radius: Math.max(0, r)
|
|
747
752
|
});
|
|
748
753
|
} else if (shape === "ellipse") {
|
|
749
|
-
return new
|
|
754
|
+
return new import_paper2.default.Path.Ellipse({
|
|
750
755
|
center,
|
|
751
756
|
radius: [Math.max(0, width / 2), Math.max(0, height / 2)]
|
|
752
757
|
});
|
|
753
758
|
} else if (shape === "custom" && pathData) {
|
|
754
|
-
const path = new
|
|
759
|
+
const path = new import_paper2.default.Path();
|
|
755
760
|
path.pathData = pathData;
|
|
756
761
|
path.position = center;
|
|
757
762
|
if (width > 0 && height > 0 && path.bounds.width > 0 && path.bounds.height > 0) {
|
|
@@ -759,112 +764,131 @@ function createBaseShape(options) {
|
|
|
759
764
|
}
|
|
760
765
|
return path;
|
|
761
766
|
} else {
|
|
762
|
-
return new
|
|
767
|
+
return new import_paper2.default.Path.Rectangle({
|
|
763
768
|
point: [x - width / 2, y - height / 2],
|
|
764
769
|
size: [Math.max(0, width), Math.max(0, height)]
|
|
765
770
|
});
|
|
766
771
|
}
|
|
767
772
|
}
|
|
768
|
-
function
|
|
773
|
+
function createFeatureItem(feature, center) {
|
|
774
|
+
let item;
|
|
775
|
+
if (feature.shape === "rect") {
|
|
776
|
+
const w = feature.width || 10;
|
|
777
|
+
const h = feature.height || 10;
|
|
778
|
+
const r = feature.radius || 0;
|
|
779
|
+
item = new import_paper2.default.Path.Rectangle({
|
|
780
|
+
point: [center.x - w / 2, center.y - h / 2],
|
|
781
|
+
size: [w, h],
|
|
782
|
+
radius: r
|
|
783
|
+
});
|
|
784
|
+
} else {
|
|
785
|
+
const r = feature.radius || 5;
|
|
786
|
+
item = new import_paper2.default.Path.Circle({
|
|
787
|
+
center,
|
|
788
|
+
radius: r
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
if (feature.rotation) {
|
|
792
|
+
item.rotate(feature.rotation, center);
|
|
793
|
+
}
|
|
794
|
+
return item;
|
|
795
|
+
}
|
|
796
|
+
function getPerimeterShape(options) {
|
|
769
797
|
let mainShape = createBaseShape(options);
|
|
770
|
-
const {
|
|
771
|
-
if (
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
center,
|
|
784
|
-
radius: hole.outerRadius
|
|
785
|
-
});
|
|
786
|
-
const cut = hole.shape === "square" ? new import_paper.default.Path.Rectangle({
|
|
787
|
-
point: [
|
|
788
|
-
center.x - hole.innerRadius,
|
|
789
|
-
center.y - hole.innerRadius
|
|
790
|
-
],
|
|
791
|
-
size: [hole.innerRadius * 2, hole.innerRadius * 2]
|
|
792
|
-
}) : new import_paper.default.Path.Circle({
|
|
793
|
-
center,
|
|
794
|
-
radius: hole.innerRadius
|
|
795
|
-
});
|
|
796
|
-
if (!lugsPath) {
|
|
797
|
-
lugsPath = lug;
|
|
798
|
+
const { features } = options;
|
|
799
|
+
if (features && features.length > 0) {
|
|
800
|
+
const edgeFeatures = features.filter(
|
|
801
|
+
(f) => !f.placement || f.placement === "edge"
|
|
802
|
+
);
|
|
803
|
+
const adds = [];
|
|
804
|
+
const subtracts = [];
|
|
805
|
+
edgeFeatures.forEach((f) => {
|
|
806
|
+
const pos = resolveFeaturePosition(f, options);
|
|
807
|
+
const center = new import_paper2.default.Point(pos.x, pos.y);
|
|
808
|
+
const item = createFeatureItem(f, center);
|
|
809
|
+
if (f.operation === "add") {
|
|
810
|
+
adds.push(item);
|
|
798
811
|
} else {
|
|
812
|
+
subtracts.push(item);
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
if (adds.length > 0) {
|
|
816
|
+
for (const item of adds) {
|
|
799
817
|
try {
|
|
800
|
-
const temp =
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
818
|
+
const temp = mainShape.unite(item);
|
|
819
|
+
mainShape.remove();
|
|
820
|
+
item.remove();
|
|
821
|
+
mainShape = temp;
|
|
804
822
|
} catch (e) {
|
|
805
|
-
console.error("Geometry: Failed to unite
|
|
806
|
-
|
|
823
|
+
console.error("Geometry: Failed to unite feature", e);
|
|
824
|
+
item.remove();
|
|
807
825
|
}
|
|
808
826
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
827
|
+
}
|
|
828
|
+
if (subtracts.length > 0) {
|
|
829
|
+
for (const item of subtracts) {
|
|
812
830
|
try {
|
|
813
|
-
const temp =
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
831
|
+
const temp = mainShape.subtract(item);
|
|
832
|
+
mainShape.remove();
|
|
833
|
+
item.remove();
|
|
834
|
+
mainShape = temp;
|
|
817
835
|
} catch (e) {
|
|
818
|
-
console.error("Geometry: Failed to
|
|
819
|
-
|
|
836
|
+
console.error("Geometry: Failed to subtract feature", e);
|
|
837
|
+
item.remove();
|
|
820
838
|
}
|
|
821
839
|
}
|
|
822
|
-
});
|
|
823
|
-
if (lugsPath) {
|
|
824
|
-
try {
|
|
825
|
-
const temp = mainShape.unite(lugsPath);
|
|
826
|
-
mainShape.remove();
|
|
827
|
-
lugsPath.remove();
|
|
828
|
-
mainShape = temp;
|
|
829
|
-
} catch (e) {
|
|
830
|
-
console.error("Geometry: Failed to unite lugsPath to mainShape", e);
|
|
831
|
-
}
|
|
832
840
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
841
|
+
}
|
|
842
|
+
return mainShape;
|
|
843
|
+
}
|
|
844
|
+
function applySurfaceFeatures(shape, features, options) {
|
|
845
|
+
const internalFeatures = features.filter((f) => f.placement === "internal");
|
|
846
|
+
if (internalFeatures.length === 0) return shape;
|
|
847
|
+
let result = shape;
|
|
848
|
+
for (const f of internalFeatures) {
|
|
849
|
+
const pos = resolveFeaturePosition(f, options);
|
|
850
|
+
const center = new import_paper2.default.Point(pos.x, pos.y);
|
|
851
|
+
const item = createFeatureItem(f, center);
|
|
852
|
+
try {
|
|
853
|
+
if (f.operation === "add") {
|
|
854
|
+
const temp = result.unite(item);
|
|
855
|
+
result.remove();
|
|
856
|
+
item.remove();
|
|
857
|
+
result = temp;
|
|
858
|
+
} else {
|
|
859
|
+
const temp = result.subtract(item);
|
|
860
|
+
result.remove();
|
|
861
|
+
item.remove();
|
|
862
|
+
result = temp;
|
|
844
863
|
}
|
|
864
|
+
} catch (e) {
|
|
865
|
+
console.error("Geometry: Failed to apply surface feature", e);
|
|
866
|
+
item.remove();
|
|
845
867
|
}
|
|
846
868
|
}
|
|
847
|
-
return
|
|
869
|
+
return result;
|
|
848
870
|
}
|
|
849
871
|
function generateDielinePath(options) {
|
|
850
872
|
const paperWidth = options.canvasWidth || options.width * 2 || 2e3;
|
|
851
873
|
const paperHeight = options.canvasHeight || options.height * 2 || 2e3;
|
|
852
874
|
ensurePaper(paperWidth, paperHeight);
|
|
853
|
-
|
|
854
|
-
const
|
|
855
|
-
const
|
|
856
|
-
|
|
875
|
+
import_paper2.default.project.activeLayer.removeChildren();
|
|
876
|
+
const perimeter = getPerimeterShape(options);
|
|
877
|
+
const finalShape = applySurfaceFeatures(perimeter, options.features, options);
|
|
878
|
+
const pathData = finalShape.pathData;
|
|
879
|
+
finalShape.remove();
|
|
857
880
|
return pathData;
|
|
858
881
|
}
|
|
859
882
|
function generateMaskPath(options) {
|
|
860
883
|
ensurePaper(options.canvasWidth, options.canvasHeight);
|
|
861
|
-
|
|
884
|
+
import_paper2.default.project.activeLayer.removeChildren();
|
|
862
885
|
const { canvasWidth, canvasHeight } = options;
|
|
863
|
-
const maskRect = new
|
|
886
|
+
const maskRect = new import_paper2.default.Path.Rectangle({
|
|
864
887
|
point: [0, 0],
|
|
865
888
|
size: [canvasWidth, canvasHeight]
|
|
866
889
|
});
|
|
867
|
-
const
|
|
890
|
+
const perimeter = getPerimeterShape(options);
|
|
891
|
+
const mainShape = applySurfaceFeatures(perimeter, options.features, options);
|
|
868
892
|
const finalMask = maskRect.subtract(mainShape);
|
|
869
893
|
maskRect.remove();
|
|
870
894
|
mainShape.remove();
|
|
@@ -872,43 +896,15 @@ function generateMaskPath(options) {
|
|
|
872
896
|
finalMask.remove();
|
|
873
897
|
return pathData;
|
|
874
898
|
}
|
|
875
|
-
function generateBleedZonePath(
|
|
876
|
-
const paperWidth =
|
|
877
|
-
const paperHeight =
|
|
899
|
+
function generateBleedZonePath(originalOptions, offsetOptions, offset) {
|
|
900
|
+
const paperWidth = originalOptions.canvasWidth || originalOptions.width * 2 || 2e3;
|
|
901
|
+
const paperHeight = originalOptions.canvasHeight || originalOptions.height * 2 || 2e3;
|
|
878
902
|
ensurePaper(paperWidth, paperHeight);
|
|
879
|
-
|
|
880
|
-
const
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
stroker.strokeColor = new import_paper.default.Color("black");
|
|
885
|
-
stroker.strokeWidth = Math.abs(offset) * 2;
|
|
886
|
-
stroker.strokeJoin = "round";
|
|
887
|
-
stroker.strokeCap = "round";
|
|
888
|
-
let expanded;
|
|
889
|
-
try {
|
|
890
|
-
expanded = stroker.expand({ stroke: true, fill: false, insert: false });
|
|
891
|
-
} catch (e) {
|
|
892
|
-
stroker.remove();
|
|
893
|
-
shapeOffset = shapeOriginal.clone();
|
|
894
|
-
return shapeOffset.pathData;
|
|
895
|
-
}
|
|
896
|
-
stroker.remove();
|
|
897
|
-
if (offset > 0) {
|
|
898
|
-
shapeOffset = shapeOriginal.unite(expanded);
|
|
899
|
-
} else {
|
|
900
|
-
shapeOffset = shapeOriginal.subtract(expanded);
|
|
901
|
-
}
|
|
902
|
-
expanded.remove();
|
|
903
|
-
} else {
|
|
904
|
-
const offsetOptions = {
|
|
905
|
-
...options,
|
|
906
|
-
width: Math.max(0, options.width + offset * 2),
|
|
907
|
-
height: Math.max(0, options.height + offset * 2),
|
|
908
|
-
radius: options.radius === 0 ? 0 : Math.max(0, options.radius + offset)
|
|
909
|
-
};
|
|
910
|
-
shapeOffset = getDielineShape(offsetOptions);
|
|
911
|
-
}
|
|
903
|
+
import_paper2.default.project.activeLayer.removeChildren();
|
|
904
|
+
const pOriginal = getPerimeterShape(originalOptions);
|
|
905
|
+
const shapeOriginal = applySurfaceFeatures(pOriginal, originalOptions.features, originalOptions);
|
|
906
|
+
const pOffset = getPerimeterShape(offsetOptions);
|
|
907
|
+
const shapeOffset = applySurfaceFeatures(pOffset, offsetOptions.features, offsetOptions);
|
|
912
908
|
let bleedZone;
|
|
913
909
|
if (offset > 0) {
|
|
914
910
|
bleedZone = shapeOffset.subtract(shapeOriginal);
|
|
@@ -923,16 +919,16 @@ function generateBleedZonePath(options, offset) {
|
|
|
923
919
|
}
|
|
924
920
|
function getNearestPointOnDieline(point, options) {
|
|
925
921
|
ensurePaper(options.width * 2, options.height * 2);
|
|
926
|
-
|
|
922
|
+
import_paper2.default.project.activeLayer.removeChildren();
|
|
927
923
|
const shape = createBaseShape(options);
|
|
928
|
-
const p = new
|
|
924
|
+
const p = new import_paper2.default.Point(point.x, point.y);
|
|
929
925
|
const nearest = shape.getNearestPoint(p);
|
|
930
926
|
const result = { x: nearest.x, y: nearest.y };
|
|
931
927
|
shape.remove();
|
|
932
928
|
return result;
|
|
933
929
|
}
|
|
934
930
|
function getPathBounds(pathData) {
|
|
935
|
-
const path = new
|
|
931
|
+
const path = new import_paper2.default.Path();
|
|
936
932
|
path.pathData = pathData;
|
|
937
933
|
const bounds = path.bounds;
|
|
938
934
|
path.remove();
|
|
@@ -951,20 +947,41 @@ var DielineTool = class {
|
|
|
951
947
|
this.metadata = {
|
|
952
948
|
name: "DielineTool"
|
|
953
949
|
};
|
|
954
|
-
this.
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
950
|
+
this.state = {
|
|
951
|
+
unit: "mm",
|
|
952
|
+
shape: "rect",
|
|
953
|
+
width: 500,
|
|
954
|
+
height: 500,
|
|
955
|
+
radius: 0,
|
|
956
|
+
offset: 0,
|
|
957
|
+
padding: 140,
|
|
958
|
+
mainLine: {
|
|
959
|
+
width: 2.7,
|
|
960
|
+
color: "#FF0000",
|
|
961
|
+
dashLength: 5,
|
|
962
|
+
style: "solid"
|
|
963
|
+
},
|
|
964
|
+
offsetLine: {
|
|
965
|
+
width: 2.7,
|
|
966
|
+
color: "#FF0000",
|
|
967
|
+
dashLength: 5,
|
|
968
|
+
style: "solid"
|
|
969
|
+
},
|
|
970
|
+
insideColor: "rgba(0,0,0,0)",
|
|
971
|
+
outsideColor: "#ffffff",
|
|
972
|
+
showBleedLines: true,
|
|
973
|
+
features: []
|
|
974
|
+
};
|
|
966
975
|
if (options) {
|
|
967
|
-
|
|
976
|
+
if (options.mainLine) {
|
|
977
|
+
Object.assign(this.state.mainLine, options.mainLine);
|
|
978
|
+
delete options.mainLine;
|
|
979
|
+
}
|
|
980
|
+
if (options.offsetLine) {
|
|
981
|
+
Object.assign(this.state.offsetLine, options.offsetLine);
|
|
982
|
+
delete options.offsetLine;
|
|
983
|
+
}
|
|
984
|
+
Object.assign(this.state, options);
|
|
968
985
|
}
|
|
969
986
|
}
|
|
970
987
|
activate(context) {
|
|
@@ -976,38 +993,93 @@ var DielineTool = class {
|
|
|
976
993
|
}
|
|
977
994
|
const configService = context.services.get("ConfigurationService");
|
|
978
995
|
if (configService) {
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
);
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
);
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
);
|
|
999
|
-
|
|
1000
|
-
this.pathData = configService.get("dieline.pathData", this.pathData);
|
|
996
|
+
const s = this.state;
|
|
997
|
+
s.unit = configService.get("dieline.unit", s.unit);
|
|
998
|
+
s.shape = configService.get("dieline.shape", s.shape);
|
|
999
|
+
s.width = configService.get("dieline.width", s.width);
|
|
1000
|
+
s.height = configService.get("dieline.height", s.height);
|
|
1001
|
+
s.radius = configService.get("dieline.radius", s.radius);
|
|
1002
|
+
s.padding = configService.get("dieline.padding", s.padding);
|
|
1003
|
+
s.offset = configService.get("dieline.offset", s.offset);
|
|
1004
|
+
s.mainLine.width = configService.get("dieline.strokeWidth", s.mainLine.width);
|
|
1005
|
+
s.mainLine.color = configService.get("dieline.strokeColor", s.mainLine.color);
|
|
1006
|
+
s.mainLine.dashLength = configService.get("dieline.dashLength", s.mainLine.dashLength);
|
|
1007
|
+
s.mainLine.style = configService.get("dieline.style", s.mainLine.style);
|
|
1008
|
+
s.offsetLine.width = configService.get("dieline.offsetStrokeWidth", s.offsetLine.width);
|
|
1009
|
+
s.offsetLine.color = configService.get("dieline.offsetStrokeColor", s.offsetLine.color);
|
|
1010
|
+
s.offsetLine.dashLength = configService.get("dieline.offsetDashLength", s.offsetLine.dashLength);
|
|
1011
|
+
s.offsetLine.style = configService.get("dieline.offsetStyle", s.offsetLine.style);
|
|
1012
|
+
s.insideColor = configService.get("dieline.insideColor", s.insideColor);
|
|
1013
|
+
s.outsideColor = configService.get("dieline.outsideColor", s.outsideColor);
|
|
1014
|
+
s.showBleedLines = configService.get("dieline.showBleedLines", s.showBleedLines);
|
|
1015
|
+
s.features = configService.get("dieline.features", s.features);
|
|
1016
|
+
s.pathData = configService.get("dieline.pathData", s.pathData);
|
|
1001
1017
|
configService.onAnyChange((e) => {
|
|
1002
1018
|
if (e.key.startsWith("dieline.")) {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1019
|
+
console.log(`[DielineTool] Config change detected: ${e.key} -> ${e.value}`);
|
|
1020
|
+
switch (e.key) {
|
|
1021
|
+
case "dieline.unit":
|
|
1022
|
+
s.unit = e.value;
|
|
1023
|
+
break;
|
|
1024
|
+
case "dieline.shape":
|
|
1025
|
+
s.shape = e.value;
|
|
1026
|
+
break;
|
|
1027
|
+
case "dieline.width":
|
|
1028
|
+
s.width = e.value;
|
|
1029
|
+
break;
|
|
1030
|
+
case "dieline.height":
|
|
1031
|
+
s.height = e.value;
|
|
1032
|
+
break;
|
|
1033
|
+
case "dieline.radius":
|
|
1034
|
+
s.radius = e.value;
|
|
1035
|
+
break;
|
|
1036
|
+
case "dieline.padding":
|
|
1037
|
+
s.padding = e.value;
|
|
1038
|
+
break;
|
|
1039
|
+
case "dieline.offset":
|
|
1040
|
+
s.offset = e.value;
|
|
1041
|
+
break;
|
|
1042
|
+
case "dieline.strokeWidth":
|
|
1043
|
+
s.mainLine.width = e.value;
|
|
1044
|
+
break;
|
|
1045
|
+
case "dieline.strokeColor":
|
|
1046
|
+
s.mainLine.color = e.value;
|
|
1047
|
+
break;
|
|
1048
|
+
case "dieline.dashLength":
|
|
1049
|
+
s.mainLine.dashLength = e.value;
|
|
1050
|
+
break;
|
|
1051
|
+
case "dieline.style":
|
|
1052
|
+
s.mainLine.style = e.value;
|
|
1053
|
+
break;
|
|
1054
|
+
case "dieline.offsetStrokeWidth":
|
|
1055
|
+
s.offsetLine.width = e.value;
|
|
1056
|
+
break;
|
|
1057
|
+
case "dieline.offsetStrokeColor":
|
|
1058
|
+
s.offsetLine.color = e.value;
|
|
1059
|
+
break;
|
|
1060
|
+
case "dieline.offsetDashLength":
|
|
1061
|
+
s.offsetLine.dashLength = e.value;
|
|
1062
|
+
break;
|
|
1063
|
+
case "dieline.offsetStyle":
|
|
1064
|
+
s.offsetLine.style = e.value;
|
|
1065
|
+
break;
|
|
1066
|
+
case "dieline.insideColor":
|
|
1067
|
+
s.insideColor = e.value;
|
|
1068
|
+
break;
|
|
1069
|
+
case "dieline.outsideColor":
|
|
1070
|
+
s.outsideColor = e.value;
|
|
1071
|
+
break;
|
|
1072
|
+
case "dieline.showBleedLines":
|
|
1073
|
+
s.showBleedLines = e.value;
|
|
1074
|
+
break;
|
|
1075
|
+
case "dieline.features":
|
|
1076
|
+
s.features = e.value;
|
|
1077
|
+
break;
|
|
1078
|
+
case "dieline.pathData":
|
|
1079
|
+
s.pathData = e.value;
|
|
1080
|
+
break;
|
|
1010
1081
|
}
|
|
1082
|
+
this.updateDieline();
|
|
1011
1083
|
}
|
|
1012
1084
|
});
|
|
1013
1085
|
}
|
|
@@ -1020,6 +1092,7 @@ var DielineTool = class {
|
|
|
1020
1092
|
this.context = void 0;
|
|
1021
1093
|
}
|
|
1022
1094
|
contribute() {
|
|
1095
|
+
const s = this.state;
|
|
1023
1096
|
return {
|
|
1024
1097
|
[import_core2.ContributionPointIds.CONFIGURATIONS]: [
|
|
1025
1098
|
{
|
|
@@ -1027,14 +1100,14 @@ var DielineTool = class {
|
|
|
1027
1100
|
type: "select",
|
|
1028
1101
|
label: "Unit",
|
|
1029
1102
|
options: ["px", "mm", "cm", "in"],
|
|
1030
|
-
default:
|
|
1103
|
+
default: s.unit
|
|
1031
1104
|
},
|
|
1032
1105
|
{
|
|
1033
1106
|
id: "dieline.shape",
|
|
1034
1107
|
type: "select",
|
|
1035
1108
|
label: "Shape",
|
|
1036
1109
|
options: ["rect", "circle", "ellipse", "custom"],
|
|
1037
|
-
default:
|
|
1110
|
+
default: s.shape
|
|
1038
1111
|
},
|
|
1039
1112
|
{
|
|
1040
1113
|
id: "dieline.width",
|
|
@@ -1042,7 +1115,7 @@ var DielineTool = class {
|
|
|
1042
1115
|
label: "Width",
|
|
1043
1116
|
min: 10,
|
|
1044
1117
|
max: 2e3,
|
|
1045
|
-
default:
|
|
1118
|
+
default: s.width
|
|
1046
1119
|
},
|
|
1047
1120
|
{
|
|
1048
1121
|
id: "dieline.height",
|
|
@@ -1050,7 +1123,7 @@ var DielineTool = class {
|
|
|
1050
1123
|
label: "Height",
|
|
1051
1124
|
min: 10,
|
|
1052
1125
|
max: 2e3,
|
|
1053
|
-
default:
|
|
1126
|
+
default: s.height
|
|
1054
1127
|
},
|
|
1055
1128
|
{
|
|
1056
1129
|
id: "dieline.radius",
|
|
@@ -1058,20 +1131,14 @@ var DielineTool = class {
|
|
|
1058
1131
|
label: "Corner Radius",
|
|
1059
1132
|
min: 0,
|
|
1060
1133
|
max: 500,
|
|
1061
|
-
default:
|
|
1062
|
-
},
|
|
1063
|
-
{
|
|
1064
|
-
id: "dieline.position",
|
|
1065
|
-
type: "json",
|
|
1066
|
-
label: "Position (Normalized)",
|
|
1067
|
-
default: this.radius
|
|
1134
|
+
default: s.radius
|
|
1068
1135
|
},
|
|
1069
1136
|
{
|
|
1070
1137
|
id: "dieline.padding",
|
|
1071
1138
|
type: "select",
|
|
1072
1139
|
label: "View Padding",
|
|
1073
1140
|
options: [0, 10, 20, 40, 60, 100, "2%", "5%", "10%", "15%", "20%"],
|
|
1074
|
-
default:
|
|
1141
|
+
default: s.padding
|
|
1075
1142
|
},
|
|
1076
1143
|
{
|
|
1077
1144
|
id: "dieline.offset",
|
|
@@ -1079,38 +1146,91 @@ var DielineTool = class {
|
|
|
1079
1146
|
label: "Bleed Offset",
|
|
1080
1147
|
min: -100,
|
|
1081
1148
|
max: 100,
|
|
1082
|
-
default:
|
|
1149
|
+
default: s.offset
|
|
1083
1150
|
},
|
|
1084
1151
|
{
|
|
1085
1152
|
id: "dieline.showBleedLines",
|
|
1086
1153
|
type: "boolean",
|
|
1087
1154
|
label: "Show Bleed Lines",
|
|
1088
|
-
default:
|
|
1155
|
+
default: s.showBleedLines
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
id: "dieline.strokeWidth",
|
|
1159
|
+
type: "number",
|
|
1160
|
+
label: "Line Width",
|
|
1161
|
+
min: 0.1,
|
|
1162
|
+
max: 10,
|
|
1163
|
+
step: 0.1,
|
|
1164
|
+
default: s.mainLine.width
|
|
1165
|
+
},
|
|
1166
|
+
{
|
|
1167
|
+
id: "dieline.strokeColor",
|
|
1168
|
+
type: "color",
|
|
1169
|
+
label: "Line Color",
|
|
1170
|
+
default: s.mainLine.color
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
id: "dieline.dashLength",
|
|
1174
|
+
type: "number",
|
|
1175
|
+
label: "Dash Length",
|
|
1176
|
+
min: 1,
|
|
1177
|
+
max: 50,
|
|
1178
|
+
default: s.mainLine.dashLength
|
|
1089
1179
|
},
|
|
1090
1180
|
{
|
|
1091
1181
|
id: "dieline.style",
|
|
1092
1182
|
type: "select",
|
|
1093
1183
|
label: "Line Style",
|
|
1094
|
-
options: ["solid", "dashed"],
|
|
1095
|
-
default:
|
|
1184
|
+
options: ["solid", "dashed", "hidden"],
|
|
1185
|
+
default: s.mainLine.style
|
|
1186
|
+
},
|
|
1187
|
+
{
|
|
1188
|
+
id: "dieline.offsetStrokeWidth",
|
|
1189
|
+
type: "number",
|
|
1190
|
+
label: "Offset Line Width",
|
|
1191
|
+
min: 0.1,
|
|
1192
|
+
max: 10,
|
|
1193
|
+
step: 0.1,
|
|
1194
|
+
default: s.offsetLine.width
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
id: "dieline.offsetStrokeColor",
|
|
1198
|
+
type: "color",
|
|
1199
|
+
label: "Offset Line Color",
|
|
1200
|
+
default: s.offsetLine.color
|
|
1201
|
+
},
|
|
1202
|
+
{
|
|
1203
|
+
id: "dieline.offsetDashLength",
|
|
1204
|
+
type: "number",
|
|
1205
|
+
label: "Offset Dash Length",
|
|
1206
|
+
min: 1,
|
|
1207
|
+
max: 50,
|
|
1208
|
+
default: s.offsetLine.dashLength
|
|
1209
|
+
},
|
|
1210
|
+
{
|
|
1211
|
+
id: "dieline.offsetStyle",
|
|
1212
|
+
type: "select",
|
|
1213
|
+
label: "Offset Line Style",
|
|
1214
|
+
options: ["solid", "dashed", "hidden"],
|
|
1215
|
+
default: s.offsetLine.style
|
|
1096
1216
|
},
|
|
1097
1217
|
{
|
|
1098
1218
|
id: "dieline.insideColor",
|
|
1099
1219
|
type: "color",
|
|
1100
1220
|
label: "Inside Color",
|
|
1101
|
-
default:
|
|
1221
|
+
default: s.insideColor
|
|
1102
1222
|
},
|
|
1103
1223
|
{
|
|
1104
1224
|
id: "dieline.outsideColor",
|
|
1105
1225
|
type: "color",
|
|
1106
1226
|
label: "Outside Color",
|
|
1107
|
-
default:
|
|
1227
|
+
default: s.outsideColor
|
|
1108
1228
|
},
|
|
1109
1229
|
{
|
|
1110
|
-
id: "dieline.
|
|
1230
|
+
id: "dieline.features",
|
|
1111
1231
|
type: "json",
|
|
1112
|
-
label: "
|
|
1113
|
-
default:
|
|
1232
|
+
label: "Edge Features",
|
|
1233
|
+
default: s.features
|
|
1114
1234
|
}
|
|
1115
1235
|
],
|
|
1116
1236
|
[import_core2.ContributionPointIds.COMMANDS]: [
|
|
@@ -1132,24 +1252,18 @@ var DielineTool = class {
|
|
|
1132
1252
|
command: "detectEdge",
|
|
1133
1253
|
title: "Detect Edge from Image",
|
|
1134
1254
|
handler: async (imageUrl, options) => {
|
|
1135
|
-
var _a;
|
|
1136
1255
|
try {
|
|
1137
1256
|
const pathData = await ImageTracer.trace(imageUrl, options);
|
|
1138
1257
|
const bounds = getPathBounds(pathData);
|
|
1139
|
-
const currentMax = Math.max(
|
|
1258
|
+
const currentMax = Math.max(s.width, s.height);
|
|
1140
1259
|
const scale = currentMax / Math.max(bounds.width, bounds.height);
|
|
1141
1260
|
const newWidth = bounds.width * scale;
|
|
1142
1261
|
const newHeight = bounds.height * scale;
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
configService.update("dieline.height", newHeight);
|
|
1149
|
-
configService.update("dieline.shape", "custom");
|
|
1150
|
-
configService.update("dieline.pathData", pathData);
|
|
1151
|
-
}
|
|
1152
|
-
return pathData;
|
|
1262
|
+
return {
|
|
1263
|
+
pathData,
|
|
1264
|
+
width: newWidth,
|
|
1265
|
+
height: newHeight
|
|
1266
|
+
};
|
|
1153
1267
|
} catch (e) {
|
|
1154
1268
|
console.error("Edge detection failed", e);
|
|
1155
1269
|
throw e;
|
|
@@ -1208,15 +1322,15 @@ var DielineTool = class {
|
|
|
1208
1322
|
return new import_fabric2.Pattern({ source: canvas, repetition: "repeat" });
|
|
1209
1323
|
}
|
|
1210
1324
|
resolvePadding(containerWidth, containerHeight) {
|
|
1211
|
-
if (typeof this.padding === "number") {
|
|
1212
|
-
return this.padding;
|
|
1325
|
+
if (typeof this.state.padding === "number") {
|
|
1326
|
+
return this.state.padding;
|
|
1213
1327
|
}
|
|
1214
|
-
if (typeof this.padding === "string") {
|
|
1215
|
-
if (this.padding.endsWith("%")) {
|
|
1216
|
-
const percent = parseFloat(this.padding) / 100;
|
|
1328
|
+
if (typeof this.state.padding === "string") {
|
|
1329
|
+
if (this.state.padding.endsWith("%")) {
|
|
1330
|
+
const percent = parseFloat(this.state.padding) / 100;
|
|
1217
1331
|
return Math.min(containerWidth, containerHeight) * percent;
|
|
1218
1332
|
}
|
|
1219
|
-
return parseFloat(this.padding) || 0;
|
|
1333
|
+
return parseFloat(this.state.padding) || 0;
|
|
1220
1334
|
}
|
|
1221
1335
|
return 0;
|
|
1222
1336
|
}
|
|
@@ -1229,14 +1343,14 @@ var DielineTool = class {
|
|
|
1229
1343
|
shape,
|
|
1230
1344
|
radius,
|
|
1231
1345
|
offset,
|
|
1232
|
-
|
|
1346
|
+
mainLine,
|
|
1347
|
+
offsetLine,
|
|
1233
1348
|
insideColor,
|
|
1234
1349
|
outsideColor,
|
|
1235
|
-
position,
|
|
1236
1350
|
showBleedLines,
|
|
1237
|
-
|
|
1238
|
-
} = this;
|
|
1239
|
-
let { width, height } = this;
|
|
1351
|
+
features
|
|
1352
|
+
} = this.state;
|
|
1353
|
+
let { width, height } = this.state;
|
|
1240
1354
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1241
1355
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1242
1356
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
@@ -1253,37 +1367,18 @@ var DielineTool = class {
|
|
|
1253
1367
|
const visualRadius = radius * scale;
|
|
1254
1368
|
const visualOffset = offset * scale;
|
|
1255
1369
|
layer.remove(...layer.getObjects());
|
|
1256
|
-
const
|
|
1257
|
-
|
|
1258
|
-
y: cy,
|
|
1259
|
-
width: visualWidth,
|
|
1260
|
-
height: visualHeight
|
|
1261
|
-
// Pass scale/unit context if needed by resolveHolePosition (though currently unused there)
|
|
1262
|
-
};
|
|
1263
|
-
const absoluteHoles = (holes || []).map((h) => {
|
|
1264
|
-
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
1265
|
-
const offsetScale = unitScale * scale;
|
|
1266
|
-
const hWithPixelOffsets = {
|
|
1267
|
-
...h,
|
|
1268
|
-
offsetX: (h.offsetX || 0) * offsetScale,
|
|
1269
|
-
offsetY: (h.offsetY || 0) * offsetScale
|
|
1270
|
-
};
|
|
1271
|
-
const pos = resolveHolePosition(hWithPixelOffsets, geometryForHoles, {
|
|
1272
|
-
width: canvasW,
|
|
1273
|
-
height: canvasH
|
|
1274
|
-
});
|
|
1370
|
+
const absoluteFeatures = (features || []).map((f) => {
|
|
1371
|
+
const featureScale = scale;
|
|
1275
1372
|
return {
|
|
1276
|
-
...
|
|
1277
|
-
x:
|
|
1278
|
-
y:
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
// Store scaled offsets in the result for consistency, though pos is already resolved
|
|
1283
|
-
offsetX: hWithPixelOffsets.offsetX,
|
|
1284
|
-
offsetY: hWithPixelOffsets.offsetY
|
|
1373
|
+
...f,
|
|
1374
|
+
x: f.x,
|
|
1375
|
+
y: f.y,
|
|
1376
|
+
width: (f.width || 0) * featureScale,
|
|
1377
|
+
height: (f.height || 0) * featureScale,
|
|
1378
|
+
radius: (f.radius || 0) * featureScale
|
|
1285
1379
|
};
|
|
1286
1380
|
});
|
|
1381
|
+
const cutFeatures = absoluteFeatures.filter((f) => !f.skipCut);
|
|
1287
1382
|
const cutW = Math.max(0, visualWidth + visualOffset * 2);
|
|
1288
1383
|
const cutH = Math.max(0, visualHeight + visualOffset * 2);
|
|
1289
1384
|
const cutR = visualRadius === 0 ? 0 : Math.max(0, visualRadius + visualOffset);
|
|
@@ -1296,8 +1391,8 @@ var DielineTool = class {
|
|
|
1296
1391
|
radius: cutR,
|
|
1297
1392
|
x: cx,
|
|
1298
1393
|
y: cy,
|
|
1299
|
-
|
|
1300
|
-
pathData: this.pathData
|
|
1394
|
+
features: cutFeatures,
|
|
1395
|
+
pathData: this.state.pathData
|
|
1301
1396
|
});
|
|
1302
1397
|
const mask = new import_fabric2.Path(maskPathData, {
|
|
1303
1398
|
fill: outsideColor,
|
|
@@ -1318,8 +1413,9 @@ var DielineTool = class {
|
|
|
1318
1413
|
radius: cutR,
|
|
1319
1414
|
x: cx,
|
|
1320
1415
|
y: cy,
|
|
1321
|
-
|
|
1322
|
-
|
|
1416
|
+
features: cutFeatures,
|
|
1417
|
+
// Use same features as mask for consistency
|
|
1418
|
+
pathData: this.state.pathData,
|
|
1323
1419
|
canvasWidth: canvasW,
|
|
1324
1420
|
canvasHeight: canvasH
|
|
1325
1421
|
});
|
|
@@ -1343,15 +1439,27 @@ var DielineTool = class {
|
|
|
1343
1439
|
radius: visualRadius,
|
|
1344
1440
|
x: cx,
|
|
1345
1441
|
y: cy,
|
|
1346
|
-
|
|
1347
|
-
pathData: this.pathData,
|
|
1442
|
+
features: cutFeatures,
|
|
1443
|
+
pathData: this.state.pathData,
|
|
1444
|
+
canvasWidth: canvasW,
|
|
1445
|
+
canvasHeight: canvasH
|
|
1446
|
+
},
|
|
1447
|
+
{
|
|
1448
|
+
shape,
|
|
1449
|
+
width: cutW,
|
|
1450
|
+
height: cutH,
|
|
1451
|
+
radius: cutR,
|
|
1452
|
+
x: cx,
|
|
1453
|
+
y: cy,
|
|
1454
|
+
features: cutFeatures,
|
|
1455
|
+
pathData: this.state.pathData,
|
|
1348
1456
|
canvasWidth: canvasW,
|
|
1349
1457
|
canvasHeight: canvasH
|
|
1350
1458
|
},
|
|
1351
1459
|
visualOffset
|
|
1352
1460
|
);
|
|
1353
1461
|
if (showBleedLines !== false) {
|
|
1354
|
-
const pattern = this.createHatchPattern(
|
|
1462
|
+
const pattern = this.createHatchPattern(mainLine.color);
|
|
1355
1463
|
if (pattern) {
|
|
1356
1464
|
const bleedObj = new import_fabric2.Path(bleedPathData, {
|
|
1357
1465
|
fill: pattern,
|
|
@@ -1372,18 +1480,16 @@ var DielineTool = class {
|
|
|
1372
1480
|
radius: cutR,
|
|
1373
1481
|
x: cx,
|
|
1374
1482
|
y: cy,
|
|
1375
|
-
|
|
1376
|
-
pathData: this.pathData,
|
|
1483
|
+
features: cutFeatures,
|
|
1484
|
+
pathData: this.state.pathData,
|
|
1377
1485
|
canvasWidth: canvasW,
|
|
1378
1486
|
canvasHeight: canvasH
|
|
1379
1487
|
});
|
|
1380
1488
|
const offsetBorderObj = new import_fabric2.Path(offsetPathData, {
|
|
1381
1489
|
fill: null,
|
|
1382
|
-
stroke: "
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
strokeDashArray: [4, 4],
|
|
1386
|
-
// Dashed
|
|
1490
|
+
stroke: offsetLine.style === "hidden" ? null : offsetLine.color,
|
|
1491
|
+
strokeWidth: offsetLine.width,
|
|
1492
|
+
strokeDashArray: offsetLine.style === "dashed" ? [offsetLine.dashLength, offsetLine.dashLength] : void 0,
|
|
1387
1493
|
selectable: false,
|
|
1388
1494
|
evented: false,
|
|
1389
1495
|
originX: "left",
|
|
@@ -1398,16 +1504,16 @@ var DielineTool = class {
|
|
|
1398
1504
|
radius: visualRadius,
|
|
1399
1505
|
x: cx,
|
|
1400
1506
|
y: cy,
|
|
1401
|
-
|
|
1402
|
-
pathData: this.pathData,
|
|
1507
|
+
features: absoluteFeatures,
|
|
1508
|
+
pathData: this.state.pathData,
|
|
1403
1509
|
canvasWidth: canvasW,
|
|
1404
1510
|
canvasHeight: canvasH
|
|
1405
1511
|
});
|
|
1406
1512
|
const borderObj = new import_fabric2.Path(borderPathData, {
|
|
1407
1513
|
fill: "transparent",
|
|
1408
|
-
stroke: "
|
|
1409
|
-
strokeWidth:
|
|
1410
|
-
strokeDashArray: style === "dashed" ? [
|
|
1514
|
+
stroke: mainLine.style === "hidden" ? null : mainLine.color,
|
|
1515
|
+
strokeWidth: mainLine.width,
|
|
1516
|
+
strokeDashArray: mainLine.style === "dashed" ? [mainLine.dashLength, mainLine.dashLength] : void 0,
|
|
1411
1517
|
selectable: false,
|
|
1412
1518
|
evented: false,
|
|
1413
1519
|
originX: "left",
|
|
@@ -1439,7 +1545,7 @@ var DielineTool = class {
|
|
|
1439
1545
|
}
|
|
1440
1546
|
getGeometry() {
|
|
1441
1547
|
if (!this.canvasService) return null;
|
|
1442
|
-
const { unit, shape, width, height, radius,
|
|
1548
|
+
const { unit, shape, width, height, radius, offset, mainLine, pathData } = this.state;
|
|
1443
1549
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1444
1550
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1445
1551
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
@@ -1462,16 +1568,17 @@ var DielineTool = class {
|
|
|
1462
1568
|
height: visualHeight,
|
|
1463
1569
|
radius: radius * scale,
|
|
1464
1570
|
offset: offset * scale,
|
|
1465
|
-
// Pass scale to help other tools (like
|
|
1571
|
+
// Pass scale to help other tools (like FeatureTool) convert units
|
|
1466
1572
|
scale,
|
|
1467
|
-
|
|
1573
|
+
strokeWidth: mainLine.width,
|
|
1574
|
+
pathData
|
|
1468
1575
|
};
|
|
1469
1576
|
}
|
|
1470
1577
|
async exportCutImage() {
|
|
1471
1578
|
if (!this.canvasService) return null;
|
|
1472
1579
|
const userLayer = this.canvasService.getLayer("user");
|
|
1473
1580
|
if (!userLayer) return null;
|
|
1474
|
-
const { shape, width, height, radius,
|
|
1581
|
+
const { shape, width, height, radius, features, unit, pathData } = this.state;
|
|
1475
1582
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1476
1583
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1477
1584
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
@@ -1486,55 +1593,43 @@ var DielineTool = class {
|
|
|
1486
1593
|
const visualWidth = layout.width;
|
|
1487
1594
|
const visualHeight = layout.height;
|
|
1488
1595
|
const visualRadius = radius * scale;
|
|
1489
|
-
const
|
|
1490
|
-
const
|
|
1491
|
-
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
1492
|
-
const pos = resolveHolePosition(
|
|
1493
|
-
{
|
|
1494
|
-
...h,
|
|
1495
|
-
offsetX: (h.offsetX || 0) * unitScale * scale,
|
|
1496
|
-
offsetY: (h.offsetY || 0) * unitScale * scale
|
|
1497
|
-
},
|
|
1498
|
-
{ x: cx, y: cy, width: visualWidth, height: visualHeight },
|
|
1499
|
-
{ width: canvasW, height: canvasH }
|
|
1500
|
-
);
|
|
1596
|
+
const absoluteFeatures = (features || []).map((f) => {
|
|
1597
|
+
const featureScale = scale;
|
|
1501
1598
|
return {
|
|
1502
|
-
...
|
|
1503
|
-
x:
|
|
1504
|
-
y:
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
offsetY: (h.offsetY || 0) * unitScale * scale
|
|
1599
|
+
...f,
|
|
1600
|
+
x: f.x,
|
|
1601
|
+
y: f.y,
|
|
1602
|
+
width: (f.width || 0) * featureScale,
|
|
1603
|
+
height: (f.height || 0) * featureScale,
|
|
1604
|
+
radius: (f.radius || 0) * featureScale
|
|
1509
1605
|
};
|
|
1510
1606
|
});
|
|
1511
|
-
const
|
|
1607
|
+
const cutFeatures = absoluteFeatures.filter((f) => !f.skipCut);
|
|
1608
|
+
const generatedPathData = generateDielinePath({
|
|
1512
1609
|
shape,
|
|
1513
1610
|
width: visualWidth,
|
|
1514
1611
|
height: visualHeight,
|
|
1515
1612
|
radius: visualRadius,
|
|
1516
1613
|
x: cx,
|
|
1517
1614
|
y: cy,
|
|
1518
|
-
|
|
1519
|
-
pathData
|
|
1615
|
+
features: cutFeatures,
|
|
1616
|
+
pathData,
|
|
1520
1617
|
canvasWidth: canvasW,
|
|
1521
1618
|
canvasHeight: canvasH
|
|
1522
1619
|
});
|
|
1523
1620
|
const clonedLayer = await userLayer.clone();
|
|
1524
|
-
const clipPath = new import_fabric2.Path(
|
|
1621
|
+
const clipPath = new import_fabric2.Path(generatedPathData, {
|
|
1525
1622
|
originX: "left",
|
|
1526
1623
|
originY: "top",
|
|
1527
1624
|
left: 0,
|
|
1528
1625
|
top: 0,
|
|
1529
1626
|
absolutePositioned: true
|
|
1530
|
-
// Important for groups
|
|
1531
1627
|
});
|
|
1532
1628
|
clonedLayer.clipPath = clipPath;
|
|
1533
1629
|
const bounds = clipPath.getBoundingRect();
|
|
1534
1630
|
const dataUrl = clonedLayer.toDataURL({
|
|
1535
1631
|
format: "png",
|
|
1536
1632
|
multiplier: 2,
|
|
1537
|
-
// Better quality
|
|
1538
1633
|
left: bounds.left,
|
|
1539
1634
|
top: bounds.top,
|
|
1540
1635
|
width: bounds.width,
|
|
@@ -1703,23 +1798,26 @@ var FilmTool = class {
|
|
|
1703
1798
|
}
|
|
1704
1799
|
};
|
|
1705
1800
|
|
|
1706
|
-
// src/
|
|
1801
|
+
// src/feature.ts
|
|
1707
1802
|
var import_core4 = require("@pooder/core");
|
|
1708
1803
|
var import_fabric4 = require("fabric");
|
|
1709
|
-
var
|
|
1804
|
+
var FeatureTool = class {
|
|
1710
1805
|
constructor(options) {
|
|
1711
|
-
this.id = "pooder.kit.
|
|
1806
|
+
this.id = "pooder.kit.feature";
|
|
1712
1807
|
this.metadata = {
|
|
1713
|
-
name: "
|
|
1808
|
+
name: "FeatureTool"
|
|
1714
1809
|
};
|
|
1715
|
-
this.
|
|
1716
|
-
this.constraintTarget = "bleed";
|
|
1810
|
+
this.features = [];
|
|
1717
1811
|
this.isUpdatingConfig = false;
|
|
1812
|
+
this.isToolActive = false;
|
|
1718
1813
|
this.handleMoving = null;
|
|
1719
1814
|
this.handleModified = null;
|
|
1720
1815
|
this.handleDielineChange = null;
|
|
1721
|
-
// Cache geometry to enforce constraints during drag
|
|
1722
1816
|
this.currentGeometry = null;
|
|
1817
|
+
this.onToolActivated = (event) => {
|
|
1818
|
+
this.isToolActive = event.id === this.id;
|
|
1819
|
+
this.updateVisibility();
|
|
1820
|
+
};
|
|
1723
1821
|
if (options) {
|
|
1724
1822
|
Object.assign(this, options);
|
|
1725
1823
|
}
|
|
@@ -1728,135 +1826,82 @@ var HoleTool = class {
|
|
|
1728
1826
|
this.context = context;
|
|
1729
1827
|
this.canvasService = context.services.get("CanvasService");
|
|
1730
1828
|
if (!this.canvasService) {
|
|
1731
|
-
console.warn("CanvasService not found for
|
|
1829
|
+
console.warn("CanvasService not found for FeatureTool");
|
|
1732
1830
|
return;
|
|
1733
1831
|
}
|
|
1734
1832
|
const configService = context.services.get(
|
|
1735
1833
|
"ConfigurationService"
|
|
1736
1834
|
);
|
|
1737
1835
|
if (configService) {
|
|
1738
|
-
this.
|
|
1739
|
-
"hole.constraintTarget",
|
|
1740
|
-
this.constraintTarget
|
|
1741
|
-
);
|
|
1742
|
-
this.holes = configService.get("dieline.holes", []);
|
|
1836
|
+
this.features = configService.get("dieline.features", []);
|
|
1743
1837
|
configService.onAnyChange((e) => {
|
|
1744
1838
|
if (this.isUpdatingConfig) return;
|
|
1745
|
-
if (e.key === "
|
|
1746
|
-
this.
|
|
1747
|
-
this.enforceConstraints();
|
|
1748
|
-
}
|
|
1749
|
-
if (e.key === "dieline.holes") {
|
|
1750
|
-
this.holes = e.value || [];
|
|
1839
|
+
if (e.key === "dieline.features") {
|
|
1840
|
+
this.features = e.value || [];
|
|
1751
1841
|
this.redraw();
|
|
1752
1842
|
}
|
|
1753
1843
|
});
|
|
1754
1844
|
}
|
|
1845
|
+
context.eventBus.on("tool:activated", this.onToolActivated);
|
|
1755
1846
|
this.setup();
|
|
1756
1847
|
}
|
|
1757
1848
|
deactivate(context) {
|
|
1849
|
+
context.eventBus.off("tool:activated", this.onToolActivated);
|
|
1758
1850
|
this.teardown();
|
|
1759
1851
|
this.canvasService = void 0;
|
|
1760
1852
|
this.context = void 0;
|
|
1761
1853
|
}
|
|
1854
|
+
updateVisibility() {
|
|
1855
|
+
if (!this.canvasService) return;
|
|
1856
|
+
const canvas = this.canvasService.canvas;
|
|
1857
|
+
const markers = canvas.getObjects().filter((obj) => {
|
|
1858
|
+
var _a;
|
|
1859
|
+
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
1860
|
+
});
|
|
1861
|
+
markers.forEach((marker) => {
|
|
1862
|
+
marker.set({
|
|
1863
|
+
visible: this.isToolActive,
|
|
1864
|
+
// Or just selectable: false if we want them visible but locked
|
|
1865
|
+
selectable: this.isToolActive,
|
|
1866
|
+
evented: this.isToolActive
|
|
1867
|
+
});
|
|
1868
|
+
});
|
|
1869
|
+
canvas.requestRenderAll();
|
|
1870
|
+
}
|
|
1762
1871
|
contribute() {
|
|
1763
1872
|
return {
|
|
1764
|
-
[import_core4.ContributionPointIds.CONFIGURATIONS]: [
|
|
1765
|
-
{
|
|
1766
|
-
id: "hole.constraintTarget",
|
|
1767
|
-
type: "select",
|
|
1768
|
-
label: "Constraint Target",
|
|
1769
|
-
options: ["original", "bleed"],
|
|
1770
|
-
default: "bleed"
|
|
1771
|
-
}
|
|
1772
|
-
],
|
|
1773
1873
|
[import_core4.ContributionPointIds.COMMANDS]: [
|
|
1774
1874
|
{
|
|
1775
|
-
command: "
|
|
1776
|
-
title: "
|
|
1777
|
-
handler: () => {
|
|
1778
|
-
|
|
1779
|
-
if (!this.canvasService) return false;
|
|
1780
|
-
let defaultPos = { x: this.canvasService.canvas.width / 2, y: 50 };
|
|
1781
|
-
if (this.currentGeometry) {
|
|
1782
|
-
const g = this.currentGeometry;
|
|
1783
|
-
const topCenter = { x: g.x, y: g.y - g.height / 2 };
|
|
1784
|
-
defaultPos = getNearestPointOnDieline(topCenter, {
|
|
1785
|
-
...g,
|
|
1786
|
-
holes: []
|
|
1787
|
-
});
|
|
1788
|
-
}
|
|
1789
|
-
const { width, height } = this.canvasService.canvas;
|
|
1790
|
-
const normalizedHole = Coordinate.normalizePoint(defaultPos, {
|
|
1791
|
-
width: width || 800,
|
|
1792
|
-
height: height || 600
|
|
1793
|
-
});
|
|
1794
|
-
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
1795
|
-
"ConfigurationService"
|
|
1796
|
-
);
|
|
1797
|
-
if (configService) {
|
|
1798
|
-
configService.update("dieline.holes", [
|
|
1799
|
-
{
|
|
1800
|
-
x: normalizedHole.x,
|
|
1801
|
-
y: normalizedHole.y,
|
|
1802
|
-
innerRadius: 15,
|
|
1803
|
-
outerRadius: 25
|
|
1804
|
-
}
|
|
1805
|
-
]);
|
|
1806
|
-
}
|
|
1807
|
-
return true;
|
|
1875
|
+
command: "addFeature",
|
|
1876
|
+
title: "Add Edge Feature",
|
|
1877
|
+
handler: (type = "subtract") => {
|
|
1878
|
+
return this.addFeature(type);
|
|
1808
1879
|
}
|
|
1809
1880
|
},
|
|
1810
1881
|
{
|
|
1811
1882
|
command: "addHole",
|
|
1812
1883
|
title: "Add Hole",
|
|
1813
|
-
handler: (
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
normalizedX = gw > 0 ? (x - left) / gw : 0.5;
|
|
1823
|
-
normalizedY = gh > 0 ? (y - top) / gh : 0.5;
|
|
1824
|
-
} else {
|
|
1825
|
-
const { width, height } = this.canvasService.canvas;
|
|
1826
|
-
normalizedX = Coordinate.toNormalized(x, width || 800);
|
|
1827
|
-
normalizedY = Coordinate.toNormalized(y, height || 600);
|
|
1828
|
-
}
|
|
1829
|
-
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
1830
|
-
"ConfigurationService"
|
|
1831
|
-
);
|
|
1832
|
-
if (configService) {
|
|
1833
|
-
const currentHoles = configService.get("dieline.holes", []);
|
|
1834
|
-
const lastHole = currentHoles[currentHoles.length - 1];
|
|
1835
|
-
const innerRadius = (_b = lastHole == null ? void 0 : lastHole.innerRadius) != null ? _b : 15;
|
|
1836
|
-
const outerRadius = (_c = lastHole == null ? void 0 : lastHole.outerRadius) != null ? _c : 25;
|
|
1837
|
-
const shape = (_d = lastHole == null ? void 0 : lastHole.shape) != null ? _d : "circle";
|
|
1838
|
-
const newHole = {
|
|
1839
|
-
x: normalizedX,
|
|
1840
|
-
y: normalizedY,
|
|
1841
|
-
shape,
|
|
1842
|
-
innerRadius,
|
|
1843
|
-
outerRadius
|
|
1844
|
-
};
|
|
1845
|
-
configService.update("dieline.holes", [...currentHoles, newHole]);
|
|
1846
|
-
}
|
|
1847
|
-
return true;
|
|
1884
|
+
handler: () => {
|
|
1885
|
+
return this.addFeature("subtract");
|
|
1886
|
+
}
|
|
1887
|
+
},
|
|
1888
|
+
{
|
|
1889
|
+
command: "addDoubleLayerHole",
|
|
1890
|
+
title: "Add Double Layer Hole",
|
|
1891
|
+
handler: () => {
|
|
1892
|
+
return this.addDoubleLayerHole();
|
|
1848
1893
|
}
|
|
1849
1894
|
},
|
|
1850
1895
|
{
|
|
1851
|
-
command: "
|
|
1852
|
-
title: "Clear
|
|
1896
|
+
command: "clearFeatures",
|
|
1897
|
+
title: "Clear Features",
|
|
1853
1898
|
handler: () => {
|
|
1854
1899
|
var _a;
|
|
1855
1900
|
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
1856
1901
|
"ConfigurationService"
|
|
1857
1902
|
);
|
|
1858
1903
|
if (configService) {
|
|
1859
|
-
configService.update("dieline.
|
|
1904
|
+
configService.update("dieline.features", []);
|
|
1860
1905
|
}
|
|
1861
1906
|
return true;
|
|
1862
1907
|
}
|
|
@@ -1864,6 +1909,82 @@ var HoleTool = class {
|
|
|
1864
1909
|
]
|
|
1865
1910
|
};
|
|
1866
1911
|
}
|
|
1912
|
+
addFeature(type) {
|
|
1913
|
+
var _a;
|
|
1914
|
+
if (!this.canvasService) return false;
|
|
1915
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
1916
|
+
"ConfigurationService"
|
|
1917
|
+
);
|
|
1918
|
+
const unit = (configService == null ? void 0 : configService.get("dieline.unit", "mm")) || "mm";
|
|
1919
|
+
const defaultSize = Coordinate.convertUnit(10, "mm", unit);
|
|
1920
|
+
const newFeature = {
|
|
1921
|
+
id: Date.now().toString(),
|
|
1922
|
+
operation: type,
|
|
1923
|
+
placement: "edge",
|
|
1924
|
+
shape: "rect",
|
|
1925
|
+
x: 0.5,
|
|
1926
|
+
y: 0,
|
|
1927
|
+
// Top edge
|
|
1928
|
+
width: defaultSize,
|
|
1929
|
+
height: defaultSize,
|
|
1930
|
+
rotation: 0
|
|
1931
|
+
};
|
|
1932
|
+
if (configService) {
|
|
1933
|
+
const current = configService.get(
|
|
1934
|
+
"dieline.features",
|
|
1935
|
+
[]
|
|
1936
|
+
);
|
|
1937
|
+
configService.update("dieline.features", [...current, newFeature]);
|
|
1938
|
+
}
|
|
1939
|
+
return true;
|
|
1940
|
+
}
|
|
1941
|
+
addDoubleLayerHole() {
|
|
1942
|
+
var _a;
|
|
1943
|
+
if (!this.canvasService) return false;
|
|
1944
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
1945
|
+
"ConfigurationService"
|
|
1946
|
+
);
|
|
1947
|
+
const unit = (configService == null ? void 0 : configService.get("dieline.unit", "mm")) || "mm";
|
|
1948
|
+
const lugRadius = Coordinate.convertUnit(20, "mm", unit);
|
|
1949
|
+
const holeRadius = Coordinate.convertUnit(15, "mm", unit);
|
|
1950
|
+
const groupId = Date.now().toString();
|
|
1951
|
+
const timestamp = Date.now();
|
|
1952
|
+
const lug = {
|
|
1953
|
+
id: `${timestamp}-lug`,
|
|
1954
|
+
groupId,
|
|
1955
|
+
operation: "add",
|
|
1956
|
+
shape: "circle",
|
|
1957
|
+
placement: "edge",
|
|
1958
|
+
x: 0.5,
|
|
1959
|
+
y: 0,
|
|
1960
|
+
radius: lugRadius,
|
|
1961
|
+
// 20mm
|
|
1962
|
+
rotation: 0
|
|
1963
|
+
};
|
|
1964
|
+
const hole = {
|
|
1965
|
+
id: `${timestamp}-hole`,
|
|
1966
|
+
groupId,
|
|
1967
|
+
operation: "subtract",
|
|
1968
|
+
shape: "circle",
|
|
1969
|
+
placement: "edge",
|
|
1970
|
+
x: 0.5,
|
|
1971
|
+
y: 0,
|
|
1972
|
+
radius: holeRadius,
|
|
1973
|
+
// 15mm
|
|
1974
|
+
rotation: 0
|
|
1975
|
+
};
|
|
1976
|
+
if (configService) {
|
|
1977
|
+
const current = configService.get(
|
|
1978
|
+
"dieline.features",
|
|
1979
|
+
[]
|
|
1980
|
+
);
|
|
1981
|
+
configService.update("dieline.features", [...current, lug, hole]);
|
|
1982
|
+
}
|
|
1983
|
+
return true;
|
|
1984
|
+
}
|
|
1985
|
+
getGeometryForFeature(geometry, feature) {
|
|
1986
|
+
return geometry;
|
|
1987
|
+
}
|
|
1867
1988
|
setup() {
|
|
1868
1989
|
if (!this.canvasService || !this.context) return;
|
|
1869
1990
|
const canvas = this.canvasService.canvas;
|
|
@@ -1871,10 +1992,7 @@ var HoleTool = class {
|
|
|
1871
1992
|
this.handleDielineChange = (geometry) => {
|
|
1872
1993
|
this.currentGeometry = geometry;
|
|
1873
1994
|
this.redraw();
|
|
1874
|
-
|
|
1875
|
-
if (changed) {
|
|
1876
|
-
this.syncHolesToDieline();
|
|
1877
|
-
}
|
|
1995
|
+
this.enforceConstraints();
|
|
1878
1996
|
};
|
|
1879
1997
|
this.context.eventBus.on(
|
|
1880
1998
|
"dieline:geometry:change",
|
|
@@ -1884,69 +2002,101 @@ var HoleTool = class {
|
|
|
1884
2002
|
const commandService = this.context.services.get("CommandService");
|
|
1885
2003
|
if (commandService) {
|
|
1886
2004
|
try {
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
Promise.resolve(geometry).then((g) => {
|
|
2005
|
+
Promise.resolve(commandService.executeCommand("getGeometry")).then(
|
|
2006
|
+
(g) => {
|
|
1890
2007
|
if (g) {
|
|
1891
2008
|
this.currentGeometry = g;
|
|
1892
|
-
this.
|
|
1893
|
-
this.initializeHoles();
|
|
2009
|
+
this.redraw();
|
|
1894
2010
|
}
|
|
1895
|
-
}
|
|
1896
|
-
|
|
2011
|
+
}
|
|
2012
|
+
);
|
|
1897
2013
|
} catch (e) {
|
|
1898
2014
|
}
|
|
1899
2015
|
}
|
|
1900
2016
|
if (!this.handleMoving) {
|
|
1901
2017
|
this.handleMoving = (e) => {
|
|
1902
|
-
var _a, _b, _c, _d
|
|
2018
|
+
var _a, _b, _c, _d;
|
|
1903
2019
|
const target = e.target;
|
|
1904
|
-
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "
|
|
2020
|
+
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "feature-marker") return;
|
|
1905
2021
|
if (!this.currentGeometry) return;
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
}
|
|
1918
|
-
const
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
constraintGeometry,
|
|
1922
|
-
(_d = holeData == null ? void 0 : holeData.innerRadius) != null ? _d : 15,
|
|
1923
|
-
(_e = holeData == null ? void 0 : holeData.outerRadius) != null ? _e : 25
|
|
2022
|
+
let feature;
|
|
2023
|
+
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
2024
|
+
const indices = (_c = target.data) == null ? void 0 : _c.indices;
|
|
2025
|
+
if (indices && indices.length > 0) {
|
|
2026
|
+
feature = this.features[indices[0]];
|
|
2027
|
+
}
|
|
2028
|
+
} else {
|
|
2029
|
+
const index = (_d = target.data) == null ? void 0 : _d.index;
|
|
2030
|
+
if (index !== void 0) {
|
|
2031
|
+
feature = this.features[index];
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
const geometry = this.getGeometryForFeature(
|
|
2035
|
+
this.currentGeometry,
|
|
2036
|
+
feature
|
|
1924
2037
|
);
|
|
2038
|
+
const p = new import_fabric4.Point(target.left, target.top);
|
|
2039
|
+
const markerStrokeWidth = (target.strokeWidth || 2) * (target.scaleX || 1);
|
|
2040
|
+
const minDim = Math.min(target.getScaledWidth(), target.getScaledHeight());
|
|
2041
|
+
const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
|
|
2042
|
+
const snapped = this.constrainPosition(p, geometry, limit, feature);
|
|
1925
2043
|
target.set({
|
|
1926
|
-
left:
|
|
1927
|
-
top:
|
|
2044
|
+
left: snapped.x,
|
|
2045
|
+
top: snapped.y
|
|
1928
2046
|
});
|
|
1929
2047
|
};
|
|
1930
2048
|
canvas.on("object:moving", this.handleMoving);
|
|
1931
2049
|
}
|
|
1932
2050
|
if (!this.handleModified) {
|
|
1933
2051
|
this.handleModified = (e) => {
|
|
1934
|
-
var _a;
|
|
2052
|
+
var _a, _b, _c, _d;
|
|
1935
2053
|
const target = e.target;
|
|
1936
|
-
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2054
|
+
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "feature-marker") return;
|
|
2055
|
+
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
2056
|
+
const groupObj = target;
|
|
2057
|
+
const indices = (_c = groupObj.data) == null ? void 0 : _c.indices;
|
|
2058
|
+
if (!indices) return;
|
|
2059
|
+
const groupCenter = new import_fabric4.Point(groupObj.left, groupObj.top);
|
|
2060
|
+
const newFeatures = [...this.features];
|
|
2061
|
+
const { x, y } = this.currentGeometry;
|
|
2062
|
+
groupObj.getObjects().forEach((child, i) => {
|
|
2063
|
+
const originalIndex = indices[i];
|
|
2064
|
+
const feature = this.features[originalIndex];
|
|
2065
|
+
const geometry = this.getGeometryForFeature(
|
|
2066
|
+
this.currentGeometry,
|
|
2067
|
+
feature
|
|
2068
|
+
);
|
|
2069
|
+
const { width, height } = geometry;
|
|
2070
|
+
const layoutLeft = x - width / 2;
|
|
2071
|
+
const layoutTop = y - height / 2;
|
|
2072
|
+
const absX = groupCenter.x + (child.left || 0);
|
|
2073
|
+
const absY = groupCenter.y + (child.top || 0);
|
|
2074
|
+
const normalizedX = width > 0 ? (absX - layoutLeft) / width : 0.5;
|
|
2075
|
+
const normalizedY = height > 0 ? (absY - layoutTop) / height : 0.5;
|
|
2076
|
+
newFeatures[originalIndex] = {
|
|
2077
|
+
...newFeatures[originalIndex],
|
|
2078
|
+
x: normalizedX,
|
|
2079
|
+
y: normalizedY
|
|
2080
|
+
};
|
|
2081
|
+
});
|
|
2082
|
+
this.features = newFeatures;
|
|
2083
|
+
const configService = (_d = this.context) == null ? void 0 : _d.services.get(
|
|
2084
|
+
"ConfigurationService"
|
|
2085
|
+
);
|
|
2086
|
+
if (configService) {
|
|
2087
|
+
this.isUpdatingConfig = true;
|
|
2088
|
+
try {
|
|
2089
|
+
configService.update("dieline.features", this.features);
|
|
2090
|
+
} finally {
|
|
2091
|
+
this.isUpdatingConfig = false;
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
} else {
|
|
2095
|
+
this.syncFeatureFromCanvas(target);
|
|
1940
2096
|
}
|
|
1941
2097
|
};
|
|
1942
2098
|
canvas.on("object:modified", this.handleModified);
|
|
1943
2099
|
}
|
|
1944
|
-
this.initializeHoles();
|
|
1945
|
-
}
|
|
1946
|
-
initializeHoles() {
|
|
1947
|
-
if (!this.canvasService) return;
|
|
1948
|
-
this.redraw();
|
|
1949
|
-
this.syncHolesToDieline();
|
|
1950
2100
|
}
|
|
1951
2101
|
teardown() {
|
|
1952
2102
|
if (!this.canvasService) return;
|
|
@@ -1968,357 +2118,274 @@ var HoleTool = class {
|
|
|
1968
2118
|
}
|
|
1969
2119
|
const objects = canvas.getObjects().filter((obj) => {
|
|
1970
2120
|
var _a;
|
|
1971
|
-
return ((_a = obj.data) == null ? void 0 : _a.type) === "
|
|
2121
|
+
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
1972
2122
|
});
|
|
1973
2123
|
objects.forEach((obj) => canvas.remove(obj));
|
|
1974
|
-
if (this.context) {
|
|
1975
|
-
const commandService = this.context.services.get("CommandService");
|
|
1976
|
-
if (commandService) {
|
|
1977
|
-
try {
|
|
1978
|
-
commandService.executeCommand("setHoles", []);
|
|
1979
|
-
} catch (e) {
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
}
|
|
1983
2124
|
this.canvasService.requestRenderAll();
|
|
1984
2125
|
}
|
|
1985
|
-
|
|
1986
|
-
if (
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
}
|
|
1992
|
-
);
|
|
1993
|
-
if (objects.length === 0 && this.holes.length > 0) {
|
|
1994
|
-
console.warn("HoleTool: No markers found on canvas to sync from");
|
|
1995
|
-
return;
|
|
1996
|
-
}
|
|
1997
|
-
objects.sort(
|
|
1998
|
-
(a, b) => {
|
|
1999
|
-
var _a, _b, _c, _d;
|
|
2000
|
-
return ((_b = (_a = a.data) == null ? void 0 : _a.index) != null ? _b : 0) - ((_d = (_c = b.data) == null ? void 0 : _c.index) != null ? _d : 0);
|
|
2001
|
-
}
|
|
2002
|
-
);
|
|
2003
|
-
const newHoles = objects.map((obj, i) => {
|
|
2004
|
-
var _a, _b, _c, _d;
|
|
2005
|
-
const original = this.holes[i];
|
|
2006
|
-
const newAbsX = obj.left;
|
|
2007
|
-
const newAbsY = obj.top;
|
|
2008
|
-
if (isNaN(newAbsX) || isNaN(newAbsY)) {
|
|
2009
|
-
console.error("HoleTool: Invalid marker coordinates", {
|
|
2010
|
-
newAbsX,
|
|
2011
|
-
newAbsY
|
|
2012
|
-
});
|
|
2013
|
-
return original;
|
|
2014
|
-
}
|
|
2015
|
-
const scale = ((_a = this.currentGeometry) == null ? void 0 : _a.scale) || 1;
|
|
2016
|
-
const unit = ((_b = this.currentGeometry) == null ? void 0 : _b.unit) || "mm";
|
|
2017
|
-
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
2018
|
-
if (original && original.anchor && this.currentGeometry) {
|
|
2019
|
-
const { x, y, width, height } = this.currentGeometry;
|
|
2020
|
-
let bx = x;
|
|
2021
|
-
let by = y;
|
|
2022
|
-
const left = x - width / 2;
|
|
2023
|
-
const right = x + width / 2;
|
|
2024
|
-
const top = y - height / 2;
|
|
2025
|
-
const bottom = y + height / 2;
|
|
2026
|
-
switch (original.anchor) {
|
|
2027
|
-
case "top-left":
|
|
2028
|
-
bx = left;
|
|
2029
|
-
by = top;
|
|
2030
|
-
break;
|
|
2031
|
-
case "top-center":
|
|
2032
|
-
bx = x;
|
|
2033
|
-
by = top;
|
|
2034
|
-
break;
|
|
2035
|
-
case "top-right":
|
|
2036
|
-
bx = right;
|
|
2037
|
-
by = top;
|
|
2038
|
-
break;
|
|
2039
|
-
case "center-left":
|
|
2040
|
-
bx = left;
|
|
2041
|
-
by = y;
|
|
2042
|
-
break;
|
|
2043
|
-
case "center":
|
|
2044
|
-
bx = x;
|
|
2045
|
-
by = y;
|
|
2046
|
-
break;
|
|
2047
|
-
case "center-right":
|
|
2048
|
-
bx = right;
|
|
2049
|
-
by = y;
|
|
2050
|
-
break;
|
|
2051
|
-
case "bottom-left":
|
|
2052
|
-
bx = left;
|
|
2053
|
-
by = bottom;
|
|
2054
|
-
break;
|
|
2055
|
-
case "bottom-center":
|
|
2056
|
-
bx = x;
|
|
2057
|
-
by = bottom;
|
|
2058
|
-
break;
|
|
2059
|
-
case "bottom-right":
|
|
2060
|
-
bx = right;
|
|
2061
|
-
by = bottom;
|
|
2062
|
-
break;
|
|
2063
|
-
}
|
|
2064
|
-
return {
|
|
2065
|
-
...original,
|
|
2066
|
-
// Denormalize offset back to physical units (mm)
|
|
2067
|
-
offsetX: (newAbsX - bx) / scale / unitScale,
|
|
2068
|
-
offsetY: (newAbsY - by) / scale / unitScale,
|
|
2069
|
-
// Clear direct coordinates if we use anchor
|
|
2070
|
-
x: void 0,
|
|
2071
|
-
y: void 0,
|
|
2072
|
-
// Ensure other properties are preserved
|
|
2073
|
-
innerRadius: original.innerRadius,
|
|
2074
|
-
outerRadius: original.outerRadius,
|
|
2075
|
-
shape: original.shape || "circle"
|
|
2076
|
-
};
|
|
2077
|
-
}
|
|
2078
|
-
let normalizedX = 0.5;
|
|
2079
|
-
let normalizedY = 0.5;
|
|
2080
|
-
if (this.currentGeometry) {
|
|
2081
|
-
const { x, y, width, height } = this.currentGeometry;
|
|
2082
|
-
const left = x - width / 2;
|
|
2083
|
-
const top = y - height / 2;
|
|
2084
|
-
normalizedX = width > 0 ? (newAbsX - left) / width : 0.5;
|
|
2085
|
-
normalizedY = height > 0 ? (newAbsY - top) / height : 0.5;
|
|
2086
|
-
} else {
|
|
2087
|
-
const { width, height } = this.canvasService.canvas;
|
|
2088
|
-
normalizedX = Coordinate.toNormalized(newAbsX, width || 800);
|
|
2089
|
-
normalizedY = Coordinate.toNormalized(newAbsY, height || 600);
|
|
2090
|
-
}
|
|
2126
|
+
constrainPosition(p, geometry, limit, feature) {
|
|
2127
|
+
if (feature && feature.placement === "internal") {
|
|
2128
|
+
const minX = geometry.x - geometry.width / 2;
|
|
2129
|
+
const maxX = geometry.x + geometry.width / 2;
|
|
2130
|
+
const minY = geometry.y - geometry.height / 2;
|
|
2131
|
+
const maxY = geometry.y + geometry.height / 2;
|
|
2091
2132
|
return {
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
y: normalizedY,
|
|
2095
|
-
// Clear offsets if we are using direct normalized coordinates
|
|
2096
|
-
offsetX: void 0,
|
|
2097
|
-
offsetY: void 0,
|
|
2098
|
-
// Ensure other properties are preserved
|
|
2099
|
-
innerRadius: (_c = original == null ? void 0 : original.innerRadius) != null ? _c : 15,
|
|
2100
|
-
outerRadius: (_d = original == null ? void 0 : original.outerRadius) != null ? _d : 25,
|
|
2101
|
-
shape: (original == null ? void 0 : original.shape) || "circle"
|
|
2133
|
+
x: Math.max(minX, Math.min(maxX, p.x)),
|
|
2134
|
+
y: Math.max(minY, Math.min(maxY, p.y))
|
|
2102
2135
|
};
|
|
2136
|
+
}
|
|
2137
|
+
const nearest = getNearestPointOnDieline({ x: p.x, y: p.y }, {
|
|
2138
|
+
...geometry,
|
|
2139
|
+
features: []
|
|
2103
2140
|
});
|
|
2104
|
-
|
|
2105
|
-
|
|
2141
|
+
const dx = p.x - nearest.x;
|
|
2142
|
+
const dy = p.y - nearest.y;
|
|
2143
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
2144
|
+
if (dist <= limit) {
|
|
2145
|
+
return { x: p.x, y: p.y };
|
|
2146
|
+
}
|
|
2147
|
+
const scale = limit / dist;
|
|
2148
|
+
return {
|
|
2149
|
+
x: nearest.x + dx * scale,
|
|
2150
|
+
y: nearest.y + dy * scale
|
|
2151
|
+
};
|
|
2106
2152
|
}
|
|
2107
|
-
|
|
2108
|
-
|
|
2153
|
+
syncFeatureFromCanvas(target) {
|
|
2154
|
+
var _a;
|
|
2155
|
+
if (!this.currentGeometry || !this.context) return;
|
|
2156
|
+
const index = (_a = target.data) == null ? void 0 : _a.index;
|
|
2157
|
+
if (index === void 0 || index < 0 || index >= this.features.length)
|
|
2158
|
+
return;
|
|
2159
|
+
const feature = this.features[index];
|
|
2160
|
+
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
2161
|
+
const { width, height, x, y } = geometry;
|
|
2162
|
+
const left = x - width / 2;
|
|
2163
|
+
const top = y - height / 2;
|
|
2164
|
+
const normalizedX = width > 0 ? (target.left - left) / width : 0.5;
|
|
2165
|
+
const normalizedY = height > 0 ? (target.top - top) / height : 0.5;
|
|
2166
|
+
const updatedFeature = {
|
|
2167
|
+
...feature,
|
|
2168
|
+
x: normalizedX,
|
|
2169
|
+
y: normalizedY
|
|
2170
|
+
// Could also update rotation if we allowed rotating markers
|
|
2171
|
+
};
|
|
2172
|
+
const newFeatures = [...this.features];
|
|
2173
|
+
newFeatures[index] = updatedFeature;
|
|
2174
|
+
this.features = newFeatures;
|
|
2109
2175
|
const configService = this.context.services.get(
|
|
2110
2176
|
"ConfigurationService"
|
|
2111
2177
|
);
|
|
2112
2178
|
if (configService) {
|
|
2113
2179
|
this.isUpdatingConfig = true;
|
|
2114
2180
|
try {
|
|
2115
|
-
configService.update("dieline.
|
|
2181
|
+
configService.update("dieline.features", this.features);
|
|
2116
2182
|
} finally {
|
|
2117
2183
|
this.isUpdatingConfig = false;
|
|
2118
2184
|
}
|
|
2119
2185
|
}
|
|
2120
2186
|
}
|
|
2121
2187
|
redraw() {
|
|
2122
|
-
if (!this.canvasService) return;
|
|
2188
|
+
if (!this.canvasService || !this.currentGeometry) return;
|
|
2123
2189
|
const canvas = this.canvasService.canvas;
|
|
2124
|
-
const
|
|
2190
|
+
const geometry = this.currentGeometry;
|
|
2125
2191
|
const existing = canvas.getObjects().filter((obj) => {
|
|
2126
2192
|
var _a;
|
|
2127
|
-
return ((_a = obj.data) == null ? void 0 : _a.type) === "
|
|
2193
|
+
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
2128
2194
|
});
|
|
2129
2195
|
existing.forEach((obj) => canvas.remove(obj));
|
|
2130
|
-
|
|
2131
|
-
if (!holes || holes.length === 0) {
|
|
2196
|
+
if (!this.features || this.features.length === 0) {
|
|
2132
2197
|
this.canvasService.requestRenderAll();
|
|
2133
2198
|
return;
|
|
2134
2199
|
}
|
|
2135
|
-
const
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2200
|
+
const scale = geometry.scale || 1;
|
|
2201
|
+
const finalScale = scale;
|
|
2202
|
+
const groups = {};
|
|
2203
|
+
const singles = [];
|
|
2204
|
+
this.features.forEach((f, i) => {
|
|
2205
|
+
if (f.groupId) {
|
|
2206
|
+
if (!groups[f.groupId]) groups[f.groupId] = [];
|
|
2207
|
+
groups[f.groupId].push({ feature: f, index: i });
|
|
2208
|
+
} else {
|
|
2209
|
+
singles.push({ feature: f, index: i });
|
|
2210
|
+
}
|
|
2211
|
+
});
|
|
2212
|
+
const createMarkerShape = (feature, pos) => {
|
|
2213
|
+
const featureScale = scale;
|
|
2214
|
+
const visualWidth = (feature.width || 10) * featureScale;
|
|
2215
|
+
const visualHeight = (feature.height || 10) * featureScale;
|
|
2216
|
+
const visualRadius = (feature.radius || 0) * featureScale;
|
|
2217
|
+
const color = feature.color || (feature.operation === "add" ? "#00FF00" : "#FF0000");
|
|
2218
|
+
const strokeDash = feature.strokeDash || (feature.operation === "subtract" ? [4, 4] : void 0);
|
|
2219
|
+
let shape;
|
|
2220
|
+
if (feature.shape === "rect") {
|
|
2221
|
+
shape = new import_fabric4.Rect({
|
|
2222
|
+
width: visualWidth,
|
|
2223
|
+
height: visualHeight,
|
|
2224
|
+
rx: visualRadius,
|
|
2225
|
+
ry: visualRadius,
|
|
2226
|
+
fill: "transparent",
|
|
2227
|
+
stroke: color,
|
|
2228
|
+
strokeWidth: 2,
|
|
2229
|
+
strokeDashArray: strokeDash,
|
|
2230
|
+
originX: "center",
|
|
2231
|
+
originY: "center",
|
|
2232
|
+
left: pos.x,
|
|
2233
|
+
top: pos.y
|
|
2234
|
+
});
|
|
2235
|
+
} else {
|
|
2236
|
+
shape = new import_fabric4.Circle({
|
|
2237
|
+
radius: visualRadius || 5 * finalScale,
|
|
2238
|
+
fill: "transparent",
|
|
2239
|
+
stroke: color,
|
|
2240
|
+
strokeWidth: 2,
|
|
2241
|
+
strokeDashArray: strokeDash,
|
|
2242
|
+
originX: "center",
|
|
2243
|
+
originY: "center",
|
|
2244
|
+
left: pos.x,
|
|
2245
|
+
top: pos.y
|
|
2246
|
+
});
|
|
2247
|
+
}
|
|
2248
|
+
if (feature.rotation) {
|
|
2249
|
+
shape.rotate(feature.rotation);
|
|
2250
|
+
}
|
|
2251
|
+
return shape;
|
|
2142
2252
|
};
|
|
2143
|
-
|
|
2144
|
-
const
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
const visualInnerRadius = hole.innerRadius * unitScale * scale;
|
|
2148
|
-
const visualOuterRadius = hole.outerRadius * unitScale * scale;
|
|
2149
|
-
const pos = resolveHolePosition(
|
|
2150
|
-
{
|
|
2151
|
-
...hole,
|
|
2152
|
-
offsetX: (hole.offsetX || 0) * unitScale * scale,
|
|
2153
|
-
offsetY: (hole.offsetY || 0) * unitScale * scale
|
|
2154
|
-
},
|
|
2155
|
-
geometry,
|
|
2156
|
-
{ width: geometry.width, height: geometry.height }
|
|
2157
|
-
// Use geometry dims instead of canvas
|
|
2253
|
+
singles.forEach(({ feature, index }) => {
|
|
2254
|
+
const geometry2 = this.getGeometryForFeature(
|
|
2255
|
+
this.currentGeometry,
|
|
2256
|
+
feature
|
|
2158
2257
|
);
|
|
2159
|
-
const
|
|
2160
|
-
const
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
strokeWidth: 2,
|
|
2173
|
-
originX: "center",
|
|
2174
|
-
originY: "center"
|
|
2258
|
+
const pos = resolveFeaturePosition(feature, geometry2);
|
|
2259
|
+
const marker = createMarkerShape(feature, pos);
|
|
2260
|
+
marker.set({
|
|
2261
|
+
visible: this.isToolActive,
|
|
2262
|
+
selectable: this.isToolActive,
|
|
2263
|
+
evented: this.isToolActive,
|
|
2264
|
+
hasControls: false,
|
|
2265
|
+
hasBorders: false,
|
|
2266
|
+
hoverCursor: "move",
|
|
2267
|
+
lockRotation: true,
|
|
2268
|
+
lockScalingX: true,
|
|
2269
|
+
lockScalingY: true,
|
|
2270
|
+
data: { type: "feature-marker", index, isGroup: false }
|
|
2175
2271
|
});
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
stroke: "#666",
|
|
2181
|
-
strokeWidth: 1,
|
|
2182
|
-
strokeDashArray: [5, 5],
|
|
2183
|
-
originX: "center",
|
|
2184
|
-
originY: "center"
|
|
2185
|
-
}) : new import_fabric4.Circle({
|
|
2186
|
-
radius: visualOuterRadius,
|
|
2187
|
-
fill: "transparent",
|
|
2188
|
-
stroke: "#666",
|
|
2189
|
-
strokeWidth: 1,
|
|
2190
|
-
strokeDashArray: [5, 5],
|
|
2191
|
-
originX: "center",
|
|
2192
|
-
originY: "center"
|
|
2272
|
+
marker.set("opacity", 0);
|
|
2273
|
+
marker.on("mouseover", () => {
|
|
2274
|
+
marker.set("opacity", 1);
|
|
2275
|
+
canvas.requestRenderAll();
|
|
2193
2276
|
});
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2277
|
+
marker.on("mouseout", () => {
|
|
2278
|
+
if (canvas.getActiveObject() !== marker) {
|
|
2279
|
+
marker.set("opacity", 0);
|
|
2280
|
+
canvas.requestRenderAll();
|
|
2281
|
+
}
|
|
2282
|
+
});
|
|
2283
|
+
marker.on("selected", () => {
|
|
2284
|
+
marker.set("opacity", 1);
|
|
2285
|
+
canvas.requestRenderAll();
|
|
2286
|
+
});
|
|
2287
|
+
marker.on("deselected", () => {
|
|
2288
|
+
marker.set("opacity", 0);
|
|
2289
|
+
canvas.requestRenderAll();
|
|
2290
|
+
});
|
|
2291
|
+
canvas.add(marker);
|
|
2292
|
+
canvas.bringObjectToFront(marker);
|
|
2293
|
+
});
|
|
2294
|
+
Object.keys(groups).forEach((groupId) => {
|
|
2295
|
+
const members = groups[groupId];
|
|
2296
|
+
if (members.length === 0) return;
|
|
2297
|
+
const shapes = members.map(({ feature }) => {
|
|
2298
|
+
const geometry2 = this.getGeometryForFeature(
|
|
2299
|
+
this.currentGeometry,
|
|
2300
|
+
feature
|
|
2301
|
+
);
|
|
2302
|
+
const pos = resolveFeaturePosition(feature, geometry2);
|
|
2303
|
+
return createMarkerShape(feature, pos);
|
|
2304
|
+
});
|
|
2305
|
+
const groupObj = new import_fabric4.Group(shapes, {
|
|
2306
|
+
visible: this.isToolActive,
|
|
2307
|
+
selectable: this.isToolActive,
|
|
2308
|
+
evented: this.isToolActive,
|
|
2200
2309
|
hasControls: false,
|
|
2201
|
-
// Don't allow resizing/rotating
|
|
2202
2310
|
hasBorders: false,
|
|
2203
|
-
subTargetCheck: false,
|
|
2204
|
-
opacity: 0,
|
|
2205
|
-
// Default hidden
|
|
2206
2311
|
hoverCursor: "move",
|
|
2207
|
-
|
|
2312
|
+
lockRotation: true,
|
|
2313
|
+
lockScalingX: true,
|
|
2314
|
+
lockScalingY: true,
|
|
2315
|
+
subTargetCheck: true,
|
|
2316
|
+
// Allow events to pass through if needed, but we treat as one
|
|
2317
|
+
interactive: false,
|
|
2318
|
+
// Children not interactive
|
|
2319
|
+
// @ts-ignore
|
|
2320
|
+
data: {
|
|
2321
|
+
type: "feature-marker",
|
|
2322
|
+
isGroup: true,
|
|
2323
|
+
groupId,
|
|
2324
|
+
indices: members.map((m) => m.index)
|
|
2325
|
+
}
|
|
2208
2326
|
});
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2327
|
+
groupObj.set("opacity", 0);
|
|
2328
|
+
groupObj.on("mouseover", () => {
|
|
2329
|
+
groupObj.set("opacity", 1);
|
|
2212
2330
|
canvas.requestRenderAll();
|
|
2213
2331
|
});
|
|
2214
|
-
|
|
2215
|
-
if (canvas.getActiveObject() !==
|
|
2216
|
-
|
|
2332
|
+
groupObj.on("mouseout", () => {
|
|
2333
|
+
if (canvas.getActiveObject() !== groupObj) {
|
|
2334
|
+
groupObj.set("opacity", 0);
|
|
2217
2335
|
canvas.requestRenderAll();
|
|
2218
2336
|
}
|
|
2219
2337
|
});
|
|
2220
|
-
|
|
2221
|
-
|
|
2338
|
+
groupObj.on("selected", () => {
|
|
2339
|
+
groupObj.set("opacity", 1);
|
|
2222
2340
|
canvas.requestRenderAll();
|
|
2223
2341
|
});
|
|
2224
|
-
|
|
2225
|
-
|
|
2342
|
+
groupObj.on("deselected", () => {
|
|
2343
|
+
groupObj.set("opacity", 0);
|
|
2226
2344
|
canvas.requestRenderAll();
|
|
2227
2345
|
});
|
|
2228
|
-
canvas.add(
|
|
2229
|
-
canvas.bringObjectToFront(
|
|
2230
|
-
});
|
|
2231
|
-
const markers = canvas.getObjects().filter((o) => {
|
|
2232
|
-
var _a;
|
|
2233
|
-
return ((_a = o.data) == null ? void 0 : _a.type) === "hole-marker";
|
|
2346
|
+
canvas.add(groupObj);
|
|
2347
|
+
canvas.bringObjectToFront(groupObj);
|
|
2234
2348
|
});
|
|
2235
|
-
markers.forEach((m) => canvas.bringObjectToFront(m));
|
|
2236
2349
|
this.canvasService.requestRenderAll();
|
|
2237
2350
|
}
|
|
2238
2351
|
enforceConstraints() {
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
}
|
|
2243
|
-
const effectiveOffset = this.constraintTarget === "original" ? 0 : geometry.offset;
|
|
2244
|
-
const constraintGeometry = {
|
|
2245
|
-
...geometry,
|
|
2246
|
-
width: Math.max(0, geometry.width + effectiveOffset * 2),
|
|
2247
|
-
height: Math.max(0, geometry.height + effectiveOffset * 2),
|
|
2248
|
-
radius: Math.max(0, geometry.radius + effectiveOffset)
|
|
2249
|
-
};
|
|
2250
|
-
const objects = this.canvasService.canvas.getObjects().filter((obj) => {
|
|
2352
|
+
if (!this.canvasService || !this.currentGeometry) return;
|
|
2353
|
+
const canvas = this.canvasService.canvas;
|
|
2354
|
+
const markers = canvas.getObjects().filter((obj) => {
|
|
2251
2355
|
var _a;
|
|
2252
|
-
return ((_a = obj.data) == null ? void 0 : _a.type) === "
|
|
2356
|
+
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
2253
2357
|
});
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2358
|
+
markers.forEach((marker) => {
|
|
2359
|
+
var _a, _b, _c;
|
|
2360
|
+
let feature;
|
|
2361
|
+
if ((_a = marker.data) == null ? void 0 : _a.isGroup) {
|
|
2362
|
+
const indices = (_b = marker.data) == null ? void 0 : _b.indices;
|
|
2363
|
+
if (indices && indices.length > 0) {
|
|
2364
|
+
feature = this.features[indices[0]];
|
|
2365
|
+
}
|
|
2366
|
+
} else {
|
|
2367
|
+
const index = (_c = marker.data) == null ? void 0 : _c.index;
|
|
2368
|
+
if (index !== void 0) {
|
|
2369
|
+
feature = this.features[index];
|
|
2370
|
+
}
|
|
2259
2371
|
}
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
var _a, _b;
|
|
2264
|
-
const currentPos = new import_fabric4.Point(obj.left, obj.top);
|
|
2265
|
-
const holeData = this.holes[i];
|
|
2266
|
-
const scale = geometry.scale || 1;
|
|
2267
|
-
const unit = geometry.unit || "mm";
|
|
2268
|
-
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
2269
|
-
const innerR = ((_a = holeData == null ? void 0 : holeData.innerRadius) != null ? _a : 15) * unitScale * scale;
|
|
2270
|
-
const outerR = ((_b = holeData == null ? void 0 : holeData.outerRadius) != null ? _b : 25) * unitScale * scale;
|
|
2271
|
-
const newPos = this.calculateConstrainedPosition(
|
|
2272
|
-
currentPos,
|
|
2273
|
-
constraintGeometry,
|
|
2274
|
-
innerR,
|
|
2275
|
-
outerR
|
|
2372
|
+
const geometry = this.getGeometryForFeature(
|
|
2373
|
+
this.currentGeometry,
|
|
2374
|
+
feature
|
|
2276
2375
|
);
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2376
|
+
const markerStrokeWidth = (marker.strokeWidth || 2) * (marker.scaleX || 1);
|
|
2377
|
+
const minDim = Math.min(marker.getScaledWidth(), marker.getScaledHeight());
|
|
2378
|
+
const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
|
|
2379
|
+
const snapped = this.constrainPosition(
|
|
2380
|
+
new import_fabric4.Point(marker.left, marker.top),
|
|
2381
|
+
geometry,
|
|
2382
|
+
limit,
|
|
2383
|
+
feature
|
|
2384
|
+
);
|
|
2385
|
+
marker.set({ left: snapped.x, top: snapped.y });
|
|
2386
|
+
marker.setCoords();
|
|
2285
2387
|
});
|
|
2286
|
-
|
|
2287
|
-
this.syncHolesFromCanvas();
|
|
2288
|
-
return true;
|
|
2289
|
-
}
|
|
2290
|
-
return false;
|
|
2291
|
-
}
|
|
2292
|
-
calculateConstrainedPosition(p, g, innerRadius, outerRadius) {
|
|
2293
|
-
const options = {
|
|
2294
|
-
...g,
|
|
2295
|
-
holes: []
|
|
2296
|
-
// We don't need holes for boundary calculation
|
|
2297
|
-
};
|
|
2298
|
-
const nearest = getNearestPointOnDieline(
|
|
2299
|
-
{ x: p.x, y: p.y },
|
|
2300
|
-
options
|
|
2301
|
-
);
|
|
2302
|
-
const nearestP = new import_fabric4.Point(nearest.x, nearest.y);
|
|
2303
|
-
const dist = p.distanceFrom(nearestP);
|
|
2304
|
-
const v = p.subtract(nearestP);
|
|
2305
|
-
const center = new import_fabric4.Point(g.x, g.y);
|
|
2306
|
-
const distToCenter = p.distanceFrom(center);
|
|
2307
|
-
const nearestDistToCenter = nearestP.distanceFrom(center);
|
|
2308
|
-
let signedDist = dist;
|
|
2309
|
-
if (distToCenter < nearestDistToCenter) {
|
|
2310
|
-
signedDist = -dist;
|
|
2311
|
-
}
|
|
2312
|
-
let clampedDist = signedDist;
|
|
2313
|
-
if (signedDist > 0) {
|
|
2314
|
-
clampedDist = Math.min(signedDist, innerRadius);
|
|
2315
|
-
} else {
|
|
2316
|
-
clampedDist = Math.max(signedDist, -outerRadius);
|
|
2317
|
-
}
|
|
2318
|
-
if (dist < 1e-3) return nearestP;
|
|
2319
|
-
const scale = Math.abs(clampedDist) / (dist || 1);
|
|
2320
|
-
const offset = v.scalarMultiply(scale);
|
|
2321
|
-
return nearestP.add(offset);
|
|
2388
|
+
canvas.requestRenderAll();
|
|
2322
2389
|
}
|
|
2323
2390
|
};
|
|
2324
2391
|
|
|
@@ -2335,6 +2402,11 @@ var ImageTool = class {
|
|
|
2335
2402
|
this.objectMap = /* @__PURE__ */ new Map();
|
|
2336
2403
|
this.loadResolvers = /* @__PURE__ */ new Map();
|
|
2337
2404
|
this.isUpdatingConfig = false;
|
|
2405
|
+
this.isToolActive = false;
|
|
2406
|
+
this.onToolActivated = (event) => {
|
|
2407
|
+
this.isToolActive = event.id === this.id;
|
|
2408
|
+
this.updateInteractivity();
|
|
2409
|
+
};
|
|
2338
2410
|
}
|
|
2339
2411
|
activate(context) {
|
|
2340
2412
|
this.context = context;
|
|
@@ -2343,6 +2415,7 @@ var ImageTool = class {
|
|
|
2343
2415
|
console.warn("CanvasService not found for ImageTool");
|
|
2344
2416
|
return;
|
|
2345
2417
|
}
|
|
2418
|
+
context.eventBus.on("tool:activated", this.onToolActivated);
|
|
2346
2419
|
const configService = context.services.get(
|
|
2347
2420
|
"ConfigurationService"
|
|
2348
2421
|
);
|
|
@@ -2360,6 +2433,7 @@ var ImageTool = class {
|
|
|
2360
2433
|
this.updateImages();
|
|
2361
2434
|
}
|
|
2362
2435
|
deactivate(context) {
|
|
2436
|
+
context.eventBus.off("tool:activated", this.onToolActivated);
|
|
2363
2437
|
if (this.canvasService) {
|
|
2364
2438
|
const layer = this.canvasService.getLayer("user");
|
|
2365
2439
|
if (layer) {
|
|
@@ -2373,6 +2447,18 @@ var ImageTool = class {
|
|
|
2373
2447
|
this.context = void 0;
|
|
2374
2448
|
}
|
|
2375
2449
|
}
|
|
2450
|
+
updateInteractivity() {
|
|
2451
|
+
var _a;
|
|
2452
|
+
this.objectMap.forEach((obj) => {
|
|
2453
|
+
obj.set({
|
|
2454
|
+
selectable: this.isToolActive,
|
|
2455
|
+
evented: this.isToolActive,
|
|
2456
|
+
hasControls: this.isToolActive,
|
|
2457
|
+
hasBorders: this.isToolActive
|
|
2458
|
+
});
|
|
2459
|
+
});
|
|
2460
|
+
(_a = this.canvasService) == null ? void 0 : _a.requestRenderAll();
|
|
2461
|
+
}
|
|
2376
2462
|
contribute() {
|
|
2377
2463
|
return {
|
|
2378
2464
|
[import_core5.ContributionPointIds.CONFIGURATIONS]: [
|
|
@@ -2560,6 +2646,14 @@ var ImageTool = class {
|
|
|
2560
2646
|
const layout = this.getLayoutInfo();
|
|
2561
2647
|
this.items.forEach((item, index) => {
|
|
2562
2648
|
let obj = this.objectMap.get(item.id);
|
|
2649
|
+
if (obj && obj.getSrc) {
|
|
2650
|
+
const currentSrc = obj.getSrc();
|
|
2651
|
+
if (currentSrc !== item.url) {
|
|
2652
|
+
layer.remove(obj);
|
|
2653
|
+
this.objectMap.delete(item.id);
|
|
2654
|
+
obj = void 0;
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2563
2657
|
if (!obj) {
|
|
2564
2658
|
this.loadImage(item, layer, layout);
|
|
2565
2659
|
} else {
|
|
@@ -2616,7 +2710,11 @@ var ImageTool = class {
|
|
|
2616
2710
|
originY: "center",
|
|
2617
2711
|
data: { id: item.id },
|
|
2618
2712
|
uniformScaling: true,
|
|
2619
|
-
lockScalingFlip: true
|
|
2713
|
+
lockScalingFlip: true,
|
|
2714
|
+
selectable: this.isToolActive,
|
|
2715
|
+
evented: this.isToolActive,
|
|
2716
|
+
hasControls: this.isToolActive,
|
|
2717
|
+
hasBorders: this.isToolActive
|
|
2620
2718
|
});
|
|
2621
2719
|
image.setControlsVisibility({
|
|
2622
2720
|
mt: false,
|
|
@@ -3467,6 +3565,24 @@ var CanvasService = class {
|
|
|
3467
3565
|
...options
|
|
3468
3566
|
});
|
|
3469
3567
|
}
|
|
3568
|
+
if (options == null ? void 0 : options.eventBus) {
|
|
3569
|
+
this.setEventBus(options.eventBus);
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
setEventBus(eventBus) {
|
|
3573
|
+
this.eventBus = eventBus;
|
|
3574
|
+
this.setupEvents();
|
|
3575
|
+
}
|
|
3576
|
+
setupEvents() {
|
|
3577
|
+
if (!this.eventBus) return;
|
|
3578
|
+
const bus = this.eventBus;
|
|
3579
|
+
const forward = (name) => (e) => bus.emit(name, e);
|
|
3580
|
+
this.canvas.on("selection:created", forward("selection:created"));
|
|
3581
|
+
this.canvas.on("selection:updated", forward("selection:updated"));
|
|
3582
|
+
this.canvas.on("selection:cleared", forward("selection:cleared"));
|
|
3583
|
+
this.canvas.on("object:modified", forward("object:modified"));
|
|
3584
|
+
this.canvas.on("object:added", forward("object:added"));
|
|
3585
|
+
this.canvas.on("object:removed", forward("object:removed"));
|
|
3470
3586
|
}
|
|
3471
3587
|
dispose() {
|
|
3472
3588
|
this.canvas.dispose();
|
|
@@ -3524,8 +3640,8 @@ var CanvasService = class {
|
|
|
3524
3640
|
BackgroundTool,
|
|
3525
3641
|
CanvasService,
|
|
3526
3642
|
DielineTool,
|
|
3643
|
+
FeatureTool,
|
|
3527
3644
|
FilmTool,
|
|
3528
|
-
HoleTool,
|
|
3529
3645
|
ImageTool,
|
|
3530
3646
|
MirrorTool,
|
|
3531
3647
|
RulerTool,
|