@pooder/kit 3.2.0 → 3.3.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 +6 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +124 -38
- package/dist/index.mjs +125 -39
- package/package.json +1 -1
- package/src/dieline.ts +10 -0
- package/src/geometry.ts +37 -11
- package/src/hole.ts +79 -29
- package/src/image.ts +37 -14
package/CHANGELOG.md
CHANGED
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -614,12 +614,25 @@ function getDielineShape(options) {
|
|
|
614
614
|
let lugsPath = null;
|
|
615
615
|
let cutsPath = null;
|
|
616
616
|
holes.forEach((hole) => {
|
|
617
|
-
const
|
|
618
|
-
|
|
617
|
+
const center = new import_paper.default.Point(hole.x, hole.y);
|
|
618
|
+
const lug = hole.shape === "square" ? new import_paper.default.Path.Rectangle({
|
|
619
|
+
point: [
|
|
620
|
+
center.x - hole.outerRadius,
|
|
621
|
+
center.y - hole.outerRadius
|
|
622
|
+
],
|
|
623
|
+
size: [hole.outerRadius * 2, hole.outerRadius * 2]
|
|
624
|
+
}) : new import_paper.default.Path.Circle({
|
|
625
|
+
center,
|
|
619
626
|
radius: hole.outerRadius
|
|
620
627
|
});
|
|
621
|
-
const cut = new import_paper.default.Path.
|
|
622
|
-
|
|
628
|
+
const cut = hole.shape === "square" ? new import_paper.default.Path.Rectangle({
|
|
629
|
+
point: [
|
|
630
|
+
center.x - hole.innerRadius,
|
|
631
|
+
center.y - hole.innerRadius
|
|
632
|
+
],
|
|
633
|
+
size: [hole.innerRadius * 2, hole.innerRadius * 2]
|
|
634
|
+
}) : new import_paper.default.Path.Circle({
|
|
635
|
+
center,
|
|
623
636
|
radius: hole.innerRadius
|
|
624
637
|
});
|
|
625
638
|
if (!lugsPath) {
|
|
@@ -676,7 +689,9 @@ function getDielineShape(options) {
|
|
|
676
689
|
return mainShape;
|
|
677
690
|
}
|
|
678
691
|
function generateDielinePath(options) {
|
|
679
|
-
|
|
692
|
+
const paperWidth = options.canvasWidth || options.width * 2 || 2e3;
|
|
693
|
+
const paperHeight = options.canvasHeight || options.height * 2 || 2e3;
|
|
694
|
+
ensurePaper(paperWidth, paperHeight);
|
|
680
695
|
import_paper.default.project.activeLayer.removeChildren();
|
|
681
696
|
const mainShape = getDielineShape(options);
|
|
682
697
|
const pathData = mainShape.pathData;
|
|
@@ -700,8 +715,9 @@ function generateMaskPath(options) {
|
|
|
700
715
|
return pathData;
|
|
701
716
|
}
|
|
702
717
|
function generateBleedZonePath(options, offset) {
|
|
703
|
-
const
|
|
704
|
-
|
|
718
|
+
const paperWidth = options.canvasWidth || options.width * 2 || 2e3;
|
|
719
|
+
const paperHeight = options.canvasHeight || options.height * 2 || 2e3;
|
|
720
|
+
ensurePaper(paperWidth, paperHeight);
|
|
705
721
|
import_paper.default.project.activeLayer.removeChildren();
|
|
706
722
|
const shapeOriginal = getDielineShape(options);
|
|
707
723
|
let shapeOffset;
|
|
@@ -1145,7 +1161,9 @@ var DielineTool = class {
|
|
|
1145
1161
|
x: cx,
|
|
1146
1162
|
y: cy,
|
|
1147
1163
|
holes: absoluteHoles,
|
|
1148
|
-
pathData: this.pathData
|
|
1164
|
+
pathData: this.pathData,
|
|
1165
|
+
canvasWidth: canvasW,
|
|
1166
|
+
canvasHeight: canvasH
|
|
1149
1167
|
});
|
|
1150
1168
|
const insideObj = new import_fabric2.Path(productPathData, {
|
|
1151
1169
|
fill: insideColor,
|
|
@@ -1168,7 +1186,9 @@ var DielineTool = class {
|
|
|
1168
1186
|
x: cx,
|
|
1169
1187
|
y: cy,
|
|
1170
1188
|
holes: absoluteHoles,
|
|
1171
|
-
pathData: this.pathData
|
|
1189
|
+
pathData: this.pathData,
|
|
1190
|
+
canvasWidth: canvasW,
|
|
1191
|
+
canvasHeight: canvasH
|
|
1172
1192
|
},
|
|
1173
1193
|
visualOffset
|
|
1174
1194
|
);
|
|
@@ -1195,7 +1215,9 @@ var DielineTool = class {
|
|
|
1195
1215
|
x: cx,
|
|
1196
1216
|
y: cy,
|
|
1197
1217
|
holes: absoluteHoles,
|
|
1198
|
-
pathData: this.pathData
|
|
1218
|
+
pathData: this.pathData,
|
|
1219
|
+
canvasWidth: canvasW,
|
|
1220
|
+
canvasHeight: canvasH
|
|
1199
1221
|
});
|
|
1200
1222
|
const offsetBorderObj = new import_fabric2.Path(offsetPathData, {
|
|
1201
1223
|
fill: null,
|
|
@@ -1219,7 +1241,9 @@ var DielineTool = class {
|
|
|
1219
1241
|
x: cx,
|
|
1220
1242
|
y: cy,
|
|
1221
1243
|
holes: absoluteHoles,
|
|
1222
|
-
pathData: this.pathData
|
|
1244
|
+
pathData: this.pathData,
|
|
1245
|
+
canvasWidth: canvasW,
|
|
1246
|
+
canvasHeight: canvasH
|
|
1223
1247
|
});
|
|
1224
1248
|
const borderObj = new import_fabric2.Path(borderPathData, {
|
|
1225
1249
|
fill: "transparent",
|
|
@@ -1334,7 +1358,9 @@ var DielineTool = class {
|
|
|
1334
1358
|
x: cx,
|
|
1335
1359
|
y: cy,
|
|
1336
1360
|
holes: absoluteHoles,
|
|
1337
|
-
pathData: this.pathData
|
|
1361
|
+
pathData: this.pathData,
|
|
1362
|
+
canvasWidth: canvasW,
|
|
1363
|
+
canvasHeight: canvasH
|
|
1338
1364
|
});
|
|
1339
1365
|
const clonedLayer = await userLayer.clone();
|
|
1340
1366
|
const clipPath = new import_fabric2.Path(pathData, {
|
|
@@ -1627,7 +1653,7 @@ var HoleTool = class {
|
|
|
1627
1653
|
command: "addHole",
|
|
1628
1654
|
title: "Add Hole",
|
|
1629
1655
|
handler: (x, y) => {
|
|
1630
|
-
var _a, _b, _c;
|
|
1656
|
+
var _a, _b, _c, _d;
|
|
1631
1657
|
if (!this.canvasService) return false;
|
|
1632
1658
|
let normalizedX = 0.5;
|
|
1633
1659
|
let normalizedY = 0.5;
|
|
@@ -1650,9 +1676,11 @@ var HoleTool = class {
|
|
|
1650
1676
|
const lastHole = currentHoles[currentHoles.length - 1];
|
|
1651
1677
|
const innerRadius = (_b = lastHole == null ? void 0 : lastHole.innerRadius) != null ? _b : 15;
|
|
1652
1678
|
const outerRadius = (_c = lastHole == null ? void 0 : lastHole.outerRadius) != null ? _c : 25;
|
|
1679
|
+
const shape = (_d = lastHole == null ? void 0 : lastHole.shape) != null ? _d : "circle";
|
|
1653
1680
|
const newHole = {
|
|
1654
1681
|
x: normalizedX,
|
|
1655
1682
|
y: normalizedY,
|
|
1683
|
+
shape,
|
|
1656
1684
|
innerRadius,
|
|
1657
1685
|
outerRadius
|
|
1658
1686
|
};
|
|
@@ -1684,6 +1712,7 @@ var HoleTool = class {
|
|
|
1684
1712
|
if (!this.handleDielineChange) {
|
|
1685
1713
|
this.handleDielineChange = (geometry) => {
|
|
1686
1714
|
this.currentGeometry = geometry;
|
|
1715
|
+
this.redraw();
|
|
1687
1716
|
const changed = this.enforceConstraints();
|
|
1688
1717
|
if (changed) {
|
|
1689
1718
|
this.syncHolesToDieline();
|
|
@@ -1797,10 +1826,16 @@ var HoleTool = class {
|
|
|
1797
1826
|
}
|
|
1798
1827
|
syncHolesFromCanvas() {
|
|
1799
1828
|
if (!this.canvasService) return;
|
|
1800
|
-
const objects = this.canvasService.canvas.getObjects().filter(
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1829
|
+
const objects = this.canvasService.canvas.getObjects().filter(
|
|
1830
|
+
(obj) => {
|
|
1831
|
+
var _a;
|
|
1832
|
+
return ((_a = obj.data) == null ? void 0 : _a.type) === "hole-marker" || obj.name === "hole-marker";
|
|
1833
|
+
}
|
|
1834
|
+
);
|
|
1835
|
+
if (objects.length === 0 && this.holes.length > 0) {
|
|
1836
|
+
console.warn("HoleTool: No markers found on canvas to sync from");
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1804
1839
|
objects.sort(
|
|
1805
1840
|
(a, b) => {
|
|
1806
1841
|
var _a, _b, _c, _d;
|
|
@@ -1812,6 +1847,13 @@ var HoleTool = class {
|
|
|
1812
1847
|
const original = this.holes[i];
|
|
1813
1848
|
const newAbsX = obj.left;
|
|
1814
1849
|
const newAbsY = obj.top;
|
|
1850
|
+
if (isNaN(newAbsX) || isNaN(newAbsY)) {
|
|
1851
|
+
console.error("HoleTool: Invalid marker coordinates", {
|
|
1852
|
+
newAbsX,
|
|
1853
|
+
newAbsY
|
|
1854
|
+
});
|
|
1855
|
+
return original;
|
|
1856
|
+
}
|
|
1815
1857
|
const scale = ((_a = this.currentGeometry) == null ? void 0 : _a.scale) || 1;
|
|
1816
1858
|
const unit = ((_b = this.currentGeometry) == null ? void 0 : _b.unit) || "mm";
|
|
1817
1859
|
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
@@ -1868,7 +1910,11 @@ var HoleTool = class {
|
|
|
1868
1910
|
offsetY: (newAbsY - by) / scale / unitScale,
|
|
1869
1911
|
// Clear direct coordinates if we use anchor
|
|
1870
1912
|
x: void 0,
|
|
1871
|
-
y: void 0
|
|
1913
|
+
y: void 0,
|
|
1914
|
+
// Ensure other properties are preserved
|
|
1915
|
+
innerRadius: original.innerRadius,
|
|
1916
|
+
outerRadius: original.outerRadius,
|
|
1917
|
+
shape: original.shape || "circle"
|
|
1872
1918
|
};
|
|
1873
1919
|
}
|
|
1874
1920
|
let normalizedX = 0.5;
|
|
@@ -1888,9 +1934,13 @@ var HoleTool = class {
|
|
|
1888
1934
|
...original,
|
|
1889
1935
|
x: normalizedX,
|
|
1890
1936
|
y: normalizedY,
|
|
1891
|
-
//
|
|
1937
|
+
// Clear offsets if we are using direct normalized coordinates
|
|
1938
|
+
offsetX: void 0,
|
|
1939
|
+
offsetY: void 0,
|
|
1940
|
+
// Ensure other properties are preserved
|
|
1892
1941
|
innerRadius: (_c = original == null ? void 0 : original.innerRadius) != null ? _c : 15,
|
|
1893
|
-
outerRadius: (_d = original == null ? void 0 : original.outerRadius) != null ? _d : 25
|
|
1942
|
+
outerRadius: (_d = original == null ? void 0 : original.outerRadius) != null ? _d : 25,
|
|
1943
|
+
shape: (original == null ? void 0 : original.shape) || "circle"
|
|
1894
1944
|
};
|
|
1895
1945
|
});
|
|
1896
1946
|
this.holes = newHoles;
|
|
@@ -1948,7 +1998,16 @@ var HoleTool = class {
|
|
|
1948
1998
|
{ width: geometry.width, height: geometry.height }
|
|
1949
1999
|
// Use geometry dims instead of canvas
|
|
1950
2000
|
);
|
|
1951
|
-
const
|
|
2001
|
+
const isSquare = hole.shape === "square";
|
|
2002
|
+
const innerMarker = isSquare ? new import_fabric4.Rect({
|
|
2003
|
+
width: visualInnerRadius * 2,
|
|
2004
|
+
height: visualInnerRadius * 2,
|
|
2005
|
+
fill: "transparent",
|
|
2006
|
+
stroke: "red",
|
|
2007
|
+
strokeWidth: 2,
|
|
2008
|
+
originX: "center",
|
|
2009
|
+
originY: "center"
|
|
2010
|
+
}) : new import_fabric4.Circle({
|
|
1952
2011
|
radius: visualInnerRadius,
|
|
1953
2012
|
fill: "transparent",
|
|
1954
2013
|
stroke: "red",
|
|
@@ -1956,7 +2015,16 @@ var HoleTool = class {
|
|
|
1956
2015
|
originX: "center",
|
|
1957
2016
|
originY: "center"
|
|
1958
2017
|
});
|
|
1959
|
-
const
|
|
2018
|
+
const outerMarker = isSquare ? new import_fabric4.Rect({
|
|
2019
|
+
width: visualOuterRadius * 2,
|
|
2020
|
+
height: visualOuterRadius * 2,
|
|
2021
|
+
fill: "transparent",
|
|
2022
|
+
stroke: "#666",
|
|
2023
|
+
strokeWidth: 1,
|
|
2024
|
+
strokeDashArray: [5, 5],
|
|
2025
|
+
originX: "center",
|
|
2026
|
+
originY: "center"
|
|
2027
|
+
}) : new import_fabric4.Circle({
|
|
1960
2028
|
radius: visualOuterRadius,
|
|
1961
2029
|
fill: "transparent",
|
|
1962
2030
|
stroke: "#666",
|
|
@@ -1965,7 +2033,7 @@ var HoleTool = class {
|
|
|
1965
2033
|
originX: "center",
|
|
1966
2034
|
originY: "center"
|
|
1967
2035
|
});
|
|
1968
|
-
const holeGroup = new import_fabric4.Group([
|
|
2036
|
+
const holeGroup = new import_fabric4.Group([outerMarker, innerMarker], {
|
|
1969
2037
|
left: pos.x,
|
|
1970
2038
|
top: pos.y,
|
|
1971
2039
|
originX: "center",
|
|
@@ -2293,12 +2361,25 @@ var ImageTool = class {
|
|
|
2293
2361
|
let visualHeight = canvasH;
|
|
2294
2362
|
let dielinePhysicalWidth = 500;
|
|
2295
2363
|
let dielinePhysicalHeight = 500;
|
|
2364
|
+
let bleedOffset = 0;
|
|
2296
2365
|
if (this.context) {
|
|
2297
2366
|
const configService = this.context.services.get("ConfigurationService");
|
|
2298
2367
|
if (configService) {
|
|
2299
2368
|
dielinePhysicalWidth = configService.get("dieline.width") || 500;
|
|
2300
2369
|
dielinePhysicalHeight = configService.get("dieline.height") || 500;
|
|
2301
|
-
|
|
2370
|
+
bleedOffset = configService.get("dieline.offset") || 0;
|
|
2371
|
+
const paddingValue = configService.get("dieline.padding") || 40;
|
|
2372
|
+
let padding = 0;
|
|
2373
|
+
if (typeof paddingValue === "number") {
|
|
2374
|
+
padding = paddingValue;
|
|
2375
|
+
} else if (typeof paddingValue === "string") {
|
|
2376
|
+
if (paddingValue.endsWith("%")) {
|
|
2377
|
+
const percent = parseFloat(paddingValue) / 100;
|
|
2378
|
+
padding = Math.min(canvasW, canvasH) * percent;
|
|
2379
|
+
} else {
|
|
2380
|
+
padding = parseFloat(paddingValue) || 0;
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2302
2383
|
const layout = Coordinate.calculateLayout(
|
|
2303
2384
|
{ width: canvasW, height: canvasH },
|
|
2304
2385
|
{ width: dielinePhysicalWidth, height: dielinePhysicalHeight },
|
|
@@ -2318,7 +2399,8 @@ var ImageTool = class {
|
|
|
2318
2399
|
visualWidth,
|
|
2319
2400
|
visualHeight,
|
|
2320
2401
|
dielinePhysicalWidth,
|
|
2321
|
-
dielinePhysicalHeight
|
|
2402
|
+
dielinePhysicalHeight,
|
|
2403
|
+
bleedOffset
|
|
2322
2404
|
};
|
|
2323
2405
|
}
|
|
2324
2406
|
updateImages() {
|
|
@@ -2385,22 +2467,26 @@ var ImageTool = class {
|
|
|
2385
2467
|
image.set({
|
|
2386
2468
|
originX: "center",
|
|
2387
2469
|
originY: "center",
|
|
2388
|
-
data: { id: item.id }
|
|
2470
|
+
data: { id: item.id },
|
|
2471
|
+
uniformScaling: true,
|
|
2472
|
+
lockScalingFlip: true
|
|
2473
|
+
});
|
|
2474
|
+
image.setControlsVisibility({
|
|
2475
|
+
mt: false,
|
|
2476
|
+
mb: false,
|
|
2477
|
+
ml: false,
|
|
2478
|
+
mr: false
|
|
2389
2479
|
});
|
|
2390
2480
|
let { width, height, left, top } = item;
|
|
2391
|
-
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, dielinePhysicalWidth, dielinePhysicalHeight } = layout;
|
|
2481
|
+
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, dielinePhysicalWidth, dielinePhysicalHeight, bleedOffset } = layout;
|
|
2392
2482
|
if (width === void 0 && height === void 0) {
|
|
2393
|
-
const
|
|
2394
|
-
const
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
const h = dielinePhysicalHeight;
|
|
2401
|
-
height = h;
|
|
2402
|
-
width = h * imgAspect;
|
|
2403
|
-
}
|
|
2483
|
+
const targetWidth = dielinePhysicalWidth + 2 * bleedOffset;
|
|
2484
|
+
const targetHeight = dielinePhysicalHeight + 2 * bleedOffset;
|
|
2485
|
+
const targetMax = Math.max(targetWidth, targetHeight);
|
|
2486
|
+
const imageMax = Math.max(image.width || 1, image.height || 1);
|
|
2487
|
+
const scale = targetMax / imageMax;
|
|
2488
|
+
width = (image.width || 1) * scale;
|
|
2489
|
+
height = (image.height || 1) * scale;
|
|
2404
2490
|
item.width = width;
|
|
2405
2491
|
item.height = height;
|
|
2406
2492
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -574,12 +574,25 @@ function getDielineShape(options) {
|
|
|
574
574
|
let lugsPath = null;
|
|
575
575
|
let cutsPath = null;
|
|
576
576
|
holes.forEach((hole) => {
|
|
577
|
-
const
|
|
578
|
-
|
|
577
|
+
const center = new paper.Point(hole.x, hole.y);
|
|
578
|
+
const lug = hole.shape === "square" ? new paper.Path.Rectangle({
|
|
579
|
+
point: [
|
|
580
|
+
center.x - hole.outerRadius,
|
|
581
|
+
center.y - hole.outerRadius
|
|
582
|
+
],
|
|
583
|
+
size: [hole.outerRadius * 2, hole.outerRadius * 2]
|
|
584
|
+
}) : new paper.Path.Circle({
|
|
585
|
+
center,
|
|
579
586
|
radius: hole.outerRadius
|
|
580
587
|
});
|
|
581
|
-
const cut = new paper.Path.
|
|
582
|
-
|
|
588
|
+
const cut = hole.shape === "square" ? new paper.Path.Rectangle({
|
|
589
|
+
point: [
|
|
590
|
+
center.x - hole.innerRadius,
|
|
591
|
+
center.y - hole.innerRadius
|
|
592
|
+
],
|
|
593
|
+
size: [hole.innerRadius * 2, hole.innerRadius * 2]
|
|
594
|
+
}) : new paper.Path.Circle({
|
|
595
|
+
center,
|
|
583
596
|
radius: hole.innerRadius
|
|
584
597
|
});
|
|
585
598
|
if (!lugsPath) {
|
|
@@ -636,7 +649,9 @@ function getDielineShape(options) {
|
|
|
636
649
|
return mainShape;
|
|
637
650
|
}
|
|
638
651
|
function generateDielinePath(options) {
|
|
639
|
-
|
|
652
|
+
const paperWidth = options.canvasWidth || options.width * 2 || 2e3;
|
|
653
|
+
const paperHeight = options.canvasHeight || options.height * 2 || 2e3;
|
|
654
|
+
ensurePaper(paperWidth, paperHeight);
|
|
640
655
|
paper.project.activeLayer.removeChildren();
|
|
641
656
|
const mainShape = getDielineShape(options);
|
|
642
657
|
const pathData = mainShape.pathData;
|
|
@@ -660,8 +675,9 @@ function generateMaskPath(options) {
|
|
|
660
675
|
return pathData;
|
|
661
676
|
}
|
|
662
677
|
function generateBleedZonePath(options, offset) {
|
|
663
|
-
const
|
|
664
|
-
|
|
678
|
+
const paperWidth = options.canvasWidth || options.width * 2 || 2e3;
|
|
679
|
+
const paperHeight = options.canvasHeight || options.height * 2 || 2e3;
|
|
680
|
+
ensurePaper(paperWidth, paperHeight);
|
|
665
681
|
paper.project.activeLayer.removeChildren();
|
|
666
682
|
const shapeOriginal = getDielineShape(options);
|
|
667
683
|
let shapeOffset;
|
|
@@ -1105,7 +1121,9 @@ var DielineTool = class {
|
|
|
1105
1121
|
x: cx,
|
|
1106
1122
|
y: cy,
|
|
1107
1123
|
holes: absoluteHoles,
|
|
1108
|
-
pathData: this.pathData
|
|
1124
|
+
pathData: this.pathData,
|
|
1125
|
+
canvasWidth: canvasW,
|
|
1126
|
+
canvasHeight: canvasH
|
|
1109
1127
|
});
|
|
1110
1128
|
const insideObj = new Path(productPathData, {
|
|
1111
1129
|
fill: insideColor,
|
|
@@ -1128,7 +1146,9 @@ var DielineTool = class {
|
|
|
1128
1146
|
x: cx,
|
|
1129
1147
|
y: cy,
|
|
1130
1148
|
holes: absoluteHoles,
|
|
1131
|
-
pathData: this.pathData
|
|
1149
|
+
pathData: this.pathData,
|
|
1150
|
+
canvasWidth: canvasW,
|
|
1151
|
+
canvasHeight: canvasH
|
|
1132
1152
|
},
|
|
1133
1153
|
visualOffset
|
|
1134
1154
|
);
|
|
@@ -1155,7 +1175,9 @@ var DielineTool = class {
|
|
|
1155
1175
|
x: cx,
|
|
1156
1176
|
y: cy,
|
|
1157
1177
|
holes: absoluteHoles,
|
|
1158
|
-
pathData: this.pathData
|
|
1178
|
+
pathData: this.pathData,
|
|
1179
|
+
canvasWidth: canvasW,
|
|
1180
|
+
canvasHeight: canvasH
|
|
1159
1181
|
});
|
|
1160
1182
|
const offsetBorderObj = new Path(offsetPathData, {
|
|
1161
1183
|
fill: null,
|
|
@@ -1179,7 +1201,9 @@ var DielineTool = class {
|
|
|
1179
1201
|
x: cx,
|
|
1180
1202
|
y: cy,
|
|
1181
1203
|
holes: absoluteHoles,
|
|
1182
|
-
pathData: this.pathData
|
|
1204
|
+
pathData: this.pathData,
|
|
1205
|
+
canvasWidth: canvasW,
|
|
1206
|
+
canvasHeight: canvasH
|
|
1183
1207
|
});
|
|
1184
1208
|
const borderObj = new Path(borderPathData, {
|
|
1185
1209
|
fill: "transparent",
|
|
@@ -1294,7 +1318,9 @@ var DielineTool = class {
|
|
|
1294
1318
|
x: cx,
|
|
1295
1319
|
y: cy,
|
|
1296
1320
|
holes: absoluteHoles,
|
|
1297
|
-
pathData: this.pathData
|
|
1321
|
+
pathData: this.pathData,
|
|
1322
|
+
canvasWidth: canvasW,
|
|
1323
|
+
canvasHeight: canvasH
|
|
1298
1324
|
});
|
|
1299
1325
|
const clonedLayer = await userLayer.clone();
|
|
1300
1326
|
const clipPath = new Path(pathData, {
|
|
@@ -1485,7 +1511,7 @@ var FilmTool = class {
|
|
|
1485
1511
|
import {
|
|
1486
1512
|
ContributionPointIds as ContributionPointIds4
|
|
1487
1513
|
} from "@pooder/core";
|
|
1488
|
-
import { Circle, Group, Point } from "fabric";
|
|
1514
|
+
import { Circle, Group, Point, Rect as Rect2 } from "fabric";
|
|
1489
1515
|
var HoleTool = class {
|
|
1490
1516
|
constructor(options) {
|
|
1491
1517
|
this.id = "pooder.kit.hole";
|
|
@@ -1591,7 +1617,7 @@ var HoleTool = class {
|
|
|
1591
1617
|
command: "addHole",
|
|
1592
1618
|
title: "Add Hole",
|
|
1593
1619
|
handler: (x, y) => {
|
|
1594
|
-
var _a, _b, _c;
|
|
1620
|
+
var _a, _b, _c, _d;
|
|
1595
1621
|
if (!this.canvasService) return false;
|
|
1596
1622
|
let normalizedX = 0.5;
|
|
1597
1623
|
let normalizedY = 0.5;
|
|
@@ -1614,9 +1640,11 @@ var HoleTool = class {
|
|
|
1614
1640
|
const lastHole = currentHoles[currentHoles.length - 1];
|
|
1615
1641
|
const innerRadius = (_b = lastHole == null ? void 0 : lastHole.innerRadius) != null ? _b : 15;
|
|
1616
1642
|
const outerRadius = (_c = lastHole == null ? void 0 : lastHole.outerRadius) != null ? _c : 25;
|
|
1643
|
+
const shape = (_d = lastHole == null ? void 0 : lastHole.shape) != null ? _d : "circle";
|
|
1617
1644
|
const newHole = {
|
|
1618
1645
|
x: normalizedX,
|
|
1619
1646
|
y: normalizedY,
|
|
1647
|
+
shape,
|
|
1620
1648
|
innerRadius,
|
|
1621
1649
|
outerRadius
|
|
1622
1650
|
};
|
|
@@ -1648,6 +1676,7 @@ var HoleTool = class {
|
|
|
1648
1676
|
if (!this.handleDielineChange) {
|
|
1649
1677
|
this.handleDielineChange = (geometry) => {
|
|
1650
1678
|
this.currentGeometry = geometry;
|
|
1679
|
+
this.redraw();
|
|
1651
1680
|
const changed = this.enforceConstraints();
|
|
1652
1681
|
if (changed) {
|
|
1653
1682
|
this.syncHolesToDieline();
|
|
@@ -1761,10 +1790,16 @@ var HoleTool = class {
|
|
|
1761
1790
|
}
|
|
1762
1791
|
syncHolesFromCanvas() {
|
|
1763
1792
|
if (!this.canvasService) return;
|
|
1764
|
-
const objects = this.canvasService.canvas.getObjects().filter(
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1793
|
+
const objects = this.canvasService.canvas.getObjects().filter(
|
|
1794
|
+
(obj) => {
|
|
1795
|
+
var _a;
|
|
1796
|
+
return ((_a = obj.data) == null ? void 0 : _a.type) === "hole-marker" || obj.name === "hole-marker";
|
|
1797
|
+
}
|
|
1798
|
+
);
|
|
1799
|
+
if (objects.length === 0 && this.holes.length > 0) {
|
|
1800
|
+
console.warn("HoleTool: No markers found on canvas to sync from");
|
|
1801
|
+
return;
|
|
1802
|
+
}
|
|
1768
1803
|
objects.sort(
|
|
1769
1804
|
(a, b) => {
|
|
1770
1805
|
var _a, _b, _c, _d;
|
|
@@ -1776,6 +1811,13 @@ var HoleTool = class {
|
|
|
1776
1811
|
const original = this.holes[i];
|
|
1777
1812
|
const newAbsX = obj.left;
|
|
1778
1813
|
const newAbsY = obj.top;
|
|
1814
|
+
if (isNaN(newAbsX) || isNaN(newAbsY)) {
|
|
1815
|
+
console.error("HoleTool: Invalid marker coordinates", {
|
|
1816
|
+
newAbsX,
|
|
1817
|
+
newAbsY
|
|
1818
|
+
});
|
|
1819
|
+
return original;
|
|
1820
|
+
}
|
|
1779
1821
|
const scale = ((_a = this.currentGeometry) == null ? void 0 : _a.scale) || 1;
|
|
1780
1822
|
const unit = ((_b = this.currentGeometry) == null ? void 0 : _b.unit) || "mm";
|
|
1781
1823
|
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
@@ -1832,7 +1874,11 @@ var HoleTool = class {
|
|
|
1832
1874
|
offsetY: (newAbsY - by) / scale / unitScale,
|
|
1833
1875
|
// Clear direct coordinates if we use anchor
|
|
1834
1876
|
x: void 0,
|
|
1835
|
-
y: void 0
|
|
1877
|
+
y: void 0,
|
|
1878
|
+
// Ensure other properties are preserved
|
|
1879
|
+
innerRadius: original.innerRadius,
|
|
1880
|
+
outerRadius: original.outerRadius,
|
|
1881
|
+
shape: original.shape || "circle"
|
|
1836
1882
|
};
|
|
1837
1883
|
}
|
|
1838
1884
|
let normalizedX = 0.5;
|
|
@@ -1852,9 +1898,13 @@ var HoleTool = class {
|
|
|
1852
1898
|
...original,
|
|
1853
1899
|
x: normalizedX,
|
|
1854
1900
|
y: normalizedY,
|
|
1855
|
-
//
|
|
1901
|
+
// Clear offsets if we are using direct normalized coordinates
|
|
1902
|
+
offsetX: void 0,
|
|
1903
|
+
offsetY: void 0,
|
|
1904
|
+
// Ensure other properties are preserved
|
|
1856
1905
|
innerRadius: (_c = original == null ? void 0 : original.innerRadius) != null ? _c : 15,
|
|
1857
|
-
outerRadius: (_d = original == null ? void 0 : original.outerRadius) != null ? _d : 25
|
|
1906
|
+
outerRadius: (_d = original == null ? void 0 : original.outerRadius) != null ? _d : 25,
|
|
1907
|
+
shape: (original == null ? void 0 : original.shape) || "circle"
|
|
1858
1908
|
};
|
|
1859
1909
|
});
|
|
1860
1910
|
this.holes = newHoles;
|
|
@@ -1912,7 +1962,16 @@ var HoleTool = class {
|
|
|
1912
1962
|
{ width: geometry.width, height: geometry.height }
|
|
1913
1963
|
// Use geometry dims instead of canvas
|
|
1914
1964
|
);
|
|
1915
|
-
const
|
|
1965
|
+
const isSquare = hole.shape === "square";
|
|
1966
|
+
const innerMarker = isSquare ? new Rect2({
|
|
1967
|
+
width: visualInnerRadius * 2,
|
|
1968
|
+
height: visualInnerRadius * 2,
|
|
1969
|
+
fill: "transparent",
|
|
1970
|
+
stroke: "red",
|
|
1971
|
+
strokeWidth: 2,
|
|
1972
|
+
originX: "center",
|
|
1973
|
+
originY: "center"
|
|
1974
|
+
}) : new Circle({
|
|
1916
1975
|
radius: visualInnerRadius,
|
|
1917
1976
|
fill: "transparent",
|
|
1918
1977
|
stroke: "red",
|
|
@@ -1920,7 +1979,16 @@ var HoleTool = class {
|
|
|
1920
1979
|
originX: "center",
|
|
1921
1980
|
originY: "center"
|
|
1922
1981
|
});
|
|
1923
|
-
const
|
|
1982
|
+
const outerMarker = isSquare ? new Rect2({
|
|
1983
|
+
width: visualOuterRadius * 2,
|
|
1984
|
+
height: visualOuterRadius * 2,
|
|
1985
|
+
fill: "transparent",
|
|
1986
|
+
stroke: "#666",
|
|
1987
|
+
strokeWidth: 1,
|
|
1988
|
+
strokeDashArray: [5, 5],
|
|
1989
|
+
originX: "center",
|
|
1990
|
+
originY: "center"
|
|
1991
|
+
}) : new Circle({
|
|
1924
1992
|
radius: visualOuterRadius,
|
|
1925
1993
|
fill: "transparent",
|
|
1926
1994
|
stroke: "#666",
|
|
@@ -1929,7 +1997,7 @@ var HoleTool = class {
|
|
|
1929
1997
|
originX: "center",
|
|
1930
1998
|
originY: "center"
|
|
1931
1999
|
});
|
|
1932
|
-
const holeGroup = new Group([
|
|
2000
|
+
const holeGroup = new Group([outerMarker, innerMarker], {
|
|
1933
2001
|
left: pos.x,
|
|
1934
2002
|
top: pos.y,
|
|
1935
2003
|
originX: "center",
|
|
@@ -2259,12 +2327,25 @@ var ImageTool = class {
|
|
|
2259
2327
|
let visualHeight = canvasH;
|
|
2260
2328
|
let dielinePhysicalWidth = 500;
|
|
2261
2329
|
let dielinePhysicalHeight = 500;
|
|
2330
|
+
let bleedOffset = 0;
|
|
2262
2331
|
if (this.context) {
|
|
2263
2332
|
const configService = this.context.services.get("ConfigurationService");
|
|
2264
2333
|
if (configService) {
|
|
2265
2334
|
dielinePhysicalWidth = configService.get("dieline.width") || 500;
|
|
2266
2335
|
dielinePhysicalHeight = configService.get("dieline.height") || 500;
|
|
2267
|
-
|
|
2336
|
+
bleedOffset = configService.get("dieline.offset") || 0;
|
|
2337
|
+
const paddingValue = configService.get("dieline.padding") || 40;
|
|
2338
|
+
let padding = 0;
|
|
2339
|
+
if (typeof paddingValue === "number") {
|
|
2340
|
+
padding = paddingValue;
|
|
2341
|
+
} else if (typeof paddingValue === "string") {
|
|
2342
|
+
if (paddingValue.endsWith("%")) {
|
|
2343
|
+
const percent = parseFloat(paddingValue) / 100;
|
|
2344
|
+
padding = Math.min(canvasW, canvasH) * percent;
|
|
2345
|
+
} else {
|
|
2346
|
+
padding = parseFloat(paddingValue) || 0;
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2268
2349
|
const layout = Coordinate.calculateLayout(
|
|
2269
2350
|
{ width: canvasW, height: canvasH },
|
|
2270
2351
|
{ width: dielinePhysicalWidth, height: dielinePhysicalHeight },
|
|
@@ -2284,7 +2365,8 @@ var ImageTool = class {
|
|
|
2284
2365
|
visualWidth,
|
|
2285
2366
|
visualHeight,
|
|
2286
2367
|
dielinePhysicalWidth,
|
|
2287
|
-
dielinePhysicalHeight
|
|
2368
|
+
dielinePhysicalHeight,
|
|
2369
|
+
bleedOffset
|
|
2288
2370
|
};
|
|
2289
2371
|
}
|
|
2290
2372
|
updateImages() {
|
|
@@ -2351,22 +2433,26 @@ var ImageTool = class {
|
|
|
2351
2433
|
image.set({
|
|
2352
2434
|
originX: "center",
|
|
2353
2435
|
originY: "center",
|
|
2354
|
-
data: { id: item.id }
|
|
2436
|
+
data: { id: item.id },
|
|
2437
|
+
uniformScaling: true,
|
|
2438
|
+
lockScalingFlip: true
|
|
2439
|
+
});
|
|
2440
|
+
image.setControlsVisibility({
|
|
2441
|
+
mt: false,
|
|
2442
|
+
mb: false,
|
|
2443
|
+
ml: false,
|
|
2444
|
+
mr: false
|
|
2355
2445
|
});
|
|
2356
2446
|
let { width, height, left, top } = item;
|
|
2357
|
-
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, dielinePhysicalWidth, dielinePhysicalHeight } = layout;
|
|
2447
|
+
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, dielinePhysicalWidth, dielinePhysicalHeight, bleedOffset } = layout;
|
|
2358
2448
|
if (width === void 0 && height === void 0) {
|
|
2359
|
-
const
|
|
2360
|
-
const
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
const h = dielinePhysicalHeight;
|
|
2367
|
-
height = h;
|
|
2368
|
-
width = h * imgAspect;
|
|
2369
|
-
}
|
|
2449
|
+
const targetWidth = dielinePhysicalWidth + 2 * bleedOffset;
|
|
2450
|
+
const targetHeight = dielinePhysicalHeight + 2 * bleedOffset;
|
|
2451
|
+
const targetMax = Math.max(targetWidth, targetHeight);
|
|
2452
|
+
const imageMax = Math.max(image.width || 1, image.height || 1);
|
|
2453
|
+
const scale = targetMax / imageMax;
|
|
2454
|
+
width = (image.width || 1) * scale;
|
|
2455
|
+
height = (image.height || 1) * scale;
|
|
2370
2456
|
item.width = width;
|
|
2371
2457
|
item.height = height;
|
|
2372
2458
|
}
|
package/package.json
CHANGED
package/src/dieline.ts
CHANGED
|
@@ -493,6 +493,8 @@ export class DielineTool implements Extension {
|
|
|
493
493
|
y: cy,
|
|
494
494
|
holes: absoluteHoles,
|
|
495
495
|
pathData: this.pathData,
|
|
496
|
+
canvasWidth: canvasW,
|
|
497
|
+
canvasHeight: canvasH,
|
|
496
498
|
});
|
|
497
499
|
|
|
498
500
|
const insideObj = new Path(productPathData, {
|
|
@@ -518,6 +520,8 @@ export class DielineTool implements Extension {
|
|
|
518
520
|
y: cy,
|
|
519
521
|
holes: absoluteHoles,
|
|
520
522
|
pathData: this.pathData,
|
|
523
|
+
canvasWidth: canvasW,
|
|
524
|
+
canvasHeight: canvasH,
|
|
521
525
|
},
|
|
522
526
|
visualOffset,
|
|
523
527
|
);
|
|
@@ -549,6 +553,8 @@ export class DielineTool implements Extension {
|
|
|
549
553
|
y: cy,
|
|
550
554
|
holes: absoluteHoles,
|
|
551
555
|
pathData: this.pathData,
|
|
556
|
+
canvasWidth: canvasW,
|
|
557
|
+
canvasHeight: canvasH,
|
|
552
558
|
});
|
|
553
559
|
|
|
554
560
|
const offsetBorderObj = new Path(offsetPathData, {
|
|
@@ -577,6 +583,8 @@ export class DielineTool implements Extension {
|
|
|
577
583
|
y: cy,
|
|
578
584
|
holes: absoluteHoles,
|
|
579
585
|
pathData: this.pathData,
|
|
586
|
+
canvasWidth: canvasW,
|
|
587
|
+
canvasHeight: canvasH,
|
|
580
588
|
});
|
|
581
589
|
|
|
582
590
|
const borderObj = new Path(borderPathData, {
|
|
@@ -730,6 +738,8 @@ export class DielineTool implements Extension {
|
|
|
730
738
|
y: cy,
|
|
731
739
|
holes: absoluteHoles,
|
|
732
740
|
pathData: this.pathData,
|
|
741
|
+
canvasWidth: canvasW,
|
|
742
|
+
canvasHeight: canvasH,
|
|
733
743
|
});
|
|
734
744
|
|
|
735
745
|
// 2. Prepare for Export
|
package/src/geometry.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type PositionAnchor =
|
|
|
14
14
|
export interface HoleData {
|
|
15
15
|
x?: number;
|
|
16
16
|
y?: number;
|
|
17
|
+
shape?: "circle" | "square";
|
|
17
18
|
anchor?: PositionAnchor;
|
|
18
19
|
offsetX?: number;
|
|
19
20
|
offsetY?: number;
|
|
@@ -103,6 +104,8 @@ export interface GeometryOptions {
|
|
|
103
104
|
y: number;
|
|
104
105
|
holes: Array<HoleData>;
|
|
105
106
|
pathData?: string;
|
|
107
|
+
canvasWidth?: number;
|
|
108
|
+
canvasHeight?: number;
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
export interface MaskGeometryOptions extends GeometryOptions {
|
|
@@ -287,21 +290,41 @@ function getDielineShape(options: GeometryOptions): paper.PathItem {
|
|
|
287
290
|
let cutsPath: paper.PathItem | null = null;
|
|
288
291
|
|
|
289
292
|
holes.forEach((hole) => {
|
|
293
|
+
const center = new paper.Point(hole.x!, hole.y!);
|
|
294
|
+
|
|
290
295
|
// Create Lug (Outer Radius)
|
|
291
|
-
const lug =
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
296
|
+
const lug =
|
|
297
|
+
hole.shape === "square"
|
|
298
|
+
? new paper.Path.Rectangle({
|
|
299
|
+
point: [
|
|
300
|
+
center.x - hole.outerRadius,
|
|
301
|
+
center.y - hole.outerRadius,
|
|
302
|
+
],
|
|
303
|
+
size: [hole.outerRadius * 2, hole.outerRadius * 2],
|
|
304
|
+
})
|
|
305
|
+
: new paper.Path.Circle({
|
|
306
|
+
center: center,
|
|
307
|
+
radius: hole.outerRadius,
|
|
308
|
+
});
|
|
295
309
|
|
|
296
310
|
// REMOVED: Intersects check. We want to process all holes defined in config.
|
|
297
311
|
// If a hole is completely outside, it might form an island, but that's better than missing it.
|
|
298
312
|
// Users can remove the hole if they don't want it.
|
|
299
313
|
|
|
300
314
|
// Create Cut (Inner Radius)
|
|
301
|
-
const cut =
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
315
|
+
const cut =
|
|
316
|
+
hole.shape === "square"
|
|
317
|
+
? new paper.Path.Rectangle({
|
|
318
|
+
point: [
|
|
319
|
+
center.x - hole.innerRadius,
|
|
320
|
+
center.y - hole.innerRadius,
|
|
321
|
+
],
|
|
322
|
+
size: [hole.innerRadius * 2, hole.innerRadius * 2],
|
|
323
|
+
})
|
|
324
|
+
: new paper.Path.Circle({
|
|
325
|
+
center: center,
|
|
326
|
+
radius: hole.innerRadius,
|
|
327
|
+
});
|
|
305
328
|
|
|
306
329
|
// Union Lugs
|
|
307
330
|
if (!lugsPath) {
|
|
@@ -373,7 +396,9 @@ function getDielineShape(options: GeometryOptions): paper.PathItem {
|
|
|
373
396
|
* Logic: (BaseShape UNION IntersectingLugs) SUBTRACT Cuts
|
|
374
397
|
*/
|
|
375
398
|
export function generateDielinePath(options: GeometryOptions): string {
|
|
376
|
-
|
|
399
|
+
const paperWidth = options.canvasWidth || options.width * 2 || 2000;
|
|
400
|
+
const paperHeight = options.canvasHeight || options.height * 2 || 2000;
|
|
401
|
+
ensurePaper(paperWidth, paperHeight);
|
|
377
402
|
paper.project.activeLayer.removeChildren();
|
|
378
403
|
|
|
379
404
|
const mainShape = getDielineShape(options);
|
|
@@ -423,8 +448,9 @@ export function generateBleedZonePath(
|
|
|
423
448
|
offset: number,
|
|
424
449
|
): string {
|
|
425
450
|
// Ensure canvas is large enough
|
|
426
|
-
const
|
|
427
|
-
|
|
451
|
+
const paperWidth = options.canvasWidth || options.width * 2 || 2000;
|
|
452
|
+
const paperHeight = options.canvasHeight || options.height * 2 || 2000;
|
|
453
|
+
ensurePaper(paperWidth, paperHeight);
|
|
428
454
|
paper.project.activeLayer.removeChildren();
|
|
429
455
|
|
|
430
456
|
// 1. Original Shape
|
package/src/hole.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
ConfigurationContribution,
|
|
7
7
|
ConfigurationService,
|
|
8
8
|
} from "@pooder/core";
|
|
9
|
-
import { Circle, Group, Point } from "fabric";
|
|
9
|
+
import { Circle, Group, Point, Rect } from "fabric";
|
|
10
10
|
import CanvasService from "./CanvasService";
|
|
11
11
|
import { DielineGeometry } from "./dieline";
|
|
12
12
|
import {
|
|
@@ -179,10 +179,12 @@ export class HoleTool implements Extension {
|
|
|
179
179
|
const lastHole = currentHoles[currentHoles.length - 1];
|
|
180
180
|
const innerRadius = lastHole?.innerRadius ?? 15;
|
|
181
181
|
const outerRadius = lastHole?.outerRadius ?? 25;
|
|
182
|
+
const shape = lastHole?.shape ?? "circle";
|
|
182
183
|
|
|
183
184
|
const newHole = {
|
|
184
185
|
x: normalizedX,
|
|
185
186
|
y: normalizedY,
|
|
187
|
+
shape,
|
|
186
188
|
innerRadius,
|
|
187
189
|
outerRadius,
|
|
188
190
|
};
|
|
@@ -216,6 +218,7 @@ export class HoleTool implements Extension {
|
|
|
216
218
|
if (!this.handleDielineChange) {
|
|
217
219
|
this.handleDielineChange = (geometry: DielineGeometry) => {
|
|
218
220
|
this.currentGeometry = geometry;
|
|
221
|
+
this.redraw();
|
|
219
222
|
const changed = this.enforceConstraints();
|
|
220
223
|
// Only sync if constraints actually moved something
|
|
221
224
|
if (changed) {
|
|
@@ -367,21 +370,38 @@ export class HoleTool implements Extension {
|
|
|
367
370
|
if (!this.canvasService) return;
|
|
368
371
|
const objects = this.canvasService.canvas
|
|
369
372
|
.getObjects()
|
|
370
|
-
.filter(
|
|
373
|
+
.filter(
|
|
374
|
+
(obj: any) =>
|
|
375
|
+
obj.data?.type === "hole-marker" || obj.name === "hole-marker",
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
// If we have markers but no state, or mismatch, we should be careful.
|
|
379
|
+
// However, if we just dragged one, we expect them to match.
|
|
380
|
+
if (objects.length === 0 && this.holes.length > 0) {
|
|
381
|
+
console.warn("HoleTool: No markers found on canvas to sync from");
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
371
384
|
|
|
372
|
-
// Sort objects by index
|
|
385
|
+
// Sort objects by index to match this.holes order
|
|
373
386
|
objects.sort(
|
|
374
|
-
(a: any, b: any) => (a.data?.index ?? 0) - (b.data?.index ?? 0)
|
|
387
|
+
(a: any, b: any) => (a.data?.index ?? 0) - (b.data?.index ?? 0),
|
|
375
388
|
);
|
|
376
389
|
|
|
377
390
|
// Update holes based on canvas positions
|
|
378
|
-
// We need to preserve original hole properties (radii, anchor)
|
|
379
|
-
// If a hole has an anchor, we update offsetX/Y instead of x/y
|
|
380
391
|
const newHoles = objects.map((obj, i) => {
|
|
381
392
|
const original = this.holes[i];
|
|
382
393
|
const newAbsX = obj.left!;
|
|
383
394
|
const newAbsY = obj.top!;
|
|
384
395
|
|
|
396
|
+
// Validate coordinates to prevent NaN issues
|
|
397
|
+
if (isNaN(newAbsX) || isNaN(newAbsY)) {
|
|
398
|
+
console.error("HoleTool: Invalid marker coordinates", {
|
|
399
|
+
newAbsX,
|
|
400
|
+
newAbsY,
|
|
401
|
+
});
|
|
402
|
+
return original;
|
|
403
|
+
}
|
|
404
|
+
|
|
385
405
|
// Get current scale to denormalize offsets
|
|
386
406
|
const scale = this.currentGeometry?.scale || 1;
|
|
387
407
|
const unit = this.currentGeometry?.unit || "mm";
|
|
@@ -435,7 +455,7 @@ export class HoleTool implements Extension {
|
|
|
435
455
|
by = bottom;
|
|
436
456
|
break;
|
|
437
457
|
}
|
|
438
|
-
|
|
458
|
+
|
|
439
459
|
return {
|
|
440
460
|
...original,
|
|
441
461
|
// Denormalize offset back to physical units (mm)
|
|
@@ -444,11 +464,14 @@ export class HoleTool implements Extension {
|
|
|
444
464
|
// Clear direct coordinates if we use anchor
|
|
445
465
|
x: undefined,
|
|
446
466
|
y: undefined,
|
|
467
|
+
// Ensure other properties are preserved
|
|
468
|
+
innerRadius: original.innerRadius,
|
|
469
|
+
outerRadius: original.outerRadius,
|
|
470
|
+
shape: original.shape || "circle",
|
|
447
471
|
};
|
|
448
472
|
}
|
|
449
473
|
|
|
450
474
|
// If no anchor, use normalized coordinates relative to Dieline Geometry
|
|
451
|
-
// normalized = (absolute - (center - width/2)) / width
|
|
452
475
|
let normalizedX = 0.5;
|
|
453
476
|
let normalizedY = 0.5;
|
|
454
477
|
|
|
@@ -459,19 +482,23 @@ export class HoleTool implements Extension {
|
|
|
459
482
|
normalizedX = width > 0 ? (newAbsX - left) / width : 0.5;
|
|
460
483
|
normalizedY = height > 0 ? (newAbsY - top) / height : 0.5;
|
|
461
484
|
} else {
|
|
462
|
-
// Fallback to Canvas normalization
|
|
485
|
+
// Fallback to Canvas normalization
|
|
463
486
|
const { width, height } = this.canvasService!.canvas;
|
|
464
487
|
normalizedX = Coordinate.toNormalized(newAbsX, width || 800);
|
|
465
488
|
normalizedY = Coordinate.toNormalized(newAbsY, height || 600);
|
|
466
489
|
}
|
|
467
|
-
|
|
490
|
+
|
|
468
491
|
return {
|
|
469
492
|
...original,
|
|
470
493
|
x: normalizedX,
|
|
471
494
|
y: normalizedY,
|
|
472
|
-
//
|
|
495
|
+
// Clear offsets if we are using direct normalized coordinates
|
|
496
|
+
offsetX: undefined,
|
|
497
|
+
offsetY: undefined,
|
|
498
|
+
// Ensure other properties are preserved
|
|
473
499
|
innerRadius: original?.innerRadius ?? 15,
|
|
474
500
|
outerRadius: original?.outerRadius ?? 25,
|
|
501
|
+
shape: original?.shape || "circle",
|
|
475
502
|
};
|
|
476
503
|
});
|
|
477
504
|
|
|
@@ -544,26 +571,49 @@ export class HoleTool implements Extension {
|
|
|
544
571
|
{ width: geometry.width, height: geometry.height } // Use geometry dims instead of canvas
|
|
545
572
|
);
|
|
546
573
|
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
574
|
+
const isSquare = hole.shape === "square";
|
|
575
|
+
|
|
576
|
+
const innerMarker = isSquare
|
|
577
|
+
? new Rect({
|
|
578
|
+
width: visualInnerRadius * 2,
|
|
579
|
+
height: visualInnerRadius * 2,
|
|
580
|
+
fill: "transparent",
|
|
581
|
+
stroke: "red",
|
|
582
|
+
strokeWidth: 2,
|
|
583
|
+
originX: "center",
|
|
584
|
+
originY: "center",
|
|
585
|
+
})
|
|
586
|
+
: new Circle({
|
|
587
|
+
radius: visualInnerRadius,
|
|
588
|
+
fill: "transparent",
|
|
589
|
+
stroke: "red",
|
|
590
|
+
strokeWidth: 2,
|
|
591
|
+
originX: "center",
|
|
592
|
+
originY: "center",
|
|
593
|
+
});
|
|
555
594
|
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
595
|
+
const outerMarker = isSquare
|
|
596
|
+
? new Rect({
|
|
597
|
+
width: visualOuterRadius * 2,
|
|
598
|
+
height: visualOuterRadius * 2,
|
|
599
|
+
fill: "transparent",
|
|
600
|
+
stroke: "#666",
|
|
601
|
+
strokeWidth: 1,
|
|
602
|
+
strokeDashArray: [5, 5],
|
|
603
|
+
originX: "center",
|
|
604
|
+
originY: "center",
|
|
605
|
+
})
|
|
606
|
+
: new Circle({
|
|
607
|
+
radius: visualOuterRadius,
|
|
608
|
+
fill: "transparent",
|
|
609
|
+
stroke: "#666",
|
|
610
|
+
strokeWidth: 1,
|
|
611
|
+
strokeDashArray: [5, 5],
|
|
612
|
+
originX: "center",
|
|
613
|
+
originY: "center",
|
|
614
|
+
});
|
|
565
615
|
|
|
566
|
-
const holeGroup = new Group([
|
|
616
|
+
const holeGroup = new Group([outerMarker, innerMarker], {
|
|
567
617
|
left: pos.x,
|
|
568
618
|
top: pos.y,
|
|
569
619
|
originX: "center",
|
package/src/image.ts
CHANGED
|
@@ -241,13 +241,27 @@ export class ImageTool implements Extension {
|
|
|
241
241
|
let visualHeight = canvasH;
|
|
242
242
|
let dielinePhysicalWidth = 500;
|
|
243
243
|
let dielinePhysicalHeight = 500;
|
|
244
|
+
let bleedOffset = 0;
|
|
244
245
|
|
|
245
246
|
if (this.context) {
|
|
246
247
|
const configService = this.context.services.get<ConfigurationService>("ConfigurationService");
|
|
247
248
|
if (configService) {
|
|
248
249
|
dielinePhysicalWidth = configService.get("dieline.width") || 500;
|
|
249
250
|
dielinePhysicalHeight = configService.get("dieline.height") || 500;
|
|
250
|
-
|
|
251
|
+
bleedOffset = configService.get("dieline.offset") || 0;
|
|
252
|
+
|
|
253
|
+
const paddingValue = configService.get("dieline.padding") || 40;
|
|
254
|
+
let padding = 0;
|
|
255
|
+
if (typeof paddingValue === "number") {
|
|
256
|
+
padding = paddingValue;
|
|
257
|
+
} else if (typeof paddingValue === "string") {
|
|
258
|
+
if (paddingValue.endsWith("%")) {
|
|
259
|
+
const percent = parseFloat(paddingValue) / 100;
|
|
260
|
+
padding = Math.min(canvasW, canvasH) * percent;
|
|
261
|
+
} else {
|
|
262
|
+
padding = parseFloat(paddingValue) || 0;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
251
265
|
|
|
252
266
|
const layout = Coordinate.calculateLayout(
|
|
253
267
|
{ width: canvasW, height: canvasH },
|
|
@@ -269,7 +283,8 @@ export class ImageTool implements Extension {
|
|
|
269
283
|
visualWidth,
|
|
270
284
|
visualHeight,
|
|
271
285
|
dielinePhysicalWidth,
|
|
272
|
-
dielinePhysicalHeight
|
|
286
|
+
dielinePhysicalHeight,
|
|
287
|
+
bleedOffset
|
|
273
288
|
};
|
|
274
289
|
}
|
|
275
290
|
|
|
@@ -378,26 +393,34 @@ export class ImageTool implements Extension {
|
|
|
378
393
|
originX: "center",
|
|
379
394
|
originY: "center",
|
|
380
395
|
data: { id: item.id },
|
|
396
|
+
uniformScaling: true,
|
|
397
|
+
lockScalingFlip: true,
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
image.setControlsVisibility({
|
|
401
|
+
mt: false,
|
|
402
|
+
mb: false,
|
|
403
|
+
ml: false,
|
|
404
|
+
mr: false,
|
|
381
405
|
});
|
|
382
406
|
|
|
383
407
|
// Initial Layout
|
|
384
408
|
let { width, height, left, top } = item;
|
|
385
|
-
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, dielinePhysicalWidth, dielinePhysicalHeight } = layout;
|
|
409
|
+
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, dielinePhysicalWidth, dielinePhysicalHeight, bleedOffset } = layout;
|
|
386
410
|
|
|
387
411
|
// Auto-scale if needed
|
|
388
412
|
if (width === undefined && height === undefined) {
|
|
389
|
-
|
|
390
|
-
const
|
|
413
|
+
// Calculate target dimensions including bleed
|
|
414
|
+
const targetWidth = dielinePhysicalWidth + 2 * bleedOffset;
|
|
415
|
+
const targetHeight = dielinePhysicalHeight + 2 * bleedOffset;
|
|
416
|
+
|
|
417
|
+
// "适应最长边" (Fit to longest side) logic
|
|
418
|
+
const targetMax = Math.max(targetWidth, targetHeight);
|
|
419
|
+
const imageMax = Math.max(image.width || 1, image.height || 1);
|
|
420
|
+
const scale = targetMax / imageMax;
|
|
391
421
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
width = w;
|
|
395
|
-
height = w / imgAspect;
|
|
396
|
-
} else {
|
|
397
|
-
const h = dielinePhysicalHeight;
|
|
398
|
-
height = h;
|
|
399
|
-
width = h * imgAspect;
|
|
400
|
-
}
|
|
422
|
+
width = (image.width || 1) * scale;
|
|
423
|
+
height = (image.height || 1) * scale;
|
|
401
424
|
|
|
402
425
|
// Update item with defaults
|
|
403
426
|
item.width = width;
|