@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.js
CHANGED
|
@@ -38,7 +38,9 @@ __export(index_exports, {
|
|
|
38
38
|
ImageTool: () => ImageTool,
|
|
39
39
|
MirrorTool: () => MirrorTool,
|
|
40
40
|
RulerTool: () => RulerTool,
|
|
41
|
-
WhiteInkTool: () => WhiteInkTool
|
|
41
|
+
WhiteInkTool: () => WhiteInkTool,
|
|
42
|
+
formatMm: () => formatMm,
|
|
43
|
+
parseLengthToMm: () => parseLengthToMm
|
|
42
44
|
});
|
|
43
45
|
module.exports = __toCommonJS(index_exports);
|
|
44
46
|
|
|
@@ -717,6 +719,29 @@ var Coordinate = class {
|
|
|
717
719
|
}
|
|
718
720
|
};
|
|
719
721
|
|
|
722
|
+
// src/units.ts
|
|
723
|
+
function parseLengthToMm(input, defaultUnit) {
|
|
724
|
+
var _a, _b;
|
|
725
|
+
if (typeof input === "number") {
|
|
726
|
+
if (!Number.isFinite(input)) return 0;
|
|
727
|
+
return Coordinate.convertUnit(input, defaultUnit, "mm");
|
|
728
|
+
}
|
|
729
|
+
const raw = input.trim();
|
|
730
|
+
if (!raw) return 0;
|
|
731
|
+
const match = raw.match(/^([+-]?\d+(?:\.\d+)?)\s*(px|mm|cm|in)?$/i);
|
|
732
|
+
if (!match) return 0;
|
|
733
|
+
const value = Number(match[1]);
|
|
734
|
+
if (!Number.isFinite(value)) return 0;
|
|
735
|
+
const unit = (_b = (_a = match[2]) == null ? void 0 : _a.toLowerCase()) != null ? _b : defaultUnit;
|
|
736
|
+
return Coordinate.convertUnit(value, unit, "mm");
|
|
737
|
+
}
|
|
738
|
+
function formatMm(valueMm, displayUnit, fractionDigits = 2) {
|
|
739
|
+
if (!Number.isFinite(valueMm)) return "0";
|
|
740
|
+
const value = Coordinate.convertUnit(valueMm, "mm", displayUnit);
|
|
741
|
+
const rounded = Number(value.toFixed(fractionDigits));
|
|
742
|
+
return rounded.toString();
|
|
743
|
+
}
|
|
744
|
+
|
|
720
745
|
// src/geometry.ts
|
|
721
746
|
var import_paper2 = __toESM(require("paper"));
|
|
722
747
|
function resolveFeaturePosition(feature, geometry) {
|
|
@@ -940,105 +965,6 @@ function getPathBounds(pathData) {
|
|
|
940
965
|
};
|
|
941
966
|
}
|
|
942
967
|
|
|
943
|
-
// src/constraints.ts
|
|
944
|
-
var ConstraintRegistry = class {
|
|
945
|
-
static register(type, handler) {
|
|
946
|
-
this.handlers.set(type, handler);
|
|
947
|
-
}
|
|
948
|
-
static apply(x, y, feature, context) {
|
|
949
|
-
if (!feature.constraints || !feature.constraints.type) {
|
|
950
|
-
return { x, y };
|
|
951
|
-
}
|
|
952
|
-
const handler = this.handlers.get(feature.constraints.type);
|
|
953
|
-
if (handler) {
|
|
954
|
-
return handler(x, y, feature, context);
|
|
955
|
-
}
|
|
956
|
-
return { x, y };
|
|
957
|
-
}
|
|
958
|
-
};
|
|
959
|
-
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
960
|
-
var edgeConstraint = (x, y, feature, context) => {
|
|
961
|
-
var _a;
|
|
962
|
-
const { dielineWidth, dielineHeight } = context;
|
|
963
|
-
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
964
|
-
const allowedEdges = params.allowedEdges || [
|
|
965
|
-
"top",
|
|
966
|
-
"bottom",
|
|
967
|
-
"left",
|
|
968
|
-
"right"
|
|
969
|
-
];
|
|
970
|
-
const confine = params.confine || false;
|
|
971
|
-
const offset = params.offset || 0;
|
|
972
|
-
const distances = [];
|
|
973
|
-
if (allowedEdges.includes("top"))
|
|
974
|
-
distances.push({ edge: "top", dist: y * dielineHeight });
|
|
975
|
-
if (allowedEdges.includes("bottom"))
|
|
976
|
-
distances.push({ edge: "bottom", dist: (1 - y) * dielineHeight });
|
|
977
|
-
if (allowedEdges.includes("left"))
|
|
978
|
-
distances.push({ edge: "left", dist: x * dielineWidth });
|
|
979
|
-
if (allowedEdges.includes("right"))
|
|
980
|
-
distances.push({ edge: "right", dist: (1 - x) * dielineWidth });
|
|
981
|
-
if (distances.length === 0) return { x, y };
|
|
982
|
-
distances.sort((a, b) => a.dist - b.dist);
|
|
983
|
-
const nearest = distances[0].edge;
|
|
984
|
-
let newX = x;
|
|
985
|
-
let newY = y;
|
|
986
|
-
const fw = feature.width || 0;
|
|
987
|
-
const fh = feature.height || 0;
|
|
988
|
-
switch (nearest) {
|
|
989
|
-
case "top":
|
|
990
|
-
newY = 0 + offset / dielineHeight;
|
|
991
|
-
if (confine) {
|
|
992
|
-
const minX = fw / 2 / dielineWidth;
|
|
993
|
-
const maxX = 1 - minX;
|
|
994
|
-
newX = Math.max(minX, Math.min(newX, maxX));
|
|
995
|
-
}
|
|
996
|
-
break;
|
|
997
|
-
case "bottom":
|
|
998
|
-
newY = 1 - offset / dielineHeight;
|
|
999
|
-
if (confine) {
|
|
1000
|
-
const minX = fw / 2 / dielineWidth;
|
|
1001
|
-
const maxX = 1 - minX;
|
|
1002
|
-
newX = Math.max(minX, Math.min(newX, maxX));
|
|
1003
|
-
}
|
|
1004
|
-
break;
|
|
1005
|
-
case "left":
|
|
1006
|
-
newX = 0 + offset / dielineWidth;
|
|
1007
|
-
if (confine) {
|
|
1008
|
-
const minY = fh / 2 / dielineHeight;
|
|
1009
|
-
const maxY = 1 - minY;
|
|
1010
|
-
newY = Math.max(minY, Math.min(newY, maxY));
|
|
1011
|
-
}
|
|
1012
|
-
break;
|
|
1013
|
-
case "right":
|
|
1014
|
-
newX = 1 - offset / dielineWidth;
|
|
1015
|
-
if (confine) {
|
|
1016
|
-
const minY = fh / 2 / dielineHeight;
|
|
1017
|
-
const maxY = 1 - minY;
|
|
1018
|
-
newY = Math.max(minY, Math.min(newY, maxY));
|
|
1019
|
-
}
|
|
1020
|
-
break;
|
|
1021
|
-
}
|
|
1022
|
-
return { x: newX, y: newY };
|
|
1023
|
-
};
|
|
1024
|
-
var internalConstraint = (x, y, feature, context) => {
|
|
1025
|
-
var _a;
|
|
1026
|
-
const { dielineWidth, dielineHeight } = context;
|
|
1027
|
-
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1028
|
-
const margin = params.margin || 0;
|
|
1029
|
-
const fw = feature.width || 0;
|
|
1030
|
-
const fh = feature.height || 0;
|
|
1031
|
-
const minX = (margin + fw / 2) / dielineWidth;
|
|
1032
|
-
const maxX = 1 - (margin + fw / 2) / dielineWidth;
|
|
1033
|
-
const minY = (margin + fh / 2) / dielineHeight;
|
|
1034
|
-
const maxY = 1 - (margin + fh / 2) / dielineHeight;
|
|
1035
|
-
const clampedX = minX > maxX ? 0.5 : Math.max(minX, Math.min(x, maxX));
|
|
1036
|
-
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
1037
|
-
return { x: clampedX, y: clampedY };
|
|
1038
|
-
};
|
|
1039
|
-
ConstraintRegistry.register("edge", edgeConstraint);
|
|
1040
|
-
ConstraintRegistry.register("internal", internalConstraint);
|
|
1041
|
-
|
|
1042
968
|
// src/dieline.ts
|
|
1043
969
|
var DielineTool = class {
|
|
1044
970
|
constructor(options) {
|
|
@@ -1047,7 +973,7 @@ var DielineTool = class {
|
|
|
1047
973
|
name: "DielineTool"
|
|
1048
974
|
};
|
|
1049
975
|
this.state = {
|
|
1050
|
-
|
|
976
|
+
displayUnit: "mm",
|
|
1051
977
|
shape: "rect",
|
|
1052
978
|
width: 500,
|
|
1053
979
|
height: 500,
|
|
@@ -1093,50 +1019,88 @@ var DielineTool = class {
|
|
|
1093
1019
|
const configService = context.services.get("ConfigurationService");
|
|
1094
1020
|
if (configService) {
|
|
1095
1021
|
const s = this.state;
|
|
1096
|
-
s.
|
|
1022
|
+
s.displayUnit = configService.get("dieline.displayUnit", s.displayUnit);
|
|
1097
1023
|
s.shape = configService.get("dieline.shape", s.shape);
|
|
1098
|
-
s.width =
|
|
1099
|
-
|
|
1100
|
-
|
|
1024
|
+
s.width = parseLengthToMm(
|
|
1025
|
+
configService.get("dieline.width", s.width),
|
|
1026
|
+
"mm"
|
|
1027
|
+
);
|
|
1028
|
+
s.height = parseLengthToMm(
|
|
1029
|
+
configService.get("dieline.height", s.height),
|
|
1030
|
+
"mm"
|
|
1031
|
+
);
|
|
1032
|
+
s.radius = parseLengthToMm(
|
|
1033
|
+
configService.get("dieline.radius", s.radius),
|
|
1034
|
+
"mm"
|
|
1035
|
+
);
|
|
1101
1036
|
s.padding = configService.get("dieline.padding", s.padding);
|
|
1102
|
-
s.offset =
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1037
|
+
s.offset = parseLengthToMm(
|
|
1038
|
+
configService.get("dieline.offset", s.offset),
|
|
1039
|
+
"mm"
|
|
1040
|
+
);
|
|
1041
|
+
s.mainLine.width = configService.get(
|
|
1042
|
+
"dieline.strokeWidth",
|
|
1043
|
+
s.mainLine.width
|
|
1044
|
+
);
|
|
1045
|
+
s.mainLine.color = configService.get(
|
|
1046
|
+
"dieline.strokeColor",
|
|
1047
|
+
s.mainLine.color
|
|
1048
|
+
);
|
|
1049
|
+
s.mainLine.dashLength = configService.get(
|
|
1050
|
+
"dieline.dashLength",
|
|
1051
|
+
s.mainLine.dashLength
|
|
1052
|
+
);
|
|
1106
1053
|
s.mainLine.style = configService.get("dieline.style", s.mainLine.style);
|
|
1107
|
-
s.offsetLine.width = configService.get(
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1054
|
+
s.offsetLine.width = configService.get(
|
|
1055
|
+
"dieline.offsetStrokeWidth",
|
|
1056
|
+
s.offsetLine.width
|
|
1057
|
+
);
|
|
1058
|
+
s.offsetLine.color = configService.get(
|
|
1059
|
+
"dieline.offsetStrokeColor",
|
|
1060
|
+
s.offsetLine.color
|
|
1061
|
+
);
|
|
1062
|
+
s.offsetLine.dashLength = configService.get(
|
|
1063
|
+
"dieline.offsetDashLength",
|
|
1064
|
+
s.offsetLine.dashLength
|
|
1065
|
+
);
|
|
1066
|
+
s.offsetLine.style = configService.get(
|
|
1067
|
+
"dieline.offsetStyle",
|
|
1068
|
+
s.offsetLine.style
|
|
1069
|
+
);
|
|
1111
1070
|
s.insideColor = configService.get("dieline.insideColor", s.insideColor);
|
|
1112
|
-
s.outsideColor = configService.get(
|
|
1113
|
-
|
|
1071
|
+
s.outsideColor = configService.get(
|
|
1072
|
+
"dieline.outsideColor",
|
|
1073
|
+
s.outsideColor
|
|
1074
|
+
);
|
|
1075
|
+
s.showBleedLines = configService.get(
|
|
1076
|
+
"dieline.showBleedLines",
|
|
1077
|
+
s.showBleedLines
|
|
1078
|
+
);
|
|
1114
1079
|
s.features = configService.get("dieline.features", s.features);
|
|
1115
1080
|
s.pathData = configService.get("dieline.pathData", s.pathData);
|
|
1116
1081
|
configService.onAnyChange((e) => {
|
|
1117
1082
|
if (e.key.startsWith("dieline.")) {
|
|
1118
|
-
console.log(`[DielineTool] Config change detected: ${e.key} -> ${e.value}`);
|
|
1119
1083
|
switch (e.key) {
|
|
1120
|
-
case "dieline.
|
|
1121
|
-
s.
|
|
1084
|
+
case "dieline.displayUnit":
|
|
1085
|
+
s.displayUnit = e.value;
|
|
1122
1086
|
break;
|
|
1123
1087
|
case "dieline.shape":
|
|
1124
1088
|
s.shape = e.value;
|
|
1125
1089
|
break;
|
|
1126
1090
|
case "dieline.width":
|
|
1127
|
-
s.width = e.value;
|
|
1091
|
+
s.width = parseLengthToMm(e.value, "mm");
|
|
1128
1092
|
break;
|
|
1129
1093
|
case "dieline.height":
|
|
1130
|
-
s.height = e.value;
|
|
1094
|
+
s.height = parseLengthToMm(e.value, "mm");
|
|
1131
1095
|
break;
|
|
1132
1096
|
case "dieline.radius":
|
|
1133
|
-
s.radius = e.value;
|
|
1097
|
+
s.radius = parseLengthToMm(e.value, "mm");
|
|
1134
1098
|
break;
|
|
1135
1099
|
case "dieline.padding":
|
|
1136
1100
|
s.padding = e.value;
|
|
1137
1101
|
break;
|
|
1138
1102
|
case "dieline.offset":
|
|
1139
|
-
s.offset = e.value;
|
|
1103
|
+
s.offset = parseLengthToMm(e.value, "mm");
|
|
1140
1104
|
break;
|
|
1141
1105
|
case "dieline.strokeWidth":
|
|
1142
1106
|
s.mainLine.width = e.value;
|
|
@@ -1195,11 +1159,11 @@ var DielineTool = class {
|
|
|
1195
1159
|
return {
|
|
1196
1160
|
[import_core2.ContributionPointIds.CONFIGURATIONS]: [
|
|
1197
1161
|
{
|
|
1198
|
-
id: "dieline.
|
|
1162
|
+
id: "dieline.displayUnit",
|
|
1199
1163
|
type: "select",
|
|
1200
|
-
label: "Unit",
|
|
1201
|
-
options: ["
|
|
1202
|
-
default: s.
|
|
1164
|
+
label: "Display Unit",
|
|
1165
|
+
options: ["mm", "cm", "in"],
|
|
1166
|
+
default: s.displayUnit
|
|
1203
1167
|
},
|
|
1204
1168
|
{
|
|
1205
1169
|
id: "dieline.shape",
|
|
@@ -1211,7 +1175,7 @@ var DielineTool = class {
|
|
|
1211
1175
|
{
|
|
1212
1176
|
id: "dieline.width",
|
|
1213
1177
|
type: "number",
|
|
1214
|
-
label: "Width",
|
|
1178
|
+
label: "Width (mm)",
|
|
1215
1179
|
min: 10,
|
|
1216
1180
|
max: 2e3,
|
|
1217
1181
|
default: s.width
|
|
@@ -1219,7 +1183,7 @@ var DielineTool = class {
|
|
|
1219
1183
|
{
|
|
1220
1184
|
id: "dieline.height",
|
|
1221
1185
|
type: "number",
|
|
1222
|
-
label: "Height",
|
|
1186
|
+
label: "Height (mm)",
|
|
1223
1187
|
min: 10,
|
|
1224
1188
|
max: 2e3,
|
|
1225
1189
|
default: s.height
|
|
@@ -1227,7 +1191,7 @@ var DielineTool = class {
|
|
|
1227
1191
|
{
|
|
1228
1192
|
id: "dieline.radius",
|
|
1229
1193
|
type: "number",
|
|
1230
|
-
label: "Corner Radius",
|
|
1194
|
+
label: "Corner Radius (mm)",
|
|
1231
1195
|
min: 0,
|
|
1232
1196
|
max: 500,
|
|
1233
1197
|
default: s.radius
|
|
@@ -1242,7 +1206,7 @@ var DielineTool = class {
|
|
|
1242
1206
|
{
|
|
1243
1207
|
id: "dieline.offset",
|
|
1244
1208
|
type: "number",
|
|
1245
|
-
label: "Bleed Offset",
|
|
1209
|
+
label: "Bleed Offset (mm)",
|
|
1246
1210
|
min: -100,
|
|
1247
1211
|
max: 100,
|
|
1248
1212
|
default: s.offset
|
|
@@ -1343,18 +1307,12 @@ var DielineTool = class {
|
|
|
1343
1307
|
);
|
|
1344
1308
|
if (!configService) return;
|
|
1345
1309
|
const features = configService.get("dieline.features") || [];
|
|
1346
|
-
const dielineWidth = configService.get("dieline.width") || 500;
|
|
1347
|
-
const dielineHeight = configService.get("dieline.height") || 500;
|
|
1348
1310
|
let changed = false;
|
|
1349
1311
|
const newFeatures = features.map((f) => {
|
|
1350
1312
|
if (f.groupId === groupId) {
|
|
1351
|
-
|
|
1352
|
-
dielineWidth,
|
|
1353
|
-
dielineHeight
|
|
1354
|
-
});
|
|
1355
|
-
if (f.x !== constrained.x || f.y !== constrained.y) {
|
|
1313
|
+
if (f.x !== x || f.y !== y) {
|
|
1356
1314
|
changed = true;
|
|
1357
|
-
return { ...f, x
|
|
1315
|
+
return { ...f, x, y };
|
|
1358
1316
|
}
|
|
1359
1317
|
}
|
|
1360
1318
|
return f;
|
|
@@ -1469,7 +1427,7 @@ var DielineTool = class {
|
|
|
1469
1427
|
const layer = this.getLayer();
|
|
1470
1428
|
if (!layer) return;
|
|
1471
1429
|
const {
|
|
1472
|
-
|
|
1430
|
+
displayUnit,
|
|
1473
1431
|
shape,
|
|
1474
1432
|
radius,
|
|
1475
1433
|
offset,
|
|
@@ -1480,15 +1438,13 @@ var DielineTool = class {
|
|
|
1480
1438
|
showBleedLines,
|
|
1481
1439
|
features
|
|
1482
1440
|
} = this.state;
|
|
1483
|
-
|
|
1441
|
+
const { width, height } = this.state;
|
|
1484
1442
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1485
1443
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1486
1444
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
paddingPx
|
|
1491
|
-
);
|
|
1445
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1446
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1447
|
+
const layout = this.canvasService.viewport.layout;
|
|
1492
1448
|
const scale = layout.scale;
|
|
1493
1449
|
const cx = layout.offsetX + layout.width / 2;
|
|
1494
1450
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1675,15 +1631,22 @@ var DielineTool = class {
|
|
|
1675
1631
|
}
|
|
1676
1632
|
getGeometry() {
|
|
1677
1633
|
if (!this.canvasService) return null;
|
|
1678
|
-
const {
|
|
1634
|
+
const {
|
|
1635
|
+
displayUnit,
|
|
1636
|
+
shape,
|
|
1637
|
+
width,
|
|
1638
|
+
height,
|
|
1639
|
+
radius,
|
|
1640
|
+
offset,
|
|
1641
|
+
mainLine,
|
|
1642
|
+
pathData
|
|
1643
|
+
} = this.state;
|
|
1679
1644
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1680
1645
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1681
1646
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
paddingPx
|
|
1686
|
-
);
|
|
1647
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1648
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1649
|
+
const layout = this.canvasService.viewport.layout;
|
|
1687
1650
|
const scale = layout.scale;
|
|
1688
1651
|
const cx = layout.offsetX + layout.width / 2;
|
|
1689
1652
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1691,14 +1654,14 @@ var DielineTool = class {
|
|
|
1691
1654
|
const visualHeight = layout.height;
|
|
1692
1655
|
return {
|
|
1693
1656
|
shape,
|
|
1694
|
-
unit,
|
|
1657
|
+
unit: "mm",
|
|
1658
|
+
displayUnit,
|
|
1695
1659
|
x: cx,
|
|
1696
1660
|
y: cy,
|
|
1697
1661
|
width: visualWidth,
|
|
1698
1662
|
height: visualHeight,
|
|
1699
1663
|
radius: radius * scale,
|
|
1700
1664
|
offset: offset * scale,
|
|
1701
|
-
// Pass scale to help other tools (like FeatureTool) convert units
|
|
1702
1665
|
scale,
|
|
1703
1666
|
strokeWidth: mainLine.width,
|
|
1704
1667
|
pathData
|
|
@@ -1708,15 +1671,13 @@ var DielineTool = class {
|
|
|
1708
1671
|
if (!this.canvasService) return null;
|
|
1709
1672
|
const userLayer = this.canvasService.getLayer("user");
|
|
1710
1673
|
if (!userLayer) return null;
|
|
1711
|
-
const { shape, width, height, radius, features,
|
|
1674
|
+
const { shape, width, height, radius, features, pathData } = this.state;
|
|
1712
1675
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1713
1676
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1714
1677
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
paddingPx
|
|
1719
|
-
);
|
|
1678
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1679
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1680
|
+
const layout = this.canvasService.viewport.layout;
|
|
1720
1681
|
const scale = layout.scale;
|
|
1721
1682
|
const cx = layout.offsetX + layout.width / 2;
|
|
1722
1683
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1931,13 +1892,158 @@ var FilmTool = class {
|
|
|
1931
1892
|
// src/feature.ts
|
|
1932
1893
|
var import_core4 = require("@pooder/core");
|
|
1933
1894
|
var import_fabric4 = require("fabric");
|
|
1895
|
+
|
|
1896
|
+
// src/constraints.ts
|
|
1897
|
+
var ConstraintRegistry = class {
|
|
1898
|
+
static register(type, handler) {
|
|
1899
|
+
this.handlers.set(type, handler);
|
|
1900
|
+
}
|
|
1901
|
+
static apply(x, y, feature, context) {
|
|
1902
|
+
if (!feature.constraints || !feature.constraints.type) {
|
|
1903
|
+
return { x, y };
|
|
1904
|
+
}
|
|
1905
|
+
const handler = this.handlers.get(feature.constraints.type);
|
|
1906
|
+
if (handler) {
|
|
1907
|
+
return handler(x, y, feature, context);
|
|
1908
|
+
}
|
|
1909
|
+
return { x, y };
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
1913
|
+
var edgeConstraint = (x, y, feature, context) => {
|
|
1914
|
+
var _a;
|
|
1915
|
+
const { dielineWidth, dielineHeight } = context;
|
|
1916
|
+
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1917
|
+
const allowedEdges = params.allowedEdges || [
|
|
1918
|
+
"top",
|
|
1919
|
+
"bottom",
|
|
1920
|
+
"left",
|
|
1921
|
+
"right"
|
|
1922
|
+
];
|
|
1923
|
+
const confine = params.confine || false;
|
|
1924
|
+
const offset = params.offset || 0;
|
|
1925
|
+
const distances = [];
|
|
1926
|
+
if (allowedEdges.includes("top"))
|
|
1927
|
+
distances.push({ edge: "top", dist: y * dielineHeight });
|
|
1928
|
+
if (allowedEdges.includes("bottom"))
|
|
1929
|
+
distances.push({ edge: "bottom", dist: (1 - y) * dielineHeight });
|
|
1930
|
+
if (allowedEdges.includes("left"))
|
|
1931
|
+
distances.push({ edge: "left", dist: x * dielineWidth });
|
|
1932
|
+
if (allowedEdges.includes("right"))
|
|
1933
|
+
distances.push({ edge: "right", dist: (1 - x) * dielineWidth });
|
|
1934
|
+
if (distances.length === 0) return { x, y };
|
|
1935
|
+
distances.sort((a, b) => a.dist - b.dist);
|
|
1936
|
+
const nearest = distances[0].edge;
|
|
1937
|
+
let newX = x;
|
|
1938
|
+
let newY = y;
|
|
1939
|
+
const fw = feature.width || 0;
|
|
1940
|
+
const fh = feature.height || 0;
|
|
1941
|
+
switch (nearest) {
|
|
1942
|
+
case "top":
|
|
1943
|
+
newY = 0 + offset / dielineHeight;
|
|
1944
|
+
if (confine) {
|
|
1945
|
+
const minX = fw / 2 / dielineWidth;
|
|
1946
|
+
const maxX = 1 - minX;
|
|
1947
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
1948
|
+
}
|
|
1949
|
+
break;
|
|
1950
|
+
case "bottom":
|
|
1951
|
+
newY = 1 - offset / dielineHeight;
|
|
1952
|
+
if (confine) {
|
|
1953
|
+
const minX = fw / 2 / dielineWidth;
|
|
1954
|
+
const maxX = 1 - minX;
|
|
1955
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
1956
|
+
}
|
|
1957
|
+
break;
|
|
1958
|
+
case "left":
|
|
1959
|
+
newX = 0 + offset / dielineWidth;
|
|
1960
|
+
if (confine) {
|
|
1961
|
+
const minY = fh / 2 / dielineHeight;
|
|
1962
|
+
const maxY = 1 - minY;
|
|
1963
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
1964
|
+
}
|
|
1965
|
+
break;
|
|
1966
|
+
case "right":
|
|
1967
|
+
newX = 1 - offset / dielineWidth;
|
|
1968
|
+
if (confine) {
|
|
1969
|
+
const minY = fh / 2 / dielineHeight;
|
|
1970
|
+
const maxY = 1 - minY;
|
|
1971
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
1972
|
+
}
|
|
1973
|
+
break;
|
|
1974
|
+
}
|
|
1975
|
+
return { x: newX, y: newY };
|
|
1976
|
+
};
|
|
1977
|
+
var internalConstraint = (x, y, feature, context) => {
|
|
1978
|
+
var _a;
|
|
1979
|
+
const { dielineWidth, dielineHeight } = context;
|
|
1980
|
+
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1981
|
+
const margin = params.margin || 0;
|
|
1982
|
+
const fw = feature.width || 0;
|
|
1983
|
+
const fh = feature.height || 0;
|
|
1984
|
+
const minX = (margin + fw / 2) / dielineWidth;
|
|
1985
|
+
const maxX = 1 - (margin + fw / 2) / dielineWidth;
|
|
1986
|
+
const minY = (margin + fh / 2) / dielineHeight;
|
|
1987
|
+
const maxY = 1 - (margin + fh / 2) / dielineHeight;
|
|
1988
|
+
const clampedX = minX > maxX ? 0.5 : Math.max(minX, Math.min(x, maxX));
|
|
1989
|
+
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
1990
|
+
return { x: clampedX, y: clampedY };
|
|
1991
|
+
};
|
|
1992
|
+
var tangentBottomConstraint = (x, y, feature, context) => {
|
|
1993
|
+
var _a;
|
|
1994
|
+
const { dielineWidth, dielineHeight } = context;
|
|
1995
|
+
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1996
|
+
const gap = params.gap || 0;
|
|
1997
|
+
const confineX = params.confineX !== false;
|
|
1998
|
+
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
1999
|
+
const newY = 1 + (extentY + gap) / dielineHeight;
|
|
2000
|
+
let newX = x;
|
|
2001
|
+
if (confineX) {
|
|
2002
|
+
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
2003
|
+
const minX = extentX / dielineWidth;
|
|
2004
|
+
const maxX = 1 - extentX / dielineWidth;
|
|
2005
|
+
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
2006
|
+
}
|
|
2007
|
+
return { x: newX, y: newY };
|
|
2008
|
+
};
|
|
2009
|
+
ConstraintRegistry.register("edge", edgeConstraint);
|
|
2010
|
+
ConstraintRegistry.register("internal", internalConstraint);
|
|
2011
|
+
ConstraintRegistry.register("tangent-bottom", tangentBottomConstraint);
|
|
2012
|
+
|
|
2013
|
+
// src/featureComplete.ts
|
|
2014
|
+
function validateFeaturesStrict(features, context) {
|
|
2015
|
+
var _a;
|
|
2016
|
+
const eps = 1e-6;
|
|
2017
|
+
const issues = [];
|
|
2018
|
+
for (const f of features) {
|
|
2019
|
+
if (!((_a = f.constraints) == null ? void 0 : _a.type)) continue;
|
|
2020
|
+
const constrained = ConstraintRegistry.apply(f.x, f.y, f, context);
|
|
2021
|
+
if (Math.abs(constrained.x - f.x) > eps || Math.abs(constrained.y - f.y) > eps) {
|
|
2022
|
+
issues.push({
|
|
2023
|
+
featureId: f.id,
|
|
2024
|
+
groupId: f.groupId,
|
|
2025
|
+
reason: "Position violates constraint strategy"
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
return { ok: issues.length === 0, issues: issues.length ? issues : void 0 };
|
|
2030
|
+
}
|
|
2031
|
+
function completeFeaturesStrict(features, context, update) {
|
|
2032
|
+
const validation = validateFeaturesStrict(features, context);
|
|
2033
|
+
if (!validation.ok) return validation;
|
|
2034
|
+
const next = JSON.parse(JSON.stringify(features || []));
|
|
2035
|
+
update(next);
|
|
2036
|
+
return { ok: true };
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
// src/feature.ts
|
|
1934
2040
|
var FeatureTool = class {
|
|
1935
2041
|
constructor(options) {
|
|
1936
2042
|
this.id = "pooder.kit.feature";
|
|
1937
2043
|
this.metadata = {
|
|
1938
2044
|
name: "FeatureTool"
|
|
1939
2045
|
};
|
|
1940
|
-
this.
|
|
2046
|
+
this.workingFeatures = [];
|
|
1941
2047
|
this.isUpdatingConfig = false;
|
|
1942
2048
|
this.isToolActive = false;
|
|
1943
2049
|
this.handleMoving = null;
|
|
@@ -1963,12 +2069,15 @@ var FeatureTool = class {
|
|
|
1963
2069
|
"ConfigurationService"
|
|
1964
2070
|
);
|
|
1965
2071
|
if (configService) {
|
|
1966
|
-
|
|
2072
|
+
const features = configService.get("dieline.features", []) || [];
|
|
2073
|
+
this.workingFeatures = this.cloneFeatures(features);
|
|
1967
2074
|
configService.onAnyChange((e) => {
|
|
1968
2075
|
if (this.isUpdatingConfig) return;
|
|
1969
2076
|
if (e.key === "dieline.features") {
|
|
1970
|
-
|
|
2077
|
+
const next = e.value || [];
|
|
2078
|
+
this.workingFeatures = this.cloneFeatures(next);
|
|
1971
2079
|
this.redraw();
|
|
2080
|
+
this.emitWorkingChange();
|
|
1972
2081
|
}
|
|
1973
2082
|
});
|
|
1974
2083
|
}
|
|
@@ -2026,27 +2135,151 @@ var FeatureTool = class {
|
|
|
2026
2135
|
command: "clearFeatures",
|
|
2027
2136
|
title: "Clear Features",
|
|
2028
2137
|
handler: () => {
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
);
|
|
2033
|
-
if (configService) {
|
|
2034
|
-
configService.update("dieline.features", []);
|
|
2035
|
-
}
|
|
2138
|
+
this.setWorkingFeatures([]);
|
|
2139
|
+
this.redraw();
|
|
2140
|
+
this.emitWorkingChange();
|
|
2036
2141
|
return true;
|
|
2037
2142
|
}
|
|
2143
|
+
},
|
|
2144
|
+
{
|
|
2145
|
+
command: "getWorkingFeatures",
|
|
2146
|
+
title: "Get Working Features",
|
|
2147
|
+
handler: () => {
|
|
2148
|
+
return this.cloneFeatures(this.workingFeatures);
|
|
2149
|
+
}
|
|
2150
|
+
},
|
|
2151
|
+
{
|
|
2152
|
+
command: "setWorkingFeatures",
|
|
2153
|
+
title: "Set Working Features",
|
|
2154
|
+
handler: async (features) => {
|
|
2155
|
+
await this.refreshGeometry();
|
|
2156
|
+
this.setWorkingFeatures(this.cloneFeatures(features || []));
|
|
2157
|
+
this.redraw();
|
|
2158
|
+
this.emitWorkingChange();
|
|
2159
|
+
return { ok: true };
|
|
2160
|
+
}
|
|
2161
|
+
},
|
|
2162
|
+
{
|
|
2163
|
+
command: "updateWorkingGroupPosition",
|
|
2164
|
+
title: "Update Working Group Position",
|
|
2165
|
+
handler: (groupId, x, y) => {
|
|
2166
|
+
return this.updateWorkingGroupPosition(groupId, x, y);
|
|
2167
|
+
}
|
|
2168
|
+
},
|
|
2169
|
+
{
|
|
2170
|
+
command: "completeFeatures",
|
|
2171
|
+
title: "Complete Features",
|
|
2172
|
+
handler: () => {
|
|
2173
|
+
return this.completeFeatures();
|
|
2174
|
+
}
|
|
2038
2175
|
}
|
|
2039
2176
|
]
|
|
2040
2177
|
};
|
|
2041
2178
|
}
|
|
2042
|
-
|
|
2179
|
+
cloneFeatures(features) {
|
|
2180
|
+
return JSON.parse(JSON.stringify(features || []));
|
|
2181
|
+
}
|
|
2182
|
+
emitWorkingChange() {
|
|
2043
2183
|
var _a;
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2184
|
+
(_a = this.context) == null ? void 0 : _a.eventBus.emit("feature:working:change", {
|
|
2185
|
+
features: this.cloneFeatures(this.workingFeatures)
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
async refreshGeometry() {
|
|
2189
|
+
if (!this.context) return;
|
|
2190
|
+
const commandService = this.context.services.get("CommandService");
|
|
2191
|
+
if (!commandService) return;
|
|
2192
|
+
try {
|
|
2193
|
+
const g = await Promise.resolve(commandService.executeCommand("getGeometry"));
|
|
2194
|
+
if (g) this.currentGeometry = g;
|
|
2195
|
+
} catch (e) {
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
setWorkingFeatures(next) {
|
|
2199
|
+
this.workingFeatures = next;
|
|
2200
|
+
}
|
|
2201
|
+
updateWorkingGroupPosition(groupId, x, y) {
|
|
2202
|
+
var _a, _b, _c;
|
|
2203
|
+
if (!groupId) return { ok: false };
|
|
2204
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
2205
|
+
if (!configService) return { ok: false };
|
|
2206
|
+
const dielineWidth = parseLengthToMm(
|
|
2207
|
+
(_b = configService.get("dieline.width")) != null ? _b : 500,
|
|
2208
|
+
"mm"
|
|
2209
|
+
);
|
|
2210
|
+
const dielineHeight = parseLengthToMm(
|
|
2211
|
+
(_c = configService.get("dieline.height")) != null ? _c : 500,
|
|
2212
|
+
"mm"
|
|
2213
|
+
);
|
|
2214
|
+
let changed = false;
|
|
2215
|
+
const next = this.workingFeatures.map((f) => {
|
|
2216
|
+
if (f.groupId !== groupId) return f;
|
|
2217
|
+
let nx = x;
|
|
2218
|
+
let ny = y;
|
|
2219
|
+
if (f.constraints && dielineWidth > 0 && dielineHeight > 0) {
|
|
2220
|
+
const constrained = ConstraintRegistry.apply(nx, ny, f, {
|
|
2221
|
+
dielineWidth,
|
|
2222
|
+
dielineHeight
|
|
2223
|
+
});
|
|
2224
|
+
nx = constrained.x;
|
|
2225
|
+
ny = constrained.y;
|
|
2226
|
+
}
|
|
2227
|
+
if (f.x !== nx || f.y !== ny) {
|
|
2228
|
+
changed = true;
|
|
2229
|
+
return { ...f, x: nx, y: ny };
|
|
2230
|
+
}
|
|
2231
|
+
return f;
|
|
2232
|
+
});
|
|
2233
|
+
if (!changed) return { ok: true };
|
|
2234
|
+
this.setWorkingFeatures(next);
|
|
2235
|
+
this.redraw();
|
|
2236
|
+
this.enforceConstraints();
|
|
2237
|
+
this.emitWorkingChange();
|
|
2238
|
+
return { ok: true };
|
|
2239
|
+
}
|
|
2240
|
+
completeFeatures() {
|
|
2241
|
+
var _a, _b, _c;
|
|
2242
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
2243
|
+
if (!configService) {
|
|
2244
|
+
return {
|
|
2245
|
+
ok: false,
|
|
2246
|
+
issues: [
|
|
2247
|
+
{ featureId: "unknown", reason: "ConfigurationService not found" }
|
|
2248
|
+
]
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
const dielineWidth = parseLengthToMm(
|
|
2252
|
+
(_b = configService.get("dieline.width")) != null ? _b : 500,
|
|
2253
|
+
"mm"
|
|
2254
|
+
);
|
|
2255
|
+
const dielineHeight = parseLengthToMm(
|
|
2256
|
+
(_c = configService.get("dieline.height")) != null ? _c : 500,
|
|
2257
|
+
"mm"
|
|
2258
|
+
);
|
|
2259
|
+
const result = completeFeaturesStrict(
|
|
2260
|
+
this.workingFeatures,
|
|
2261
|
+
{ dielineWidth, dielineHeight },
|
|
2262
|
+
(next) => {
|
|
2263
|
+
this.isUpdatingConfig = true;
|
|
2264
|
+
try {
|
|
2265
|
+
configService.update("dieline.features", next);
|
|
2266
|
+
} finally {
|
|
2267
|
+
this.isUpdatingConfig = false;
|
|
2268
|
+
}
|
|
2269
|
+
this.workingFeatures = this.cloneFeatures(next);
|
|
2270
|
+
this.emitWorkingChange();
|
|
2271
|
+
}
|
|
2047
2272
|
);
|
|
2048
|
-
|
|
2049
|
-
|
|
2273
|
+
if (!result.ok) {
|
|
2274
|
+
return {
|
|
2275
|
+
ok: false,
|
|
2276
|
+
issues: result.issues
|
|
2277
|
+
};
|
|
2278
|
+
}
|
|
2279
|
+
return { ok: true };
|
|
2280
|
+
}
|
|
2281
|
+
addFeature(type) {
|
|
2282
|
+
if (!this.canvasService) return false;
|
|
2050
2283
|
const newFeature = {
|
|
2051
2284
|
id: Date.now().toString(),
|
|
2052
2285
|
operation: type,
|
|
@@ -2055,28 +2288,17 @@ var FeatureTool = class {
|
|
|
2055
2288
|
x: 0.5,
|
|
2056
2289
|
y: 0,
|
|
2057
2290
|
// Top edge
|
|
2058
|
-
width:
|
|
2059
|
-
height:
|
|
2291
|
+
width: 10,
|
|
2292
|
+
height: 10,
|
|
2060
2293
|
rotation: 0
|
|
2061
2294
|
};
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
[]
|
|
2066
|
-
);
|
|
2067
|
-
configService.update("dieline.features", [...current, newFeature]);
|
|
2068
|
-
}
|
|
2295
|
+
this.setWorkingFeatures([...this.workingFeatures || [], newFeature]);
|
|
2296
|
+
this.redraw();
|
|
2297
|
+
this.emitWorkingChange();
|
|
2069
2298
|
return true;
|
|
2070
2299
|
}
|
|
2071
2300
|
addDoubleLayerHole() {
|
|
2072
|
-
var _a;
|
|
2073
2301
|
if (!this.canvasService) return false;
|
|
2074
|
-
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
2075
|
-
"ConfigurationService"
|
|
2076
|
-
);
|
|
2077
|
-
const unit = (configService == null ? void 0 : configService.get("dieline.unit", "mm")) || "mm";
|
|
2078
|
-
const lugRadius = Coordinate.convertUnit(20, "mm", unit);
|
|
2079
|
-
const holeRadius = Coordinate.convertUnit(15, "mm", unit);
|
|
2080
2302
|
const groupId = Date.now().toString();
|
|
2081
2303
|
const timestamp = Date.now();
|
|
2082
2304
|
const lug = {
|
|
@@ -2087,8 +2309,7 @@ var FeatureTool = class {
|
|
|
2087
2309
|
placement: "edge",
|
|
2088
2310
|
x: 0.5,
|
|
2089
2311
|
y: 0,
|
|
2090
|
-
radius:
|
|
2091
|
-
// 20mm
|
|
2312
|
+
radius: 20,
|
|
2092
2313
|
rotation: 0
|
|
2093
2314
|
};
|
|
2094
2315
|
const hole = {
|
|
@@ -2099,17 +2320,12 @@ var FeatureTool = class {
|
|
|
2099
2320
|
placement: "edge",
|
|
2100
2321
|
x: 0.5,
|
|
2101
2322
|
y: 0,
|
|
2102
|
-
radius:
|
|
2103
|
-
// 15mm
|
|
2323
|
+
radius: 15,
|
|
2104
2324
|
rotation: 0
|
|
2105
2325
|
};
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
[]
|
|
2110
|
-
);
|
|
2111
|
-
configService.update("dieline.features", [...current, lug, hole]);
|
|
2112
|
-
}
|
|
2326
|
+
this.setWorkingFeatures([...this.workingFeatures || [], lug, hole]);
|
|
2327
|
+
this.redraw();
|
|
2328
|
+
this.emitWorkingChange();
|
|
2113
2329
|
return true;
|
|
2114
2330
|
}
|
|
2115
2331
|
getGeometryForFeature(geometry, feature) {
|
|
@@ -2153,12 +2369,12 @@ var FeatureTool = class {
|
|
|
2153
2369
|
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
2154
2370
|
const indices = (_c = target.data) == null ? void 0 : _c.indices;
|
|
2155
2371
|
if (indices && indices.length > 0) {
|
|
2156
|
-
feature = this.
|
|
2372
|
+
feature = this.workingFeatures[indices[0]];
|
|
2157
2373
|
}
|
|
2158
2374
|
} else {
|
|
2159
2375
|
const index = (_d = target.data) == null ? void 0 : _d.index;
|
|
2160
2376
|
if (index !== void 0) {
|
|
2161
|
-
feature = this.
|
|
2377
|
+
feature = this.workingFeatures[index];
|
|
2162
2378
|
}
|
|
2163
2379
|
}
|
|
2164
2380
|
const geometry = this.getGeometryForFeature(
|
|
@@ -2179,7 +2395,7 @@ var FeatureTool = class {
|
|
|
2179
2395
|
}
|
|
2180
2396
|
if (!this.handleModified) {
|
|
2181
2397
|
this.handleModified = (e) => {
|
|
2182
|
-
var _a, _b, _c
|
|
2398
|
+
var _a, _b, _c;
|
|
2183
2399
|
const target = e.target;
|
|
2184
2400
|
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "feature-marker") return;
|
|
2185
2401
|
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
@@ -2187,11 +2403,11 @@ var FeatureTool = class {
|
|
|
2187
2403
|
const indices = (_c = groupObj.data) == null ? void 0 : _c.indices;
|
|
2188
2404
|
if (!indices) return;
|
|
2189
2405
|
const groupCenter = new import_fabric4.Point(groupObj.left, groupObj.top);
|
|
2190
|
-
const newFeatures = [...this.
|
|
2406
|
+
const newFeatures = [...this.workingFeatures];
|
|
2191
2407
|
const { x, y } = this.currentGeometry;
|
|
2192
2408
|
groupObj.getObjects().forEach((child, i) => {
|
|
2193
2409
|
const originalIndex = indices[i];
|
|
2194
|
-
const feature = this.
|
|
2410
|
+
const feature = this.workingFeatures[originalIndex];
|
|
2195
2411
|
const geometry = this.getGeometryForFeature(
|
|
2196
2412
|
this.currentGeometry,
|
|
2197
2413
|
feature
|
|
@@ -2209,18 +2425,8 @@ var FeatureTool = class {
|
|
|
2209
2425
|
y: normalizedY
|
|
2210
2426
|
};
|
|
2211
2427
|
});
|
|
2212
|
-
this.
|
|
2213
|
-
|
|
2214
|
-
"ConfigurationService"
|
|
2215
|
-
);
|
|
2216
|
-
if (configService) {
|
|
2217
|
-
this.isUpdatingConfig = true;
|
|
2218
|
-
try {
|
|
2219
|
-
configService.update("dieline.features", this.features);
|
|
2220
|
-
} finally {
|
|
2221
|
-
this.isUpdatingConfig = false;
|
|
2222
|
-
}
|
|
2223
|
-
}
|
|
2428
|
+
this.setWorkingFeatures(newFeatures);
|
|
2429
|
+
this.emitWorkingChange();
|
|
2224
2430
|
} else {
|
|
2225
2431
|
this.syncFeatureFromCanvas(target);
|
|
2226
2432
|
}
|
|
@@ -2281,10 +2487,13 @@ var FeatureTool = class {
|
|
|
2281
2487
|
y: Math.max(minY, Math.min(maxY, p.y))
|
|
2282
2488
|
};
|
|
2283
2489
|
}
|
|
2284
|
-
const nearest = getNearestPointOnDieline(
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2490
|
+
const nearest = getNearestPointOnDieline(
|
|
2491
|
+
{ x: p.x, y: p.y },
|
|
2492
|
+
{
|
|
2493
|
+
...geometry,
|
|
2494
|
+
features: []
|
|
2495
|
+
}
|
|
2496
|
+
);
|
|
2288
2497
|
const dx = p.x - nearest.x;
|
|
2289
2498
|
const dy = p.y - nearest.y;
|
|
2290
2499
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
@@ -2301,9 +2510,9 @@ var FeatureTool = class {
|
|
|
2301
2510
|
var _a;
|
|
2302
2511
|
if (!this.currentGeometry || !this.context) return;
|
|
2303
2512
|
const index = (_a = target.data) == null ? void 0 : _a.index;
|
|
2304
|
-
if (index === void 0 || index < 0 || index >= this.
|
|
2513
|
+
if (index === void 0 || index < 0 || index >= this.workingFeatures.length)
|
|
2305
2514
|
return;
|
|
2306
|
-
const feature = this.
|
|
2515
|
+
const feature = this.workingFeatures[index];
|
|
2307
2516
|
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
2308
2517
|
const { width, height, x, y } = geometry;
|
|
2309
2518
|
const left = x - width / 2;
|
|
@@ -2316,20 +2525,10 @@ var FeatureTool = class {
|
|
|
2316
2525
|
y: normalizedY
|
|
2317
2526
|
// Could also update rotation if we allowed rotating markers
|
|
2318
2527
|
};
|
|
2319
|
-
const newFeatures = [...this.
|
|
2528
|
+
const newFeatures = [...this.workingFeatures];
|
|
2320
2529
|
newFeatures[index] = updatedFeature;
|
|
2321
|
-
this.
|
|
2322
|
-
|
|
2323
|
-
"ConfigurationService"
|
|
2324
|
-
);
|
|
2325
|
-
if (configService) {
|
|
2326
|
-
this.isUpdatingConfig = true;
|
|
2327
|
-
try {
|
|
2328
|
-
configService.update("dieline.features", this.features);
|
|
2329
|
-
} finally {
|
|
2330
|
-
this.isUpdatingConfig = false;
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2530
|
+
this.setWorkingFeatures(newFeatures);
|
|
2531
|
+
this.emitWorkingChange();
|
|
2333
2532
|
}
|
|
2334
2533
|
redraw() {
|
|
2335
2534
|
if (!this.canvasService || !this.currentGeometry) return;
|
|
@@ -2340,7 +2539,7 @@ var FeatureTool = class {
|
|
|
2340
2539
|
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
2341
2540
|
});
|
|
2342
2541
|
existing.forEach((obj) => canvas.remove(obj));
|
|
2343
|
-
if (!this.
|
|
2542
|
+
if (!this.workingFeatures || this.workingFeatures.length === 0) {
|
|
2344
2543
|
this.canvasService.requestRenderAll();
|
|
2345
2544
|
return;
|
|
2346
2545
|
}
|
|
@@ -2348,7 +2547,7 @@ var FeatureTool = class {
|
|
|
2348
2547
|
const finalScale = scale;
|
|
2349
2548
|
const groups = {};
|
|
2350
2549
|
const singles = [];
|
|
2351
|
-
this.
|
|
2550
|
+
this.workingFeatures.forEach((f, i) => {
|
|
2352
2551
|
if (f.groupId) {
|
|
2353
2552
|
if (!groups[f.groupId]) groups[f.groupId] = [];
|
|
2354
2553
|
groups[f.groupId].push({ feature: f, index: i });
|
|
@@ -2416,25 +2615,6 @@ var FeatureTool = class {
|
|
|
2416
2615
|
lockScalingY: true,
|
|
2417
2616
|
data: { type: "feature-marker", index, isGroup: false }
|
|
2418
2617
|
});
|
|
2419
|
-
marker.set("opacity", 0);
|
|
2420
|
-
marker.on("mouseover", () => {
|
|
2421
|
-
marker.set("opacity", 1);
|
|
2422
|
-
canvas.requestRenderAll();
|
|
2423
|
-
});
|
|
2424
|
-
marker.on("mouseout", () => {
|
|
2425
|
-
if (canvas.getActiveObject() !== marker) {
|
|
2426
|
-
marker.set("opacity", 0);
|
|
2427
|
-
canvas.requestRenderAll();
|
|
2428
|
-
}
|
|
2429
|
-
});
|
|
2430
|
-
marker.on("selected", () => {
|
|
2431
|
-
marker.set("opacity", 1);
|
|
2432
|
-
canvas.requestRenderAll();
|
|
2433
|
-
});
|
|
2434
|
-
marker.on("deselected", () => {
|
|
2435
|
-
marker.set("opacity", 0);
|
|
2436
|
-
canvas.requestRenderAll();
|
|
2437
|
-
});
|
|
2438
2618
|
canvas.add(marker);
|
|
2439
2619
|
canvas.bringObjectToFront(marker);
|
|
2440
2620
|
});
|
|
@@ -2471,25 +2651,6 @@ var FeatureTool = class {
|
|
|
2471
2651
|
indices: members.map((m) => m.index)
|
|
2472
2652
|
}
|
|
2473
2653
|
});
|
|
2474
|
-
groupObj.set("opacity", 0);
|
|
2475
|
-
groupObj.on("mouseover", () => {
|
|
2476
|
-
groupObj.set("opacity", 1);
|
|
2477
|
-
canvas.requestRenderAll();
|
|
2478
|
-
});
|
|
2479
|
-
groupObj.on("mouseout", () => {
|
|
2480
|
-
if (canvas.getActiveObject() !== groupObj) {
|
|
2481
|
-
groupObj.set("opacity", 0);
|
|
2482
|
-
canvas.requestRenderAll();
|
|
2483
|
-
}
|
|
2484
|
-
});
|
|
2485
|
-
groupObj.on("selected", () => {
|
|
2486
|
-
groupObj.set("opacity", 1);
|
|
2487
|
-
canvas.requestRenderAll();
|
|
2488
|
-
});
|
|
2489
|
-
groupObj.on("deselected", () => {
|
|
2490
|
-
groupObj.set("opacity", 0);
|
|
2491
|
-
canvas.requestRenderAll();
|
|
2492
|
-
});
|
|
2493
2654
|
canvas.add(groupObj);
|
|
2494
2655
|
canvas.bringObjectToFront(groupObj);
|
|
2495
2656
|
});
|
|
@@ -2508,12 +2669,12 @@ var FeatureTool = class {
|
|
|
2508
2669
|
if ((_a = marker.data) == null ? void 0 : _a.isGroup) {
|
|
2509
2670
|
const indices = (_b = marker.data) == null ? void 0 : _b.indices;
|
|
2510
2671
|
if (indices && indices.length > 0) {
|
|
2511
|
-
feature = this.
|
|
2672
|
+
feature = this.workingFeatures[indices[0]];
|
|
2512
2673
|
}
|
|
2513
2674
|
} else {
|
|
2514
2675
|
const index = (_c = marker.data) == null ? void 0 : _c.index;
|
|
2515
2676
|
if (index !== void 0) {
|
|
2516
|
-
feature = this.
|
|
2677
|
+
feature = this.workingFeatures[index];
|
|
2517
2678
|
}
|
|
2518
2679
|
}
|
|
2519
2680
|
const geometry = this.getGeometryForFeature(
|
|
@@ -3237,7 +3398,7 @@ var RulerTool = class {
|
|
|
3237
3398
|
// Dieline context for sync
|
|
3238
3399
|
this.dielineWidth = 500;
|
|
3239
3400
|
this.dielineHeight = 500;
|
|
3240
|
-
this.
|
|
3401
|
+
this.dielineDisplayUnit = "mm";
|
|
3241
3402
|
this.dielinePadding = 40;
|
|
3242
3403
|
this.dielineOffset = 0;
|
|
3243
3404
|
if (options) {
|
|
@@ -3261,7 +3422,10 @@ var RulerTool = class {
|
|
|
3261
3422
|
this.textColor = configService.get("ruler.textColor", this.textColor);
|
|
3262
3423
|
this.lineColor = configService.get("ruler.lineColor", this.lineColor);
|
|
3263
3424
|
this.fontSize = configService.get("ruler.fontSize", this.fontSize);
|
|
3264
|
-
this.
|
|
3425
|
+
this.dielineDisplayUnit = configService.get(
|
|
3426
|
+
"dieline.displayUnit",
|
|
3427
|
+
this.dielineDisplayUnit
|
|
3428
|
+
);
|
|
3265
3429
|
this.dielineWidth = configService.get("dieline.width", this.dielineWidth);
|
|
3266
3430
|
this.dielineHeight = configService.get(
|
|
3267
3431
|
"dieline.height",
|
|
@@ -3284,7 +3448,8 @@ var RulerTool = class {
|
|
|
3284
3448
|
shouldUpdate = true;
|
|
3285
3449
|
}
|
|
3286
3450
|
} else if (e.key.startsWith("dieline.")) {
|
|
3287
|
-
if (e.key === "dieline.
|
|
3451
|
+
if (e.key === "dieline.displayUnit")
|
|
3452
|
+
this.dielineDisplayUnit = e.value;
|
|
3288
3453
|
if (e.key === "dieline.width") this.dielineWidth = e.value;
|
|
3289
3454
|
if (e.key === "dieline.height") this.dielineHeight = e.value;
|
|
3290
3455
|
if (e.key === "dieline.padding") this.dielinePadding = e.value;
|
|
@@ -3471,26 +3636,27 @@ var RulerTool = class {
|
|
|
3471
3636
|
const width = this.canvasService.canvas.width || 800;
|
|
3472
3637
|
const height = this.canvasService.canvas.height || 600;
|
|
3473
3638
|
const paddingPx = this.resolvePadding(width, height);
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3639
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
3640
|
+
this.canvasService.viewport.updatePhysical(
|
|
3641
|
+
this.dielineWidth,
|
|
3642
|
+
this.dielineHeight
|
|
3478
3643
|
);
|
|
3644
|
+
const layout = this.canvasService.viewport.layout;
|
|
3479
3645
|
const scale = layout.scale;
|
|
3480
3646
|
const offsetX = layout.offsetX;
|
|
3481
3647
|
const offsetY = layout.offsetY;
|
|
3482
3648
|
const visualWidth = layout.width;
|
|
3483
3649
|
const visualHeight = layout.height;
|
|
3484
|
-
const
|
|
3485
|
-
const
|
|
3486
|
-
const expandPixels =
|
|
3650
|
+
const rawOffsetMm = this.dielineOffset || 0;
|
|
3651
|
+
const effectiveOffsetMm = rawOffsetMm > 0 ? rawOffsetMm : 0;
|
|
3652
|
+
const expandPixels = effectiveOffsetMm * scale;
|
|
3487
3653
|
const gap = this.gap || 15;
|
|
3488
3654
|
const rulerLeft = offsetX - expandPixels;
|
|
3489
3655
|
const rulerTop = offsetY - expandPixels;
|
|
3490
3656
|
const rulerRight = offsetX + visualWidth + expandPixels;
|
|
3491
3657
|
const rulerBottom = offsetY + visualHeight + expandPixels;
|
|
3492
|
-
const
|
|
3493
|
-
const
|
|
3658
|
+
const displayWidthMm = this.dielineWidth + effectiveOffsetMm * 2;
|
|
3659
|
+
const displayHeightMm = this.dielineHeight + effectiveOffsetMm * 2;
|
|
3494
3660
|
const topRulerY = rulerTop - gap;
|
|
3495
3661
|
const topRulerXStart = rulerLeft;
|
|
3496
3662
|
const topRulerXEnd = rulerRight;
|
|
@@ -3533,8 +3699,8 @@ var RulerTool = class {
|
|
|
3533
3699
|
}
|
|
3534
3700
|
)
|
|
3535
3701
|
);
|
|
3536
|
-
const widthStr =
|
|
3537
|
-
const topTextContent = `${widthStr} ${this.
|
|
3702
|
+
const widthStr = formatMm(displayWidthMm, this.dielineDisplayUnit);
|
|
3703
|
+
const topTextContent = `${widthStr} ${this.dielineDisplayUnit}`;
|
|
3538
3704
|
const topText = new import_fabric7.Text(topTextContent, {
|
|
3539
3705
|
left: topRulerXStart + (rulerRight - rulerLeft) / 2,
|
|
3540
3706
|
top: topRulerY,
|
|
@@ -3589,8 +3755,8 @@ var RulerTool = class {
|
|
|
3589
3755
|
}
|
|
3590
3756
|
)
|
|
3591
3757
|
);
|
|
3592
|
-
const heightStr =
|
|
3593
|
-
const leftTextContent = `${heightStr} ${this.
|
|
3758
|
+
const heightStr = formatMm(displayHeightMm, this.dielineDisplayUnit);
|
|
3759
|
+
const leftTextContent = `${heightStr} ${this.dielineDisplayUnit}`;
|
|
3594
3760
|
const leftText = new import_fabric7.Text(leftTextContent, {
|
|
3595
3761
|
left: leftRulerX,
|
|
3596
3762
|
top: leftRulerYStart + (rulerBottom - rulerTop) / 2,
|
|
@@ -3702,6 +3868,81 @@ var MirrorTool = class {
|
|
|
3702
3868
|
|
|
3703
3869
|
// src/CanvasService.ts
|
|
3704
3870
|
var import_fabric8 = require("fabric");
|
|
3871
|
+
|
|
3872
|
+
// src/ViewportSystem.ts
|
|
3873
|
+
var ViewportSystem = class {
|
|
3874
|
+
constructor(containerSize = { width: 0, height: 0 }, physicalSize = { width: 0, height: 0 }, padding = 40) {
|
|
3875
|
+
this._containerSize = { width: 0, height: 0 };
|
|
3876
|
+
this._physicalSize = { width: 0, height: 0 };
|
|
3877
|
+
this._padding = 0;
|
|
3878
|
+
this._layout = {
|
|
3879
|
+
scale: 1,
|
|
3880
|
+
offsetX: 0,
|
|
3881
|
+
offsetY: 0,
|
|
3882
|
+
width: 0,
|
|
3883
|
+
height: 0
|
|
3884
|
+
};
|
|
3885
|
+
this._containerSize = containerSize;
|
|
3886
|
+
this._physicalSize = physicalSize;
|
|
3887
|
+
this._padding = padding;
|
|
3888
|
+
this.updateLayout();
|
|
3889
|
+
}
|
|
3890
|
+
get layout() {
|
|
3891
|
+
return this._layout;
|
|
3892
|
+
}
|
|
3893
|
+
get scale() {
|
|
3894
|
+
return this._layout.scale;
|
|
3895
|
+
}
|
|
3896
|
+
get offset() {
|
|
3897
|
+
return { x: this._layout.offsetX, y: this._layout.offsetY };
|
|
3898
|
+
}
|
|
3899
|
+
updateContainer(width, height) {
|
|
3900
|
+
if (this._containerSize.width === width && this._containerSize.height === height)
|
|
3901
|
+
return;
|
|
3902
|
+
this._containerSize = { width, height };
|
|
3903
|
+
this.updateLayout();
|
|
3904
|
+
}
|
|
3905
|
+
updatePhysical(width, height) {
|
|
3906
|
+
if (this._physicalSize.width === width && this._physicalSize.height === height)
|
|
3907
|
+
return;
|
|
3908
|
+
this._physicalSize = { width, height };
|
|
3909
|
+
this.updateLayout();
|
|
3910
|
+
}
|
|
3911
|
+
setPadding(padding) {
|
|
3912
|
+
if (this._padding === padding) return;
|
|
3913
|
+
this._padding = padding;
|
|
3914
|
+
this.updateLayout();
|
|
3915
|
+
}
|
|
3916
|
+
updateLayout() {
|
|
3917
|
+
this._layout = Coordinate.calculateLayout(
|
|
3918
|
+
this._containerSize,
|
|
3919
|
+
this._physicalSize,
|
|
3920
|
+
this._padding
|
|
3921
|
+
);
|
|
3922
|
+
}
|
|
3923
|
+
toPixel(value) {
|
|
3924
|
+
return value * this._layout.scale;
|
|
3925
|
+
}
|
|
3926
|
+
toPhysical(value) {
|
|
3927
|
+
return this._layout.scale === 0 ? 0 : value / this._layout.scale;
|
|
3928
|
+
}
|
|
3929
|
+
toPixelPoint(point) {
|
|
3930
|
+
return {
|
|
3931
|
+
x: point.x * this._layout.scale + this._layout.offsetX,
|
|
3932
|
+
y: point.y * this._layout.scale + this._layout.offsetY
|
|
3933
|
+
};
|
|
3934
|
+
}
|
|
3935
|
+
// Convert screen coordinate (e.g. mouse event) to physical coordinate (relative to content origin)
|
|
3936
|
+
toPhysicalPoint(point) {
|
|
3937
|
+
if (this._layout.scale === 0) return { x: 0, y: 0 };
|
|
3938
|
+
return {
|
|
3939
|
+
x: (point.x - this._layout.offsetX) / this._layout.scale,
|
|
3940
|
+
y: (point.y - this._layout.offsetY) / this._layout.scale
|
|
3941
|
+
};
|
|
3942
|
+
}
|
|
3943
|
+
};
|
|
3944
|
+
|
|
3945
|
+
// src/CanvasService.ts
|
|
3705
3946
|
var CanvasService = class {
|
|
3706
3947
|
constructor(el, options) {
|
|
3707
3948
|
if (el instanceof import_fabric8.Canvas) {
|
|
@@ -3712,6 +3953,10 @@ var CanvasService = class {
|
|
|
3712
3953
|
...options
|
|
3713
3954
|
});
|
|
3714
3955
|
}
|
|
3956
|
+
this.viewport = new ViewportSystem();
|
|
3957
|
+
if (this.canvas.width !== void 0 && this.canvas.height !== void 0) {
|
|
3958
|
+
this.viewport.updateContainer(this.canvas.width, this.canvas.height);
|
|
3959
|
+
}
|
|
3715
3960
|
if (options == null ? void 0 : options.eventBus) {
|
|
3716
3961
|
this.setEventBus(options.eventBus);
|
|
3717
3962
|
}
|
|
@@ -3792,5 +4037,7 @@ var CanvasService = class {
|
|
|
3792
4037
|
ImageTool,
|
|
3793
4038
|
MirrorTool,
|
|
3794
4039
|
RulerTool,
|
|
3795
|
-
WhiteInkTool
|
|
4040
|
+
WhiteInkTool,
|
|
4041
|
+
formatMm,
|
|
4042
|
+
parseLengthToMm
|
|
3796
4043
|
});
|