@pooder/kit 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.test-dist/src/CanvasService.js +83 -0
- package/.test-dist/src/ViewportSystem.js +75 -0
- package/.test-dist/src/background.js +203 -0
- package/.test-dist/src/constraints.js +153 -0
- package/.test-dist/src/coordinate.js +74 -0
- package/.test-dist/src/dieline.js +758 -0
- package/.test-dist/src/feature.js +687 -0
- package/.test-dist/src/featureComplete.js +31 -0
- package/.test-dist/src/featureDraft.js +31 -0
- package/.test-dist/src/film.js +167 -0
- package/.test-dist/src/geometry.js +292 -0
- package/.test-dist/src/image.js +421 -0
- package/.test-dist/src/index.js +31 -0
- package/.test-dist/src/mirror.js +104 -0
- package/.test-dist/src/ruler.js +383 -0
- package/.test-dist/src/tracer.js +448 -0
- package/.test-dist/src/units.js +30 -0
- package/.test-dist/src/white-ink.js +310 -0
- package/.test-dist/tests/run.js +60 -0
- package/CHANGELOG.md +6 -0
- package/dist/index.d.mts +50 -5
- package/dist/index.d.ts +50 -5
- package/dist/index.js +544 -297
- package/dist/index.mjs +541 -296
- package/package.json +3 -2
- package/src/CanvasService.ts +7 -0
- package/src/ViewportSystem.ts +92 -0
- package/src/constraints.ts +53 -4
- package/src/dieline.ts +169 -85
- package/src/feature.ts +217 -150
- package/src/featureComplete.ts +45 -0
- package/src/index.ts +1 -0
- package/src/ruler.ts +26 -18
- package/src/units.ts +27 -0
- package/tests/run.ts +81 -0
- package/tsconfig.test.json +15 -0
package/dist/index.mjs
CHANGED
|
@@ -677,6 +677,29 @@ var Coordinate = class {
|
|
|
677
677
|
}
|
|
678
678
|
};
|
|
679
679
|
|
|
680
|
+
// src/units.ts
|
|
681
|
+
function parseLengthToMm(input, defaultUnit) {
|
|
682
|
+
var _a, _b;
|
|
683
|
+
if (typeof input === "number") {
|
|
684
|
+
if (!Number.isFinite(input)) return 0;
|
|
685
|
+
return Coordinate.convertUnit(input, defaultUnit, "mm");
|
|
686
|
+
}
|
|
687
|
+
const raw = input.trim();
|
|
688
|
+
if (!raw) return 0;
|
|
689
|
+
const match = raw.match(/^([+-]?\d+(?:\.\d+)?)\s*(px|mm|cm|in)?$/i);
|
|
690
|
+
if (!match) return 0;
|
|
691
|
+
const value = Number(match[1]);
|
|
692
|
+
if (!Number.isFinite(value)) return 0;
|
|
693
|
+
const unit = (_b = (_a = match[2]) == null ? void 0 : _a.toLowerCase()) != null ? _b : defaultUnit;
|
|
694
|
+
return Coordinate.convertUnit(value, unit, "mm");
|
|
695
|
+
}
|
|
696
|
+
function formatMm(valueMm, displayUnit, fractionDigits = 2) {
|
|
697
|
+
if (!Number.isFinite(valueMm)) return "0";
|
|
698
|
+
const value = Coordinate.convertUnit(valueMm, "mm", displayUnit);
|
|
699
|
+
const rounded = Number(value.toFixed(fractionDigits));
|
|
700
|
+
return rounded.toString();
|
|
701
|
+
}
|
|
702
|
+
|
|
680
703
|
// src/geometry.ts
|
|
681
704
|
import paper2 from "paper";
|
|
682
705
|
function resolveFeaturePosition(feature, geometry) {
|
|
@@ -900,105 +923,6 @@ function getPathBounds(pathData) {
|
|
|
900
923
|
};
|
|
901
924
|
}
|
|
902
925
|
|
|
903
|
-
// src/constraints.ts
|
|
904
|
-
var ConstraintRegistry = class {
|
|
905
|
-
static register(type, handler) {
|
|
906
|
-
this.handlers.set(type, handler);
|
|
907
|
-
}
|
|
908
|
-
static apply(x, y, feature, context) {
|
|
909
|
-
if (!feature.constraints || !feature.constraints.type) {
|
|
910
|
-
return { x, y };
|
|
911
|
-
}
|
|
912
|
-
const handler = this.handlers.get(feature.constraints.type);
|
|
913
|
-
if (handler) {
|
|
914
|
-
return handler(x, y, feature, context);
|
|
915
|
-
}
|
|
916
|
-
return { x, y };
|
|
917
|
-
}
|
|
918
|
-
};
|
|
919
|
-
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
920
|
-
var edgeConstraint = (x, y, feature, context) => {
|
|
921
|
-
var _a;
|
|
922
|
-
const { dielineWidth, dielineHeight } = context;
|
|
923
|
-
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
924
|
-
const allowedEdges = params.allowedEdges || [
|
|
925
|
-
"top",
|
|
926
|
-
"bottom",
|
|
927
|
-
"left",
|
|
928
|
-
"right"
|
|
929
|
-
];
|
|
930
|
-
const confine = params.confine || false;
|
|
931
|
-
const offset = params.offset || 0;
|
|
932
|
-
const distances = [];
|
|
933
|
-
if (allowedEdges.includes("top"))
|
|
934
|
-
distances.push({ edge: "top", dist: y * dielineHeight });
|
|
935
|
-
if (allowedEdges.includes("bottom"))
|
|
936
|
-
distances.push({ edge: "bottom", dist: (1 - y) * dielineHeight });
|
|
937
|
-
if (allowedEdges.includes("left"))
|
|
938
|
-
distances.push({ edge: "left", dist: x * dielineWidth });
|
|
939
|
-
if (allowedEdges.includes("right"))
|
|
940
|
-
distances.push({ edge: "right", dist: (1 - x) * dielineWidth });
|
|
941
|
-
if (distances.length === 0) return { x, y };
|
|
942
|
-
distances.sort((a, b) => a.dist - b.dist);
|
|
943
|
-
const nearest = distances[0].edge;
|
|
944
|
-
let newX = x;
|
|
945
|
-
let newY = y;
|
|
946
|
-
const fw = feature.width || 0;
|
|
947
|
-
const fh = feature.height || 0;
|
|
948
|
-
switch (nearest) {
|
|
949
|
-
case "top":
|
|
950
|
-
newY = 0 + offset / dielineHeight;
|
|
951
|
-
if (confine) {
|
|
952
|
-
const minX = fw / 2 / dielineWidth;
|
|
953
|
-
const maxX = 1 - minX;
|
|
954
|
-
newX = Math.max(minX, Math.min(newX, maxX));
|
|
955
|
-
}
|
|
956
|
-
break;
|
|
957
|
-
case "bottom":
|
|
958
|
-
newY = 1 - offset / dielineHeight;
|
|
959
|
-
if (confine) {
|
|
960
|
-
const minX = fw / 2 / dielineWidth;
|
|
961
|
-
const maxX = 1 - minX;
|
|
962
|
-
newX = Math.max(minX, Math.min(newX, maxX));
|
|
963
|
-
}
|
|
964
|
-
break;
|
|
965
|
-
case "left":
|
|
966
|
-
newX = 0 + offset / dielineWidth;
|
|
967
|
-
if (confine) {
|
|
968
|
-
const minY = fh / 2 / dielineHeight;
|
|
969
|
-
const maxY = 1 - minY;
|
|
970
|
-
newY = Math.max(minY, Math.min(newY, maxY));
|
|
971
|
-
}
|
|
972
|
-
break;
|
|
973
|
-
case "right":
|
|
974
|
-
newX = 1 - offset / dielineWidth;
|
|
975
|
-
if (confine) {
|
|
976
|
-
const minY = fh / 2 / dielineHeight;
|
|
977
|
-
const maxY = 1 - minY;
|
|
978
|
-
newY = Math.max(minY, Math.min(newY, maxY));
|
|
979
|
-
}
|
|
980
|
-
break;
|
|
981
|
-
}
|
|
982
|
-
return { x: newX, y: newY };
|
|
983
|
-
};
|
|
984
|
-
var internalConstraint = (x, y, feature, context) => {
|
|
985
|
-
var _a;
|
|
986
|
-
const { dielineWidth, dielineHeight } = context;
|
|
987
|
-
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
988
|
-
const margin = params.margin || 0;
|
|
989
|
-
const fw = feature.width || 0;
|
|
990
|
-
const fh = feature.height || 0;
|
|
991
|
-
const minX = (margin + fw / 2) / dielineWidth;
|
|
992
|
-
const maxX = 1 - (margin + fw / 2) / dielineWidth;
|
|
993
|
-
const minY = (margin + fh / 2) / dielineHeight;
|
|
994
|
-
const maxY = 1 - (margin + fh / 2) / dielineHeight;
|
|
995
|
-
const clampedX = minX > maxX ? 0.5 : Math.max(minX, Math.min(x, maxX));
|
|
996
|
-
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
997
|
-
return { x: clampedX, y: clampedY };
|
|
998
|
-
};
|
|
999
|
-
ConstraintRegistry.register("edge", edgeConstraint);
|
|
1000
|
-
ConstraintRegistry.register("internal", internalConstraint);
|
|
1001
|
-
|
|
1002
926
|
// src/dieline.ts
|
|
1003
927
|
var DielineTool = class {
|
|
1004
928
|
constructor(options) {
|
|
@@ -1007,7 +931,7 @@ var DielineTool = class {
|
|
|
1007
931
|
name: "DielineTool"
|
|
1008
932
|
};
|
|
1009
933
|
this.state = {
|
|
1010
|
-
|
|
934
|
+
displayUnit: "mm",
|
|
1011
935
|
shape: "rect",
|
|
1012
936
|
width: 500,
|
|
1013
937
|
height: 500,
|
|
@@ -1053,50 +977,88 @@ var DielineTool = class {
|
|
|
1053
977
|
const configService = context.services.get("ConfigurationService");
|
|
1054
978
|
if (configService) {
|
|
1055
979
|
const s = this.state;
|
|
1056
|
-
s.
|
|
980
|
+
s.displayUnit = configService.get("dieline.displayUnit", s.displayUnit);
|
|
1057
981
|
s.shape = configService.get("dieline.shape", s.shape);
|
|
1058
|
-
s.width =
|
|
1059
|
-
|
|
1060
|
-
|
|
982
|
+
s.width = parseLengthToMm(
|
|
983
|
+
configService.get("dieline.width", s.width),
|
|
984
|
+
"mm"
|
|
985
|
+
);
|
|
986
|
+
s.height = parseLengthToMm(
|
|
987
|
+
configService.get("dieline.height", s.height),
|
|
988
|
+
"mm"
|
|
989
|
+
);
|
|
990
|
+
s.radius = parseLengthToMm(
|
|
991
|
+
configService.get("dieline.radius", s.radius),
|
|
992
|
+
"mm"
|
|
993
|
+
);
|
|
1061
994
|
s.padding = configService.get("dieline.padding", s.padding);
|
|
1062
|
-
s.offset =
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
995
|
+
s.offset = parseLengthToMm(
|
|
996
|
+
configService.get("dieline.offset", s.offset),
|
|
997
|
+
"mm"
|
|
998
|
+
);
|
|
999
|
+
s.mainLine.width = configService.get(
|
|
1000
|
+
"dieline.strokeWidth",
|
|
1001
|
+
s.mainLine.width
|
|
1002
|
+
);
|
|
1003
|
+
s.mainLine.color = configService.get(
|
|
1004
|
+
"dieline.strokeColor",
|
|
1005
|
+
s.mainLine.color
|
|
1006
|
+
);
|
|
1007
|
+
s.mainLine.dashLength = configService.get(
|
|
1008
|
+
"dieline.dashLength",
|
|
1009
|
+
s.mainLine.dashLength
|
|
1010
|
+
);
|
|
1066
1011
|
s.mainLine.style = configService.get("dieline.style", s.mainLine.style);
|
|
1067
|
-
s.offsetLine.width = configService.get(
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1012
|
+
s.offsetLine.width = configService.get(
|
|
1013
|
+
"dieline.offsetStrokeWidth",
|
|
1014
|
+
s.offsetLine.width
|
|
1015
|
+
);
|
|
1016
|
+
s.offsetLine.color = configService.get(
|
|
1017
|
+
"dieline.offsetStrokeColor",
|
|
1018
|
+
s.offsetLine.color
|
|
1019
|
+
);
|
|
1020
|
+
s.offsetLine.dashLength = configService.get(
|
|
1021
|
+
"dieline.offsetDashLength",
|
|
1022
|
+
s.offsetLine.dashLength
|
|
1023
|
+
);
|
|
1024
|
+
s.offsetLine.style = configService.get(
|
|
1025
|
+
"dieline.offsetStyle",
|
|
1026
|
+
s.offsetLine.style
|
|
1027
|
+
);
|
|
1071
1028
|
s.insideColor = configService.get("dieline.insideColor", s.insideColor);
|
|
1072
|
-
s.outsideColor = configService.get(
|
|
1073
|
-
|
|
1029
|
+
s.outsideColor = configService.get(
|
|
1030
|
+
"dieline.outsideColor",
|
|
1031
|
+
s.outsideColor
|
|
1032
|
+
);
|
|
1033
|
+
s.showBleedLines = configService.get(
|
|
1034
|
+
"dieline.showBleedLines",
|
|
1035
|
+
s.showBleedLines
|
|
1036
|
+
);
|
|
1074
1037
|
s.features = configService.get("dieline.features", s.features);
|
|
1075
1038
|
s.pathData = configService.get("dieline.pathData", s.pathData);
|
|
1076
1039
|
configService.onAnyChange((e) => {
|
|
1077
1040
|
if (e.key.startsWith("dieline.")) {
|
|
1078
|
-
console.log(`[DielineTool] Config change detected: ${e.key} -> ${e.value}`);
|
|
1079
1041
|
switch (e.key) {
|
|
1080
|
-
case "dieline.
|
|
1081
|
-
s.
|
|
1042
|
+
case "dieline.displayUnit":
|
|
1043
|
+
s.displayUnit = e.value;
|
|
1082
1044
|
break;
|
|
1083
1045
|
case "dieline.shape":
|
|
1084
1046
|
s.shape = e.value;
|
|
1085
1047
|
break;
|
|
1086
1048
|
case "dieline.width":
|
|
1087
|
-
s.width = e.value;
|
|
1049
|
+
s.width = parseLengthToMm(e.value, "mm");
|
|
1088
1050
|
break;
|
|
1089
1051
|
case "dieline.height":
|
|
1090
|
-
s.height = e.value;
|
|
1052
|
+
s.height = parseLengthToMm(e.value, "mm");
|
|
1091
1053
|
break;
|
|
1092
1054
|
case "dieline.radius":
|
|
1093
|
-
s.radius = e.value;
|
|
1055
|
+
s.radius = parseLengthToMm(e.value, "mm");
|
|
1094
1056
|
break;
|
|
1095
1057
|
case "dieline.padding":
|
|
1096
1058
|
s.padding = e.value;
|
|
1097
1059
|
break;
|
|
1098
1060
|
case "dieline.offset":
|
|
1099
|
-
s.offset = e.value;
|
|
1061
|
+
s.offset = parseLengthToMm(e.value, "mm");
|
|
1100
1062
|
break;
|
|
1101
1063
|
case "dieline.strokeWidth":
|
|
1102
1064
|
s.mainLine.width = e.value;
|
|
@@ -1155,11 +1117,11 @@ var DielineTool = class {
|
|
|
1155
1117
|
return {
|
|
1156
1118
|
[ContributionPointIds2.CONFIGURATIONS]: [
|
|
1157
1119
|
{
|
|
1158
|
-
id: "dieline.
|
|
1120
|
+
id: "dieline.displayUnit",
|
|
1159
1121
|
type: "select",
|
|
1160
|
-
label: "Unit",
|
|
1161
|
-
options: ["
|
|
1162
|
-
default: s.
|
|
1122
|
+
label: "Display Unit",
|
|
1123
|
+
options: ["mm", "cm", "in"],
|
|
1124
|
+
default: s.displayUnit
|
|
1163
1125
|
},
|
|
1164
1126
|
{
|
|
1165
1127
|
id: "dieline.shape",
|
|
@@ -1171,7 +1133,7 @@ var DielineTool = class {
|
|
|
1171
1133
|
{
|
|
1172
1134
|
id: "dieline.width",
|
|
1173
1135
|
type: "number",
|
|
1174
|
-
label: "Width",
|
|
1136
|
+
label: "Width (mm)",
|
|
1175
1137
|
min: 10,
|
|
1176
1138
|
max: 2e3,
|
|
1177
1139
|
default: s.width
|
|
@@ -1179,7 +1141,7 @@ var DielineTool = class {
|
|
|
1179
1141
|
{
|
|
1180
1142
|
id: "dieline.height",
|
|
1181
1143
|
type: "number",
|
|
1182
|
-
label: "Height",
|
|
1144
|
+
label: "Height (mm)",
|
|
1183
1145
|
min: 10,
|
|
1184
1146
|
max: 2e3,
|
|
1185
1147
|
default: s.height
|
|
@@ -1187,7 +1149,7 @@ var DielineTool = class {
|
|
|
1187
1149
|
{
|
|
1188
1150
|
id: "dieline.radius",
|
|
1189
1151
|
type: "number",
|
|
1190
|
-
label: "Corner Radius",
|
|
1152
|
+
label: "Corner Radius (mm)",
|
|
1191
1153
|
min: 0,
|
|
1192
1154
|
max: 500,
|
|
1193
1155
|
default: s.radius
|
|
@@ -1202,7 +1164,7 @@ var DielineTool = class {
|
|
|
1202
1164
|
{
|
|
1203
1165
|
id: "dieline.offset",
|
|
1204
1166
|
type: "number",
|
|
1205
|
-
label: "Bleed Offset",
|
|
1167
|
+
label: "Bleed Offset (mm)",
|
|
1206
1168
|
min: -100,
|
|
1207
1169
|
max: 100,
|
|
1208
1170
|
default: s.offset
|
|
@@ -1303,18 +1265,12 @@ var DielineTool = class {
|
|
|
1303
1265
|
);
|
|
1304
1266
|
if (!configService) return;
|
|
1305
1267
|
const features = configService.get("dieline.features") || [];
|
|
1306
|
-
const dielineWidth = configService.get("dieline.width") || 500;
|
|
1307
|
-
const dielineHeight = configService.get("dieline.height") || 500;
|
|
1308
1268
|
let changed = false;
|
|
1309
1269
|
const newFeatures = features.map((f) => {
|
|
1310
1270
|
if (f.groupId === groupId) {
|
|
1311
|
-
|
|
1312
|
-
dielineWidth,
|
|
1313
|
-
dielineHeight
|
|
1314
|
-
});
|
|
1315
|
-
if (f.x !== constrained.x || f.y !== constrained.y) {
|
|
1271
|
+
if (f.x !== x || f.y !== y) {
|
|
1316
1272
|
changed = true;
|
|
1317
|
-
return { ...f, x
|
|
1273
|
+
return { ...f, x, y };
|
|
1318
1274
|
}
|
|
1319
1275
|
}
|
|
1320
1276
|
return f;
|
|
@@ -1429,7 +1385,7 @@ var DielineTool = class {
|
|
|
1429
1385
|
const layer = this.getLayer();
|
|
1430
1386
|
if (!layer) return;
|
|
1431
1387
|
const {
|
|
1432
|
-
|
|
1388
|
+
displayUnit,
|
|
1433
1389
|
shape,
|
|
1434
1390
|
radius,
|
|
1435
1391
|
offset,
|
|
@@ -1440,15 +1396,13 @@ var DielineTool = class {
|
|
|
1440
1396
|
showBleedLines,
|
|
1441
1397
|
features
|
|
1442
1398
|
} = this.state;
|
|
1443
|
-
|
|
1399
|
+
const { width, height } = this.state;
|
|
1444
1400
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1445
1401
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1446
1402
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
paddingPx
|
|
1451
|
-
);
|
|
1403
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1404
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1405
|
+
const layout = this.canvasService.viewport.layout;
|
|
1452
1406
|
const scale = layout.scale;
|
|
1453
1407
|
const cx = layout.offsetX + layout.width / 2;
|
|
1454
1408
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1635,15 +1589,22 @@ var DielineTool = class {
|
|
|
1635
1589
|
}
|
|
1636
1590
|
getGeometry() {
|
|
1637
1591
|
if (!this.canvasService) return null;
|
|
1638
|
-
const {
|
|
1592
|
+
const {
|
|
1593
|
+
displayUnit,
|
|
1594
|
+
shape,
|
|
1595
|
+
width,
|
|
1596
|
+
height,
|
|
1597
|
+
radius,
|
|
1598
|
+
offset,
|
|
1599
|
+
mainLine,
|
|
1600
|
+
pathData
|
|
1601
|
+
} = this.state;
|
|
1639
1602
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1640
1603
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1641
1604
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
paddingPx
|
|
1646
|
-
);
|
|
1605
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1606
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1607
|
+
const layout = this.canvasService.viewport.layout;
|
|
1647
1608
|
const scale = layout.scale;
|
|
1648
1609
|
const cx = layout.offsetX + layout.width / 2;
|
|
1649
1610
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1651,14 +1612,14 @@ var DielineTool = class {
|
|
|
1651
1612
|
const visualHeight = layout.height;
|
|
1652
1613
|
return {
|
|
1653
1614
|
shape,
|
|
1654
|
-
unit,
|
|
1615
|
+
unit: "mm",
|
|
1616
|
+
displayUnit,
|
|
1655
1617
|
x: cx,
|
|
1656
1618
|
y: cy,
|
|
1657
1619
|
width: visualWidth,
|
|
1658
1620
|
height: visualHeight,
|
|
1659
1621
|
radius: radius * scale,
|
|
1660
1622
|
offset: offset * scale,
|
|
1661
|
-
// Pass scale to help other tools (like FeatureTool) convert units
|
|
1662
1623
|
scale,
|
|
1663
1624
|
strokeWidth: mainLine.width,
|
|
1664
1625
|
pathData
|
|
@@ -1668,15 +1629,13 @@ var DielineTool = class {
|
|
|
1668
1629
|
if (!this.canvasService) return null;
|
|
1669
1630
|
const userLayer = this.canvasService.getLayer("user");
|
|
1670
1631
|
if (!userLayer) return null;
|
|
1671
|
-
const { shape, width, height, radius, features,
|
|
1632
|
+
const { shape, width, height, radius, features, pathData } = this.state;
|
|
1672
1633
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1673
1634
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1674
1635
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
paddingPx
|
|
1679
|
-
);
|
|
1636
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1637
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1638
|
+
const layout = this.canvasService.viewport.layout;
|
|
1680
1639
|
const scale = layout.scale;
|
|
1681
1640
|
const cx = layout.offsetX + layout.width / 2;
|
|
1682
1641
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1895,13 +1854,158 @@ import {
|
|
|
1895
1854
|
ContributionPointIds as ContributionPointIds4
|
|
1896
1855
|
} from "@pooder/core";
|
|
1897
1856
|
import { Circle, Group, Point, Rect as Rect2 } from "fabric";
|
|
1857
|
+
|
|
1858
|
+
// src/constraints.ts
|
|
1859
|
+
var ConstraintRegistry = class {
|
|
1860
|
+
static register(type, handler) {
|
|
1861
|
+
this.handlers.set(type, handler);
|
|
1862
|
+
}
|
|
1863
|
+
static apply(x, y, feature, context) {
|
|
1864
|
+
if (!feature.constraints || !feature.constraints.type) {
|
|
1865
|
+
return { x, y };
|
|
1866
|
+
}
|
|
1867
|
+
const handler = this.handlers.get(feature.constraints.type);
|
|
1868
|
+
if (handler) {
|
|
1869
|
+
return handler(x, y, feature, context);
|
|
1870
|
+
}
|
|
1871
|
+
return { x, y };
|
|
1872
|
+
}
|
|
1873
|
+
};
|
|
1874
|
+
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
1875
|
+
var edgeConstraint = (x, y, feature, context) => {
|
|
1876
|
+
var _a;
|
|
1877
|
+
const { dielineWidth, dielineHeight } = context;
|
|
1878
|
+
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1879
|
+
const allowedEdges = params.allowedEdges || [
|
|
1880
|
+
"top",
|
|
1881
|
+
"bottom",
|
|
1882
|
+
"left",
|
|
1883
|
+
"right"
|
|
1884
|
+
];
|
|
1885
|
+
const confine = params.confine || false;
|
|
1886
|
+
const offset = params.offset || 0;
|
|
1887
|
+
const distances = [];
|
|
1888
|
+
if (allowedEdges.includes("top"))
|
|
1889
|
+
distances.push({ edge: "top", dist: y * dielineHeight });
|
|
1890
|
+
if (allowedEdges.includes("bottom"))
|
|
1891
|
+
distances.push({ edge: "bottom", dist: (1 - y) * dielineHeight });
|
|
1892
|
+
if (allowedEdges.includes("left"))
|
|
1893
|
+
distances.push({ edge: "left", dist: x * dielineWidth });
|
|
1894
|
+
if (allowedEdges.includes("right"))
|
|
1895
|
+
distances.push({ edge: "right", dist: (1 - x) * dielineWidth });
|
|
1896
|
+
if (distances.length === 0) return { x, y };
|
|
1897
|
+
distances.sort((a, b) => a.dist - b.dist);
|
|
1898
|
+
const nearest = distances[0].edge;
|
|
1899
|
+
let newX = x;
|
|
1900
|
+
let newY = y;
|
|
1901
|
+
const fw = feature.width || 0;
|
|
1902
|
+
const fh = feature.height || 0;
|
|
1903
|
+
switch (nearest) {
|
|
1904
|
+
case "top":
|
|
1905
|
+
newY = 0 + offset / dielineHeight;
|
|
1906
|
+
if (confine) {
|
|
1907
|
+
const minX = fw / 2 / dielineWidth;
|
|
1908
|
+
const maxX = 1 - minX;
|
|
1909
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
1910
|
+
}
|
|
1911
|
+
break;
|
|
1912
|
+
case "bottom":
|
|
1913
|
+
newY = 1 - offset / dielineHeight;
|
|
1914
|
+
if (confine) {
|
|
1915
|
+
const minX = fw / 2 / dielineWidth;
|
|
1916
|
+
const maxX = 1 - minX;
|
|
1917
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
1918
|
+
}
|
|
1919
|
+
break;
|
|
1920
|
+
case "left":
|
|
1921
|
+
newX = 0 + offset / dielineWidth;
|
|
1922
|
+
if (confine) {
|
|
1923
|
+
const minY = fh / 2 / dielineHeight;
|
|
1924
|
+
const maxY = 1 - minY;
|
|
1925
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
1926
|
+
}
|
|
1927
|
+
break;
|
|
1928
|
+
case "right":
|
|
1929
|
+
newX = 1 - offset / dielineWidth;
|
|
1930
|
+
if (confine) {
|
|
1931
|
+
const minY = fh / 2 / dielineHeight;
|
|
1932
|
+
const maxY = 1 - minY;
|
|
1933
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
1934
|
+
}
|
|
1935
|
+
break;
|
|
1936
|
+
}
|
|
1937
|
+
return { x: newX, y: newY };
|
|
1938
|
+
};
|
|
1939
|
+
var internalConstraint = (x, y, feature, context) => {
|
|
1940
|
+
var _a;
|
|
1941
|
+
const { dielineWidth, dielineHeight } = context;
|
|
1942
|
+
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1943
|
+
const margin = params.margin || 0;
|
|
1944
|
+
const fw = feature.width || 0;
|
|
1945
|
+
const fh = feature.height || 0;
|
|
1946
|
+
const minX = (margin + fw / 2) / dielineWidth;
|
|
1947
|
+
const maxX = 1 - (margin + fw / 2) / dielineWidth;
|
|
1948
|
+
const minY = (margin + fh / 2) / dielineHeight;
|
|
1949
|
+
const maxY = 1 - (margin + fh / 2) / dielineHeight;
|
|
1950
|
+
const clampedX = minX > maxX ? 0.5 : Math.max(minX, Math.min(x, maxX));
|
|
1951
|
+
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
1952
|
+
return { x: clampedX, y: clampedY };
|
|
1953
|
+
};
|
|
1954
|
+
var tangentBottomConstraint = (x, y, feature, context) => {
|
|
1955
|
+
var _a;
|
|
1956
|
+
const { dielineWidth, dielineHeight } = context;
|
|
1957
|
+
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1958
|
+
const gap = params.gap || 0;
|
|
1959
|
+
const confineX = params.confineX !== false;
|
|
1960
|
+
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
1961
|
+
const newY = 1 + (extentY + gap) / dielineHeight;
|
|
1962
|
+
let newX = x;
|
|
1963
|
+
if (confineX) {
|
|
1964
|
+
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
1965
|
+
const minX = extentX / dielineWidth;
|
|
1966
|
+
const maxX = 1 - extentX / dielineWidth;
|
|
1967
|
+
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
1968
|
+
}
|
|
1969
|
+
return { x: newX, y: newY };
|
|
1970
|
+
};
|
|
1971
|
+
ConstraintRegistry.register("edge", edgeConstraint);
|
|
1972
|
+
ConstraintRegistry.register("internal", internalConstraint);
|
|
1973
|
+
ConstraintRegistry.register("tangent-bottom", tangentBottomConstraint);
|
|
1974
|
+
|
|
1975
|
+
// src/featureComplete.ts
|
|
1976
|
+
function validateFeaturesStrict(features, context) {
|
|
1977
|
+
var _a;
|
|
1978
|
+
const eps = 1e-6;
|
|
1979
|
+
const issues = [];
|
|
1980
|
+
for (const f of features) {
|
|
1981
|
+
if (!((_a = f.constraints) == null ? void 0 : _a.type)) continue;
|
|
1982
|
+
const constrained = ConstraintRegistry.apply(f.x, f.y, f, context);
|
|
1983
|
+
if (Math.abs(constrained.x - f.x) > eps || Math.abs(constrained.y - f.y) > eps) {
|
|
1984
|
+
issues.push({
|
|
1985
|
+
featureId: f.id,
|
|
1986
|
+
groupId: f.groupId,
|
|
1987
|
+
reason: "Position violates constraint strategy"
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
return { ok: issues.length === 0, issues: issues.length ? issues : void 0 };
|
|
1992
|
+
}
|
|
1993
|
+
function completeFeaturesStrict(features, context, update) {
|
|
1994
|
+
const validation = validateFeaturesStrict(features, context);
|
|
1995
|
+
if (!validation.ok) return validation;
|
|
1996
|
+
const next = JSON.parse(JSON.stringify(features || []));
|
|
1997
|
+
update(next);
|
|
1998
|
+
return { ok: true };
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
// src/feature.ts
|
|
1898
2002
|
var FeatureTool = class {
|
|
1899
2003
|
constructor(options) {
|
|
1900
2004
|
this.id = "pooder.kit.feature";
|
|
1901
2005
|
this.metadata = {
|
|
1902
2006
|
name: "FeatureTool"
|
|
1903
2007
|
};
|
|
1904
|
-
this.
|
|
2008
|
+
this.workingFeatures = [];
|
|
1905
2009
|
this.isUpdatingConfig = false;
|
|
1906
2010
|
this.isToolActive = false;
|
|
1907
2011
|
this.handleMoving = null;
|
|
@@ -1927,12 +2031,15 @@ var FeatureTool = class {
|
|
|
1927
2031
|
"ConfigurationService"
|
|
1928
2032
|
);
|
|
1929
2033
|
if (configService) {
|
|
1930
|
-
|
|
2034
|
+
const features = configService.get("dieline.features", []) || [];
|
|
2035
|
+
this.workingFeatures = this.cloneFeatures(features);
|
|
1931
2036
|
configService.onAnyChange((e) => {
|
|
1932
2037
|
if (this.isUpdatingConfig) return;
|
|
1933
2038
|
if (e.key === "dieline.features") {
|
|
1934
|
-
|
|
2039
|
+
const next = e.value || [];
|
|
2040
|
+
this.workingFeatures = this.cloneFeatures(next);
|
|
1935
2041
|
this.redraw();
|
|
2042
|
+
this.emitWorkingChange();
|
|
1936
2043
|
}
|
|
1937
2044
|
});
|
|
1938
2045
|
}
|
|
@@ -1990,27 +2097,151 @@ var FeatureTool = class {
|
|
|
1990
2097
|
command: "clearFeatures",
|
|
1991
2098
|
title: "Clear Features",
|
|
1992
2099
|
handler: () => {
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
);
|
|
1997
|
-
if (configService) {
|
|
1998
|
-
configService.update("dieline.features", []);
|
|
1999
|
-
}
|
|
2100
|
+
this.setWorkingFeatures([]);
|
|
2101
|
+
this.redraw();
|
|
2102
|
+
this.emitWorkingChange();
|
|
2000
2103
|
return true;
|
|
2001
2104
|
}
|
|
2105
|
+
},
|
|
2106
|
+
{
|
|
2107
|
+
command: "getWorkingFeatures",
|
|
2108
|
+
title: "Get Working Features",
|
|
2109
|
+
handler: () => {
|
|
2110
|
+
return this.cloneFeatures(this.workingFeatures);
|
|
2111
|
+
}
|
|
2112
|
+
},
|
|
2113
|
+
{
|
|
2114
|
+
command: "setWorkingFeatures",
|
|
2115
|
+
title: "Set Working Features",
|
|
2116
|
+
handler: async (features) => {
|
|
2117
|
+
await this.refreshGeometry();
|
|
2118
|
+
this.setWorkingFeatures(this.cloneFeatures(features || []));
|
|
2119
|
+
this.redraw();
|
|
2120
|
+
this.emitWorkingChange();
|
|
2121
|
+
return { ok: true };
|
|
2122
|
+
}
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
command: "updateWorkingGroupPosition",
|
|
2126
|
+
title: "Update Working Group Position",
|
|
2127
|
+
handler: (groupId, x, y) => {
|
|
2128
|
+
return this.updateWorkingGroupPosition(groupId, x, y);
|
|
2129
|
+
}
|
|
2130
|
+
},
|
|
2131
|
+
{
|
|
2132
|
+
command: "completeFeatures",
|
|
2133
|
+
title: "Complete Features",
|
|
2134
|
+
handler: () => {
|
|
2135
|
+
return this.completeFeatures();
|
|
2136
|
+
}
|
|
2002
2137
|
}
|
|
2003
2138
|
]
|
|
2004
2139
|
};
|
|
2005
2140
|
}
|
|
2006
|
-
|
|
2141
|
+
cloneFeatures(features) {
|
|
2142
|
+
return JSON.parse(JSON.stringify(features || []));
|
|
2143
|
+
}
|
|
2144
|
+
emitWorkingChange() {
|
|
2007
2145
|
var _a;
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2146
|
+
(_a = this.context) == null ? void 0 : _a.eventBus.emit("feature:working:change", {
|
|
2147
|
+
features: this.cloneFeatures(this.workingFeatures)
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
async refreshGeometry() {
|
|
2151
|
+
if (!this.context) return;
|
|
2152
|
+
const commandService = this.context.services.get("CommandService");
|
|
2153
|
+
if (!commandService) return;
|
|
2154
|
+
try {
|
|
2155
|
+
const g = await Promise.resolve(commandService.executeCommand("getGeometry"));
|
|
2156
|
+
if (g) this.currentGeometry = g;
|
|
2157
|
+
} catch (e) {
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
setWorkingFeatures(next) {
|
|
2161
|
+
this.workingFeatures = next;
|
|
2162
|
+
}
|
|
2163
|
+
updateWorkingGroupPosition(groupId, x, y) {
|
|
2164
|
+
var _a, _b, _c;
|
|
2165
|
+
if (!groupId) return { ok: false };
|
|
2166
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
2167
|
+
if (!configService) return { ok: false };
|
|
2168
|
+
const dielineWidth = parseLengthToMm(
|
|
2169
|
+
(_b = configService.get("dieline.width")) != null ? _b : 500,
|
|
2170
|
+
"mm"
|
|
2171
|
+
);
|
|
2172
|
+
const dielineHeight = parseLengthToMm(
|
|
2173
|
+
(_c = configService.get("dieline.height")) != null ? _c : 500,
|
|
2174
|
+
"mm"
|
|
2175
|
+
);
|
|
2176
|
+
let changed = false;
|
|
2177
|
+
const next = this.workingFeatures.map((f) => {
|
|
2178
|
+
if (f.groupId !== groupId) return f;
|
|
2179
|
+
let nx = x;
|
|
2180
|
+
let ny = y;
|
|
2181
|
+
if (f.constraints && dielineWidth > 0 && dielineHeight > 0) {
|
|
2182
|
+
const constrained = ConstraintRegistry.apply(nx, ny, f, {
|
|
2183
|
+
dielineWidth,
|
|
2184
|
+
dielineHeight
|
|
2185
|
+
});
|
|
2186
|
+
nx = constrained.x;
|
|
2187
|
+
ny = constrained.y;
|
|
2188
|
+
}
|
|
2189
|
+
if (f.x !== nx || f.y !== ny) {
|
|
2190
|
+
changed = true;
|
|
2191
|
+
return { ...f, x: nx, y: ny };
|
|
2192
|
+
}
|
|
2193
|
+
return f;
|
|
2194
|
+
});
|
|
2195
|
+
if (!changed) return { ok: true };
|
|
2196
|
+
this.setWorkingFeatures(next);
|
|
2197
|
+
this.redraw();
|
|
2198
|
+
this.enforceConstraints();
|
|
2199
|
+
this.emitWorkingChange();
|
|
2200
|
+
return { ok: true };
|
|
2201
|
+
}
|
|
2202
|
+
completeFeatures() {
|
|
2203
|
+
var _a, _b, _c;
|
|
2204
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
2205
|
+
if (!configService) {
|
|
2206
|
+
return {
|
|
2207
|
+
ok: false,
|
|
2208
|
+
issues: [
|
|
2209
|
+
{ featureId: "unknown", reason: "ConfigurationService not found" }
|
|
2210
|
+
]
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
const dielineWidth = parseLengthToMm(
|
|
2214
|
+
(_b = configService.get("dieline.width")) != null ? _b : 500,
|
|
2215
|
+
"mm"
|
|
2216
|
+
);
|
|
2217
|
+
const dielineHeight = parseLengthToMm(
|
|
2218
|
+
(_c = configService.get("dieline.height")) != null ? _c : 500,
|
|
2219
|
+
"mm"
|
|
2220
|
+
);
|
|
2221
|
+
const result = completeFeaturesStrict(
|
|
2222
|
+
this.workingFeatures,
|
|
2223
|
+
{ dielineWidth, dielineHeight },
|
|
2224
|
+
(next) => {
|
|
2225
|
+
this.isUpdatingConfig = true;
|
|
2226
|
+
try {
|
|
2227
|
+
configService.update("dieline.features", next);
|
|
2228
|
+
} finally {
|
|
2229
|
+
this.isUpdatingConfig = false;
|
|
2230
|
+
}
|
|
2231
|
+
this.workingFeatures = this.cloneFeatures(next);
|
|
2232
|
+
this.emitWorkingChange();
|
|
2233
|
+
}
|
|
2011
2234
|
);
|
|
2012
|
-
|
|
2013
|
-
|
|
2235
|
+
if (!result.ok) {
|
|
2236
|
+
return {
|
|
2237
|
+
ok: false,
|
|
2238
|
+
issues: result.issues
|
|
2239
|
+
};
|
|
2240
|
+
}
|
|
2241
|
+
return { ok: true };
|
|
2242
|
+
}
|
|
2243
|
+
addFeature(type) {
|
|
2244
|
+
if (!this.canvasService) return false;
|
|
2014
2245
|
const newFeature = {
|
|
2015
2246
|
id: Date.now().toString(),
|
|
2016
2247
|
operation: type,
|
|
@@ -2019,28 +2250,17 @@ var FeatureTool = class {
|
|
|
2019
2250
|
x: 0.5,
|
|
2020
2251
|
y: 0,
|
|
2021
2252
|
// Top edge
|
|
2022
|
-
width:
|
|
2023
|
-
height:
|
|
2253
|
+
width: 10,
|
|
2254
|
+
height: 10,
|
|
2024
2255
|
rotation: 0
|
|
2025
2256
|
};
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
[]
|
|
2030
|
-
);
|
|
2031
|
-
configService.update("dieline.features", [...current, newFeature]);
|
|
2032
|
-
}
|
|
2257
|
+
this.setWorkingFeatures([...this.workingFeatures || [], newFeature]);
|
|
2258
|
+
this.redraw();
|
|
2259
|
+
this.emitWorkingChange();
|
|
2033
2260
|
return true;
|
|
2034
2261
|
}
|
|
2035
2262
|
addDoubleLayerHole() {
|
|
2036
|
-
var _a;
|
|
2037
2263
|
if (!this.canvasService) return false;
|
|
2038
|
-
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
2039
|
-
"ConfigurationService"
|
|
2040
|
-
);
|
|
2041
|
-
const unit = (configService == null ? void 0 : configService.get("dieline.unit", "mm")) || "mm";
|
|
2042
|
-
const lugRadius = Coordinate.convertUnit(20, "mm", unit);
|
|
2043
|
-
const holeRadius = Coordinate.convertUnit(15, "mm", unit);
|
|
2044
2264
|
const groupId = Date.now().toString();
|
|
2045
2265
|
const timestamp = Date.now();
|
|
2046
2266
|
const lug = {
|
|
@@ -2051,8 +2271,7 @@ var FeatureTool = class {
|
|
|
2051
2271
|
placement: "edge",
|
|
2052
2272
|
x: 0.5,
|
|
2053
2273
|
y: 0,
|
|
2054
|
-
radius:
|
|
2055
|
-
// 20mm
|
|
2274
|
+
radius: 20,
|
|
2056
2275
|
rotation: 0
|
|
2057
2276
|
};
|
|
2058
2277
|
const hole = {
|
|
@@ -2063,17 +2282,12 @@ var FeatureTool = class {
|
|
|
2063
2282
|
placement: "edge",
|
|
2064
2283
|
x: 0.5,
|
|
2065
2284
|
y: 0,
|
|
2066
|
-
radius:
|
|
2067
|
-
// 15mm
|
|
2285
|
+
radius: 15,
|
|
2068
2286
|
rotation: 0
|
|
2069
2287
|
};
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
[]
|
|
2074
|
-
);
|
|
2075
|
-
configService.update("dieline.features", [...current, lug, hole]);
|
|
2076
|
-
}
|
|
2288
|
+
this.setWorkingFeatures([...this.workingFeatures || [], lug, hole]);
|
|
2289
|
+
this.redraw();
|
|
2290
|
+
this.emitWorkingChange();
|
|
2077
2291
|
return true;
|
|
2078
2292
|
}
|
|
2079
2293
|
getGeometryForFeature(geometry, feature) {
|
|
@@ -2117,12 +2331,12 @@ var FeatureTool = class {
|
|
|
2117
2331
|
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
2118
2332
|
const indices = (_c = target.data) == null ? void 0 : _c.indices;
|
|
2119
2333
|
if (indices && indices.length > 0) {
|
|
2120
|
-
feature = this.
|
|
2334
|
+
feature = this.workingFeatures[indices[0]];
|
|
2121
2335
|
}
|
|
2122
2336
|
} else {
|
|
2123
2337
|
const index = (_d = target.data) == null ? void 0 : _d.index;
|
|
2124
2338
|
if (index !== void 0) {
|
|
2125
|
-
feature = this.
|
|
2339
|
+
feature = this.workingFeatures[index];
|
|
2126
2340
|
}
|
|
2127
2341
|
}
|
|
2128
2342
|
const geometry = this.getGeometryForFeature(
|
|
@@ -2143,7 +2357,7 @@ var FeatureTool = class {
|
|
|
2143
2357
|
}
|
|
2144
2358
|
if (!this.handleModified) {
|
|
2145
2359
|
this.handleModified = (e) => {
|
|
2146
|
-
var _a, _b, _c
|
|
2360
|
+
var _a, _b, _c;
|
|
2147
2361
|
const target = e.target;
|
|
2148
2362
|
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "feature-marker") return;
|
|
2149
2363
|
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
@@ -2151,11 +2365,11 @@ var FeatureTool = class {
|
|
|
2151
2365
|
const indices = (_c = groupObj.data) == null ? void 0 : _c.indices;
|
|
2152
2366
|
if (!indices) return;
|
|
2153
2367
|
const groupCenter = new Point(groupObj.left, groupObj.top);
|
|
2154
|
-
const newFeatures = [...this.
|
|
2368
|
+
const newFeatures = [...this.workingFeatures];
|
|
2155
2369
|
const { x, y } = this.currentGeometry;
|
|
2156
2370
|
groupObj.getObjects().forEach((child, i) => {
|
|
2157
2371
|
const originalIndex = indices[i];
|
|
2158
|
-
const feature = this.
|
|
2372
|
+
const feature = this.workingFeatures[originalIndex];
|
|
2159
2373
|
const geometry = this.getGeometryForFeature(
|
|
2160
2374
|
this.currentGeometry,
|
|
2161
2375
|
feature
|
|
@@ -2173,18 +2387,8 @@ var FeatureTool = class {
|
|
|
2173
2387
|
y: normalizedY
|
|
2174
2388
|
};
|
|
2175
2389
|
});
|
|
2176
|
-
this.
|
|
2177
|
-
|
|
2178
|
-
"ConfigurationService"
|
|
2179
|
-
);
|
|
2180
|
-
if (configService) {
|
|
2181
|
-
this.isUpdatingConfig = true;
|
|
2182
|
-
try {
|
|
2183
|
-
configService.update("dieline.features", this.features);
|
|
2184
|
-
} finally {
|
|
2185
|
-
this.isUpdatingConfig = false;
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2390
|
+
this.setWorkingFeatures(newFeatures);
|
|
2391
|
+
this.emitWorkingChange();
|
|
2188
2392
|
} else {
|
|
2189
2393
|
this.syncFeatureFromCanvas(target);
|
|
2190
2394
|
}
|
|
@@ -2245,10 +2449,13 @@ var FeatureTool = class {
|
|
|
2245
2449
|
y: Math.max(minY, Math.min(maxY, p.y))
|
|
2246
2450
|
};
|
|
2247
2451
|
}
|
|
2248
|
-
const nearest = getNearestPointOnDieline(
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2452
|
+
const nearest = getNearestPointOnDieline(
|
|
2453
|
+
{ x: p.x, y: p.y },
|
|
2454
|
+
{
|
|
2455
|
+
...geometry,
|
|
2456
|
+
features: []
|
|
2457
|
+
}
|
|
2458
|
+
);
|
|
2252
2459
|
const dx = p.x - nearest.x;
|
|
2253
2460
|
const dy = p.y - nearest.y;
|
|
2254
2461
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
@@ -2265,9 +2472,9 @@ var FeatureTool = class {
|
|
|
2265
2472
|
var _a;
|
|
2266
2473
|
if (!this.currentGeometry || !this.context) return;
|
|
2267
2474
|
const index = (_a = target.data) == null ? void 0 : _a.index;
|
|
2268
|
-
if (index === void 0 || index < 0 || index >= this.
|
|
2475
|
+
if (index === void 0 || index < 0 || index >= this.workingFeatures.length)
|
|
2269
2476
|
return;
|
|
2270
|
-
const feature = this.
|
|
2477
|
+
const feature = this.workingFeatures[index];
|
|
2271
2478
|
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
2272
2479
|
const { width, height, x, y } = geometry;
|
|
2273
2480
|
const left = x - width / 2;
|
|
@@ -2280,20 +2487,10 @@ var FeatureTool = class {
|
|
|
2280
2487
|
y: normalizedY
|
|
2281
2488
|
// Could also update rotation if we allowed rotating markers
|
|
2282
2489
|
};
|
|
2283
|
-
const newFeatures = [...this.
|
|
2490
|
+
const newFeatures = [...this.workingFeatures];
|
|
2284
2491
|
newFeatures[index] = updatedFeature;
|
|
2285
|
-
this.
|
|
2286
|
-
|
|
2287
|
-
"ConfigurationService"
|
|
2288
|
-
);
|
|
2289
|
-
if (configService) {
|
|
2290
|
-
this.isUpdatingConfig = true;
|
|
2291
|
-
try {
|
|
2292
|
-
configService.update("dieline.features", this.features);
|
|
2293
|
-
} finally {
|
|
2294
|
-
this.isUpdatingConfig = false;
|
|
2295
|
-
}
|
|
2296
|
-
}
|
|
2492
|
+
this.setWorkingFeatures(newFeatures);
|
|
2493
|
+
this.emitWorkingChange();
|
|
2297
2494
|
}
|
|
2298
2495
|
redraw() {
|
|
2299
2496
|
if (!this.canvasService || !this.currentGeometry) return;
|
|
@@ -2304,7 +2501,7 @@ var FeatureTool = class {
|
|
|
2304
2501
|
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
2305
2502
|
});
|
|
2306
2503
|
existing.forEach((obj) => canvas.remove(obj));
|
|
2307
|
-
if (!this.
|
|
2504
|
+
if (!this.workingFeatures || this.workingFeatures.length === 0) {
|
|
2308
2505
|
this.canvasService.requestRenderAll();
|
|
2309
2506
|
return;
|
|
2310
2507
|
}
|
|
@@ -2312,7 +2509,7 @@ var FeatureTool = class {
|
|
|
2312
2509
|
const finalScale = scale;
|
|
2313
2510
|
const groups = {};
|
|
2314
2511
|
const singles = [];
|
|
2315
|
-
this.
|
|
2512
|
+
this.workingFeatures.forEach((f, i) => {
|
|
2316
2513
|
if (f.groupId) {
|
|
2317
2514
|
if (!groups[f.groupId]) groups[f.groupId] = [];
|
|
2318
2515
|
groups[f.groupId].push({ feature: f, index: i });
|
|
@@ -2380,25 +2577,6 @@ var FeatureTool = class {
|
|
|
2380
2577
|
lockScalingY: true,
|
|
2381
2578
|
data: { type: "feature-marker", index, isGroup: false }
|
|
2382
2579
|
});
|
|
2383
|
-
marker.set("opacity", 0);
|
|
2384
|
-
marker.on("mouseover", () => {
|
|
2385
|
-
marker.set("opacity", 1);
|
|
2386
|
-
canvas.requestRenderAll();
|
|
2387
|
-
});
|
|
2388
|
-
marker.on("mouseout", () => {
|
|
2389
|
-
if (canvas.getActiveObject() !== marker) {
|
|
2390
|
-
marker.set("opacity", 0);
|
|
2391
|
-
canvas.requestRenderAll();
|
|
2392
|
-
}
|
|
2393
|
-
});
|
|
2394
|
-
marker.on("selected", () => {
|
|
2395
|
-
marker.set("opacity", 1);
|
|
2396
|
-
canvas.requestRenderAll();
|
|
2397
|
-
});
|
|
2398
|
-
marker.on("deselected", () => {
|
|
2399
|
-
marker.set("opacity", 0);
|
|
2400
|
-
canvas.requestRenderAll();
|
|
2401
|
-
});
|
|
2402
2580
|
canvas.add(marker);
|
|
2403
2581
|
canvas.bringObjectToFront(marker);
|
|
2404
2582
|
});
|
|
@@ -2435,25 +2613,6 @@ var FeatureTool = class {
|
|
|
2435
2613
|
indices: members.map((m) => m.index)
|
|
2436
2614
|
}
|
|
2437
2615
|
});
|
|
2438
|
-
groupObj.set("opacity", 0);
|
|
2439
|
-
groupObj.on("mouseover", () => {
|
|
2440
|
-
groupObj.set("opacity", 1);
|
|
2441
|
-
canvas.requestRenderAll();
|
|
2442
|
-
});
|
|
2443
|
-
groupObj.on("mouseout", () => {
|
|
2444
|
-
if (canvas.getActiveObject() !== groupObj) {
|
|
2445
|
-
groupObj.set("opacity", 0);
|
|
2446
|
-
canvas.requestRenderAll();
|
|
2447
|
-
}
|
|
2448
|
-
});
|
|
2449
|
-
groupObj.on("selected", () => {
|
|
2450
|
-
groupObj.set("opacity", 1);
|
|
2451
|
-
canvas.requestRenderAll();
|
|
2452
|
-
});
|
|
2453
|
-
groupObj.on("deselected", () => {
|
|
2454
|
-
groupObj.set("opacity", 0);
|
|
2455
|
-
canvas.requestRenderAll();
|
|
2456
|
-
});
|
|
2457
2616
|
canvas.add(groupObj);
|
|
2458
2617
|
canvas.bringObjectToFront(groupObj);
|
|
2459
2618
|
});
|
|
@@ -2472,12 +2631,12 @@ var FeatureTool = class {
|
|
|
2472
2631
|
if ((_a = marker.data) == null ? void 0 : _a.isGroup) {
|
|
2473
2632
|
const indices = (_b = marker.data) == null ? void 0 : _b.indices;
|
|
2474
2633
|
if (indices && indices.length > 0) {
|
|
2475
|
-
feature = this.
|
|
2634
|
+
feature = this.workingFeatures[indices[0]];
|
|
2476
2635
|
}
|
|
2477
2636
|
} else {
|
|
2478
2637
|
const index = (_c = marker.data) == null ? void 0 : _c.index;
|
|
2479
2638
|
if (index !== void 0) {
|
|
2480
|
-
feature = this.
|
|
2639
|
+
feature = this.workingFeatures[index];
|
|
2481
2640
|
}
|
|
2482
2641
|
}
|
|
2483
2642
|
const geometry = this.getGeometryForFeature(
|
|
@@ -3207,7 +3366,7 @@ var RulerTool = class {
|
|
|
3207
3366
|
// Dieline context for sync
|
|
3208
3367
|
this.dielineWidth = 500;
|
|
3209
3368
|
this.dielineHeight = 500;
|
|
3210
|
-
this.
|
|
3369
|
+
this.dielineDisplayUnit = "mm";
|
|
3211
3370
|
this.dielinePadding = 40;
|
|
3212
3371
|
this.dielineOffset = 0;
|
|
3213
3372
|
if (options) {
|
|
@@ -3231,7 +3390,10 @@ var RulerTool = class {
|
|
|
3231
3390
|
this.textColor = configService.get("ruler.textColor", this.textColor);
|
|
3232
3391
|
this.lineColor = configService.get("ruler.lineColor", this.lineColor);
|
|
3233
3392
|
this.fontSize = configService.get("ruler.fontSize", this.fontSize);
|
|
3234
|
-
this.
|
|
3393
|
+
this.dielineDisplayUnit = configService.get(
|
|
3394
|
+
"dieline.displayUnit",
|
|
3395
|
+
this.dielineDisplayUnit
|
|
3396
|
+
);
|
|
3235
3397
|
this.dielineWidth = configService.get("dieline.width", this.dielineWidth);
|
|
3236
3398
|
this.dielineHeight = configService.get(
|
|
3237
3399
|
"dieline.height",
|
|
@@ -3254,7 +3416,8 @@ var RulerTool = class {
|
|
|
3254
3416
|
shouldUpdate = true;
|
|
3255
3417
|
}
|
|
3256
3418
|
} else if (e.key.startsWith("dieline.")) {
|
|
3257
|
-
if (e.key === "dieline.
|
|
3419
|
+
if (e.key === "dieline.displayUnit")
|
|
3420
|
+
this.dielineDisplayUnit = e.value;
|
|
3258
3421
|
if (e.key === "dieline.width") this.dielineWidth = e.value;
|
|
3259
3422
|
if (e.key === "dieline.height") this.dielineHeight = e.value;
|
|
3260
3423
|
if (e.key === "dieline.padding") this.dielinePadding = e.value;
|
|
@@ -3441,26 +3604,27 @@ var RulerTool = class {
|
|
|
3441
3604
|
const width = this.canvasService.canvas.width || 800;
|
|
3442
3605
|
const height = this.canvasService.canvas.height || 600;
|
|
3443
3606
|
const paddingPx = this.resolvePadding(width, height);
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3607
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
3608
|
+
this.canvasService.viewport.updatePhysical(
|
|
3609
|
+
this.dielineWidth,
|
|
3610
|
+
this.dielineHeight
|
|
3448
3611
|
);
|
|
3612
|
+
const layout = this.canvasService.viewport.layout;
|
|
3449
3613
|
const scale = layout.scale;
|
|
3450
3614
|
const offsetX = layout.offsetX;
|
|
3451
3615
|
const offsetY = layout.offsetY;
|
|
3452
3616
|
const visualWidth = layout.width;
|
|
3453
3617
|
const visualHeight = layout.height;
|
|
3454
|
-
const
|
|
3455
|
-
const
|
|
3456
|
-
const expandPixels =
|
|
3618
|
+
const rawOffsetMm = this.dielineOffset || 0;
|
|
3619
|
+
const effectiveOffsetMm = rawOffsetMm > 0 ? rawOffsetMm : 0;
|
|
3620
|
+
const expandPixels = effectiveOffsetMm * scale;
|
|
3457
3621
|
const gap = this.gap || 15;
|
|
3458
3622
|
const rulerLeft = offsetX - expandPixels;
|
|
3459
3623
|
const rulerTop = offsetY - expandPixels;
|
|
3460
3624
|
const rulerRight = offsetX + visualWidth + expandPixels;
|
|
3461
3625
|
const rulerBottom = offsetY + visualHeight + expandPixels;
|
|
3462
|
-
const
|
|
3463
|
-
const
|
|
3626
|
+
const displayWidthMm = this.dielineWidth + effectiveOffsetMm * 2;
|
|
3627
|
+
const displayHeightMm = this.dielineHeight + effectiveOffsetMm * 2;
|
|
3464
3628
|
const topRulerY = rulerTop - gap;
|
|
3465
3629
|
const topRulerXStart = rulerLeft;
|
|
3466
3630
|
const topRulerXEnd = rulerRight;
|
|
@@ -3503,8 +3667,8 @@ var RulerTool = class {
|
|
|
3503
3667
|
}
|
|
3504
3668
|
)
|
|
3505
3669
|
);
|
|
3506
|
-
const widthStr =
|
|
3507
|
-
const topTextContent = `${widthStr} ${this.
|
|
3670
|
+
const widthStr = formatMm(displayWidthMm, this.dielineDisplayUnit);
|
|
3671
|
+
const topTextContent = `${widthStr} ${this.dielineDisplayUnit}`;
|
|
3508
3672
|
const topText = new Text(topTextContent, {
|
|
3509
3673
|
left: topRulerXStart + (rulerRight - rulerLeft) / 2,
|
|
3510
3674
|
top: topRulerY,
|
|
@@ -3559,8 +3723,8 @@ var RulerTool = class {
|
|
|
3559
3723
|
}
|
|
3560
3724
|
)
|
|
3561
3725
|
);
|
|
3562
|
-
const heightStr =
|
|
3563
|
-
const leftTextContent = `${heightStr} ${this.
|
|
3726
|
+
const heightStr = formatMm(displayHeightMm, this.dielineDisplayUnit);
|
|
3727
|
+
const leftTextContent = `${heightStr} ${this.dielineDisplayUnit}`;
|
|
3564
3728
|
const leftText = new Text(leftTextContent, {
|
|
3565
3729
|
left: leftRulerX,
|
|
3566
3730
|
top: leftRulerYStart + (rulerBottom - rulerTop) / 2,
|
|
@@ -3674,6 +3838,81 @@ var MirrorTool = class {
|
|
|
3674
3838
|
|
|
3675
3839
|
// src/CanvasService.ts
|
|
3676
3840
|
import { Canvas, Group as Group3 } from "fabric";
|
|
3841
|
+
|
|
3842
|
+
// src/ViewportSystem.ts
|
|
3843
|
+
var ViewportSystem = class {
|
|
3844
|
+
constructor(containerSize = { width: 0, height: 0 }, physicalSize = { width: 0, height: 0 }, padding = 40) {
|
|
3845
|
+
this._containerSize = { width: 0, height: 0 };
|
|
3846
|
+
this._physicalSize = { width: 0, height: 0 };
|
|
3847
|
+
this._padding = 0;
|
|
3848
|
+
this._layout = {
|
|
3849
|
+
scale: 1,
|
|
3850
|
+
offsetX: 0,
|
|
3851
|
+
offsetY: 0,
|
|
3852
|
+
width: 0,
|
|
3853
|
+
height: 0
|
|
3854
|
+
};
|
|
3855
|
+
this._containerSize = containerSize;
|
|
3856
|
+
this._physicalSize = physicalSize;
|
|
3857
|
+
this._padding = padding;
|
|
3858
|
+
this.updateLayout();
|
|
3859
|
+
}
|
|
3860
|
+
get layout() {
|
|
3861
|
+
return this._layout;
|
|
3862
|
+
}
|
|
3863
|
+
get scale() {
|
|
3864
|
+
return this._layout.scale;
|
|
3865
|
+
}
|
|
3866
|
+
get offset() {
|
|
3867
|
+
return { x: this._layout.offsetX, y: this._layout.offsetY };
|
|
3868
|
+
}
|
|
3869
|
+
updateContainer(width, height) {
|
|
3870
|
+
if (this._containerSize.width === width && this._containerSize.height === height)
|
|
3871
|
+
return;
|
|
3872
|
+
this._containerSize = { width, height };
|
|
3873
|
+
this.updateLayout();
|
|
3874
|
+
}
|
|
3875
|
+
updatePhysical(width, height) {
|
|
3876
|
+
if (this._physicalSize.width === width && this._physicalSize.height === height)
|
|
3877
|
+
return;
|
|
3878
|
+
this._physicalSize = { width, height };
|
|
3879
|
+
this.updateLayout();
|
|
3880
|
+
}
|
|
3881
|
+
setPadding(padding) {
|
|
3882
|
+
if (this._padding === padding) return;
|
|
3883
|
+
this._padding = padding;
|
|
3884
|
+
this.updateLayout();
|
|
3885
|
+
}
|
|
3886
|
+
updateLayout() {
|
|
3887
|
+
this._layout = Coordinate.calculateLayout(
|
|
3888
|
+
this._containerSize,
|
|
3889
|
+
this._physicalSize,
|
|
3890
|
+
this._padding
|
|
3891
|
+
);
|
|
3892
|
+
}
|
|
3893
|
+
toPixel(value) {
|
|
3894
|
+
return value * this._layout.scale;
|
|
3895
|
+
}
|
|
3896
|
+
toPhysical(value) {
|
|
3897
|
+
return this._layout.scale === 0 ? 0 : value / this._layout.scale;
|
|
3898
|
+
}
|
|
3899
|
+
toPixelPoint(point) {
|
|
3900
|
+
return {
|
|
3901
|
+
x: point.x * this._layout.scale + this._layout.offsetX,
|
|
3902
|
+
y: point.y * this._layout.scale + this._layout.offsetY
|
|
3903
|
+
};
|
|
3904
|
+
}
|
|
3905
|
+
// Convert screen coordinate (e.g. mouse event) to physical coordinate (relative to content origin)
|
|
3906
|
+
toPhysicalPoint(point) {
|
|
3907
|
+
if (this._layout.scale === 0) return { x: 0, y: 0 };
|
|
3908
|
+
return {
|
|
3909
|
+
x: (point.x - this._layout.offsetX) / this._layout.scale,
|
|
3910
|
+
y: (point.y - this._layout.offsetY) / this._layout.scale
|
|
3911
|
+
};
|
|
3912
|
+
}
|
|
3913
|
+
};
|
|
3914
|
+
|
|
3915
|
+
// src/CanvasService.ts
|
|
3677
3916
|
var CanvasService = class {
|
|
3678
3917
|
constructor(el, options) {
|
|
3679
3918
|
if (el instanceof Canvas) {
|
|
@@ -3684,6 +3923,10 @@ var CanvasService = class {
|
|
|
3684
3923
|
...options
|
|
3685
3924
|
});
|
|
3686
3925
|
}
|
|
3926
|
+
this.viewport = new ViewportSystem();
|
|
3927
|
+
if (this.canvas.width !== void 0 && this.canvas.height !== void 0) {
|
|
3928
|
+
this.viewport.updateContainer(this.canvas.width, this.canvas.height);
|
|
3929
|
+
}
|
|
3687
3930
|
if (options == null ? void 0 : options.eventBus) {
|
|
3688
3931
|
this.setEventBus(options.eventBus);
|
|
3689
3932
|
}
|
|
@@ -3763,5 +4006,7 @@ export {
|
|
|
3763
4006
|
ImageTool,
|
|
3764
4007
|
MirrorTool,
|
|
3765
4008
|
RulerTool,
|
|
3766
|
-
WhiteInkTool
|
|
4009
|
+
WhiteInkTool,
|
|
4010
|
+
formatMm,
|
|
4011
|
+
parseLengthToMm
|
|
3767
4012
|
};
|