@pooder/kit 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +62 -10
- package/dist/index.d.ts +62 -10
- package/dist/index.js +756 -348
- package/dist/index.mjs +753 -347
- package/package.json +3 -2
- package/src/CanvasService.ts +96 -89
- package/src/ViewportSystem.ts +92 -0
- package/src/background.ts +230 -230
- package/src/constraints.ts +191 -27
- package/src/coordinate.ts +106 -106
- package/src/dieline.ts +955 -871
- package/src/feature.ts +282 -195
- package/src/featureComplete.ts +46 -0
- package/src/film.ts +194 -194
- package/src/geometry.ts +161 -30
- package/src/image.ts +512 -512
- package/src/index.ts +10 -9
- package/src/mirror.ts +128 -128
- package/src/ruler.ts +508 -500
- package/src/tracer.ts +570 -570
- package/src/units.ts +27 -0
- package/src/white-ink.ts +373 -373
- 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) {
|
|
@@ -798,7 +823,7 @@ function getPerimeterShape(options) {
|
|
|
798
823
|
const { features } = options;
|
|
799
824
|
if (features && features.length > 0) {
|
|
800
825
|
const edgeFeatures = features.filter(
|
|
801
|
-
(f) => !f.
|
|
826
|
+
(f) => !f.renderBehavior || f.renderBehavior === "edge"
|
|
802
827
|
);
|
|
803
828
|
const adds = [];
|
|
804
829
|
const subtracts = [];
|
|
@@ -806,10 +831,78 @@ function getPerimeterShape(options) {
|
|
|
806
831
|
const pos = resolveFeaturePosition(f, options);
|
|
807
832
|
const center = new import_paper2.default.Point(pos.x, pos.y);
|
|
808
833
|
const item = createFeatureItem(f, center);
|
|
809
|
-
if (f.
|
|
810
|
-
|
|
834
|
+
if (f.bridge && f.bridge.type === "vertical") {
|
|
835
|
+
const itemBounds = item.bounds;
|
|
836
|
+
const mainBounds = mainShape.bounds;
|
|
837
|
+
const bridgeTop = mainBounds.top;
|
|
838
|
+
const bridgeBottom = itemBounds.top;
|
|
839
|
+
if (bridgeBottom > bridgeTop) {
|
|
840
|
+
const startY = bridgeBottom + 1;
|
|
841
|
+
const bridgeRect = new import_paper2.default.Path.Rectangle({
|
|
842
|
+
from: [itemBounds.left, bridgeTop],
|
|
843
|
+
to: [itemBounds.right, startY],
|
|
844
|
+
insert: false
|
|
845
|
+
});
|
|
846
|
+
const gaps = bridgeRect.subtract(mainShape);
|
|
847
|
+
bridgeRect.remove();
|
|
848
|
+
let bridgePart = null;
|
|
849
|
+
const isBottomPart = (part) => {
|
|
850
|
+
return Math.abs(part.bounds.bottom - startY) < 2;
|
|
851
|
+
};
|
|
852
|
+
if (gaps instanceof import_paper2.default.CompoundPath) {
|
|
853
|
+
const children = gaps.children;
|
|
854
|
+
let maxBottom = -Infinity;
|
|
855
|
+
let bestChild = null;
|
|
856
|
+
for (const child of children) {
|
|
857
|
+
if (child.bounds.bottom > maxBottom) {
|
|
858
|
+
maxBottom = child.bounds.bottom;
|
|
859
|
+
bestChild = child;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
if (bestChild && isBottomPart(bestChild)) {
|
|
863
|
+
bridgePart = bestChild.clone();
|
|
864
|
+
}
|
|
865
|
+
} else if (gaps instanceof import_paper2.default.Path) {
|
|
866
|
+
if (isBottomPart(gaps)) {
|
|
867
|
+
bridgePart = gaps.clone();
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
gaps.remove();
|
|
871
|
+
if (bridgePart) {
|
|
872
|
+
const bounds = bridgePart.bounds;
|
|
873
|
+
if (bounds.height > 0) {
|
|
874
|
+
const overlap = 1;
|
|
875
|
+
const scaleY = (bounds.height + overlap) / bounds.height;
|
|
876
|
+
bridgePart.scale(1, scaleY, new import_paper2.default.Point(bounds.center.x, bounds.bottom));
|
|
877
|
+
}
|
|
878
|
+
const unitedItem = item.unite(bridgePart);
|
|
879
|
+
item.remove();
|
|
880
|
+
bridgePart.remove();
|
|
881
|
+
if (f.operation === "add") {
|
|
882
|
+
adds.push(unitedItem);
|
|
883
|
+
} else {
|
|
884
|
+
subtracts.push(unitedItem);
|
|
885
|
+
}
|
|
886
|
+
} else {
|
|
887
|
+
if (f.operation === "add") {
|
|
888
|
+
adds.push(item);
|
|
889
|
+
} else {
|
|
890
|
+
subtracts.push(item);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
} else {
|
|
894
|
+
if (f.operation === "add") {
|
|
895
|
+
adds.push(item);
|
|
896
|
+
} else {
|
|
897
|
+
subtracts.push(item);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
811
900
|
} else {
|
|
812
|
-
|
|
901
|
+
if (f.operation === "add") {
|
|
902
|
+
adds.push(item);
|
|
903
|
+
} else {
|
|
904
|
+
subtracts.push(item);
|
|
905
|
+
}
|
|
813
906
|
}
|
|
814
907
|
});
|
|
815
908
|
if (adds.length > 0) {
|
|
@@ -842,10 +935,12 @@ function getPerimeterShape(options) {
|
|
|
842
935
|
return mainShape;
|
|
843
936
|
}
|
|
844
937
|
function applySurfaceFeatures(shape, features, options) {
|
|
845
|
-
const
|
|
846
|
-
|
|
938
|
+
const surfaceFeatures = features.filter(
|
|
939
|
+
(f) => f.renderBehavior === "surface"
|
|
940
|
+
);
|
|
941
|
+
if (surfaceFeatures.length === 0) return shape;
|
|
847
942
|
let result = shape;
|
|
848
|
-
for (const f of
|
|
943
|
+
for (const f of surfaceFeatures) {
|
|
849
944
|
const pos = resolveFeaturePosition(f, options);
|
|
850
945
|
const center = new import_paper2.default.Point(pos.x, pos.y);
|
|
851
946
|
const item = createFeatureItem(f, center);
|
|
@@ -902,9 +997,17 @@ function generateBleedZonePath(originalOptions, offsetOptions, offset) {
|
|
|
902
997
|
ensurePaper(paperWidth, paperHeight);
|
|
903
998
|
import_paper2.default.project.activeLayer.removeChildren();
|
|
904
999
|
const pOriginal = getPerimeterShape(originalOptions);
|
|
905
|
-
const shapeOriginal = applySurfaceFeatures(
|
|
1000
|
+
const shapeOriginal = applySurfaceFeatures(
|
|
1001
|
+
pOriginal,
|
|
1002
|
+
originalOptions.features,
|
|
1003
|
+
originalOptions
|
|
1004
|
+
);
|
|
906
1005
|
const pOffset = getPerimeterShape(offsetOptions);
|
|
907
|
-
const shapeOffset = applySurfaceFeatures(
|
|
1006
|
+
const shapeOffset = applySurfaceFeatures(
|
|
1007
|
+
pOffset,
|
|
1008
|
+
offsetOptions.features,
|
|
1009
|
+
offsetOptions
|
|
1010
|
+
);
|
|
908
1011
|
let bleedZone;
|
|
909
1012
|
if (offset > 0) {
|
|
910
1013
|
bleedZone = shapeOffset.subtract(shapeOriginal);
|
|
@@ -917,13 +1020,29 @@ function generateBleedZonePath(originalOptions, offsetOptions, offset) {
|
|
|
917
1020
|
bleedZone.remove();
|
|
918
1021
|
return pathData;
|
|
919
1022
|
}
|
|
1023
|
+
function getLowestPointOnDieline(options) {
|
|
1024
|
+
ensurePaper(options.width * 2, options.height * 2);
|
|
1025
|
+
import_paper2.default.project.activeLayer.removeChildren();
|
|
1026
|
+
const shape = createBaseShape(options);
|
|
1027
|
+
const bounds = shape.bounds;
|
|
1028
|
+
const result = {
|
|
1029
|
+
x: bounds.center.x,
|
|
1030
|
+
y: bounds.bottom
|
|
1031
|
+
};
|
|
1032
|
+
shape.remove();
|
|
1033
|
+
return result;
|
|
1034
|
+
}
|
|
920
1035
|
function getNearestPointOnDieline(point, options) {
|
|
921
1036
|
ensurePaper(options.width * 2, options.height * 2);
|
|
922
1037
|
import_paper2.default.project.activeLayer.removeChildren();
|
|
923
1038
|
const shape = createBaseShape(options);
|
|
924
1039
|
const p = new import_paper2.default.Point(point.x, point.y);
|
|
925
|
-
const
|
|
926
|
-
const result = {
|
|
1040
|
+
const location = shape.getNearestLocation(p);
|
|
1041
|
+
const result = {
|
|
1042
|
+
x: location.point.x,
|
|
1043
|
+
y: location.point.y,
|
|
1044
|
+
normal: location.normal ? { x: location.normal.x, y: location.normal.y } : void 0
|
|
1045
|
+
};
|
|
927
1046
|
shape.remove();
|
|
928
1047
|
return result;
|
|
929
1048
|
}
|
|
@@ -940,105 +1059,6 @@ function getPathBounds(pathData) {
|
|
|
940
1059
|
};
|
|
941
1060
|
}
|
|
942
1061
|
|
|
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
1062
|
// src/dieline.ts
|
|
1043
1063
|
var DielineTool = class {
|
|
1044
1064
|
constructor(options) {
|
|
@@ -1047,7 +1067,7 @@ var DielineTool = class {
|
|
|
1047
1067
|
name: "DielineTool"
|
|
1048
1068
|
};
|
|
1049
1069
|
this.state = {
|
|
1050
|
-
|
|
1070
|
+
displayUnit: "mm",
|
|
1051
1071
|
shape: "rect",
|
|
1052
1072
|
width: 500,
|
|
1053
1073
|
height: 500,
|
|
@@ -1093,50 +1113,88 @@ var DielineTool = class {
|
|
|
1093
1113
|
const configService = context.services.get("ConfigurationService");
|
|
1094
1114
|
if (configService) {
|
|
1095
1115
|
const s = this.state;
|
|
1096
|
-
s.
|
|
1116
|
+
s.displayUnit = configService.get("dieline.displayUnit", s.displayUnit);
|
|
1097
1117
|
s.shape = configService.get("dieline.shape", s.shape);
|
|
1098
|
-
s.width =
|
|
1099
|
-
|
|
1100
|
-
|
|
1118
|
+
s.width = parseLengthToMm(
|
|
1119
|
+
configService.get("dieline.width", s.width),
|
|
1120
|
+
"mm"
|
|
1121
|
+
);
|
|
1122
|
+
s.height = parseLengthToMm(
|
|
1123
|
+
configService.get("dieline.height", s.height),
|
|
1124
|
+
"mm"
|
|
1125
|
+
);
|
|
1126
|
+
s.radius = parseLengthToMm(
|
|
1127
|
+
configService.get("dieline.radius", s.radius),
|
|
1128
|
+
"mm"
|
|
1129
|
+
);
|
|
1101
1130
|
s.padding = configService.get("dieline.padding", s.padding);
|
|
1102
|
-
s.offset =
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1131
|
+
s.offset = parseLengthToMm(
|
|
1132
|
+
configService.get("dieline.offset", s.offset),
|
|
1133
|
+
"mm"
|
|
1134
|
+
);
|
|
1135
|
+
s.mainLine.width = configService.get(
|
|
1136
|
+
"dieline.strokeWidth",
|
|
1137
|
+
s.mainLine.width
|
|
1138
|
+
);
|
|
1139
|
+
s.mainLine.color = configService.get(
|
|
1140
|
+
"dieline.strokeColor",
|
|
1141
|
+
s.mainLine.color
|
|
1142
|
+
);
|
|
1143
|
+
s.mainLine.dashLength = configService.get(
|
|
1144
|
+
"dieline.dashLength",
|
|
1145
|
+
s.mainLine.dashLength
|
|
1146
|
+
);
|
|
1106
1147
|
s.mainLine.style = configService.get("dieline.style", s.mainLine.style);
|
|
1107
|
-
s.offsetLine.width = configService.get(
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1148
|
+
s.offsetLine.width = configService.get(
|
|
1149
|
+
"dieline.offsetStrokeWidth",
|
|
1150
|
+
s.offsetLine.width
|
|
1151
|
+
);
|
|
1152
|
+
s.offsetLine.color = configService.get(
|
|
1153
|
+
"dieline.offsetStrokeColor",
|
|
1154
|
+
s.offsetLine.color
|
|
1155
|
+
);
|
|
1156
|
+
s.offsetLine.dashLength = configService.get(
|
|
1157
|
+
"dieline.offsetDashLength",
|
|
1158
|
+
s.offsetLine.dashLength
|
|
1159
|
+
);
|
|
1160
|
+
s.offsetLine.style = configService.get(
|
|
1161
|
+
"dieline.offsetStyle",
|
|
1162
|
+
s.offsetLine.style
|
|
1163
|
+
);
|
|
1111
1164
|
s.insideColor = configService.get("dieline.insideColor", s.insideColor);
|
|
1112
|
-
s.outsideColor = configService.get(
|
|
1113
|
-
|
|
1165
|
+
s.outsideColor = configService.get(
|
|
1166
|
+
"dieline.outsideColor",
|
|
1167
|
+
s.outsideColor
|
|
1168
|
+
);
|
|
1169
|
+
s.showBleedLines = configService.get(
|
|
1170
|
+
"dieline.showBleedLines",
|
|
1171
|
+
s.showBleedLines
|
|
1172
|
+
);
|
|
1114
1173
|
s.features = configService.get("dieline.features", s.features);
|
|
1115
1174
|
s.pathData = configService.get("dieline.pathData", s.pathData);
|
|
1116
1175
|
configService.onAnyChange((e) => {
|
|
1117
1176
|
if (e.key.startsWith("dieline.")) {
|
|
1118
|
-
console.log(`[DielineTool] Config change detected: ${e.key} -> ${e.value}`);
|
|
1119
1177
|
switch (e.key) {
|
|
1120
|
-
case "dieline.
|
|
1121
|
-
s.
|
|
1178
|
+
case "dieline.displayUnit":
|
|
1179
|
+
s.displayUnit = e.value;
|
|
1122
1180
|
break;
|
|
1123
1181
|
case "dieline.shape":
|
|
1124
1182
|
s.shape = e.value;
|
|
1125
1183
|
break;
|
|
1126
1184
|
case "dieline.width":
|
|
1127
|
-
s.width = e.value;
|
|
1185
|
+
s.width = parseLengthToMm(e.value, "mm");
|
|
1128
1186
|
break;
|
|
1129
1187
|
case "dieline.height":
|
|
1130
|
-
s.height = e.value;
|
|
1188
|
+
s.height = parseLengthToMm(e.value, "mm");
|
|
1131
1189
|
break;
|
|
1132
1190
|
case "dieline.radius":
|
|
1133
|
-
s.radius = e.value;
|
|
1191
|
+
s.radius = parseLengthToMm(e.value, "mm");
|
|
1134
1192
|
break;
|
|
1135
1193
|
case "dieline.padding":
|
|
1136
1194
|
s.padding = e.value;
|
|
1137
1195
|
break;
|
|
1138
1196
|
case "dieline.offset":
|
|
1139
|
-
s.offset = e.value;
|
|
1197
|
+
s.offset = parseLengthToMm(e.value, "mm");
|
|
1140
1198
|
break;
|
|
1141
1199
|
case "dieline.strokeWidth":
|
|
1142
1200
|
s.mainLine.width = e.value;
|
|
@@ -1195,11 +1253,11 @@ var DielineTool = class {
|
|
|
1195
1253
|
return {
|
|
1196
1254
|
[import_core2.ContributionPointIds.CONFIGURATIONS]: [
|
|
1197
1255
|
{
|
|
1198
|
-
id: "dieline.
|
|
1256
|
+
id: "dieline.displayUnit",
|
|
1199
1257
|
type: "select",
|
|
1200
|
-
label: "Unit",
|
|
1201
|
-
options: ["
|
|
1202
|
-
default: s.
|
|
1258
|
+
label: "Display Unit",
|
|
1259
|
+
options: ["mm", "cm", "in"],
|
|
1260
|
+
default: s.displayUnit
|
|
1203
1261
|
},
|
|
1204
1262
|
{
|
|
1205
1263
|
id: "dieline.shape",
|
|
@@ -1211,7 +1269,7 @@ var DielineTool = class {
|
|
|
1211
1269
|
{
|
|
1212
1270
|
id: "dieline.width",
|
|
1213
1271
|
type: "number",
|
|
1214
|
-
label: "Width",
|
|
1272
|
+
label: "Width (mm)",
|
|
1215
1273
|
min: 10,
|
|
1216
1274
|
max: 2e3,
|
|
1217
1275
|
default: s.width
|
|
@@ -1219,7 +1277,7 @@ var DielineTool = class {
|
|
|
1219
1277
|
{
|
|
1220
1278
|
id: "dieline.height",
|
|
1221
1279
|
type: "number",
|
|
1222
|
-
label: "Height",
|
|
1280
|
+
label: "Height (mm)",
|
|
1223
1281
|
min: 10,
|
|
1224
1282
|
max: 2e3,
|
|
1225
1283
|
default: s.height
|
|
@@ -1227,7 +1285,7 @@ var DielineTool = class {
|
|
|
1227
1285
|
{
|
|
1228
1286
|
id: "dieline.radius",
|
|
1229
1287
|
type: "number",
|
|
1230
|
-
label: "Corner Radius",
|
|
1288
|
+
label: "Corner Radius (mm)",
|
|
1231
1289
|
min: 0,
|
|
1232
1290
|
max: 500,
|
|
1233
1291
|
default: s.radius
|
|
@@ -1242,7 +1300,7 @@ var DielineTool = class {
|
|
|
1242
1300
|
{
|
|
1243
1301
|
id: "dieline.offset",
|
|
1244
1302
|
type: "number",
|
|
1245
|
-
label: "Bleed Offset",
|
|
1303
|
+
label: "Bleed Offset (mm)",
|
|
1246
1304
|
min: -100,
|
|
1247
1305
|
max: 100,
|
|
1248
1306
|
default: s.offset
|
|
@@ -1343,18 +1401,12 @@ var DielineTool = class {
|
|
|
1343
1401
|
);
|
|
1344
1402
|
if (!configService) return;
|
|
1345
1403
|
const features = configService.get("dieline.features") || [];
|
|
1346
|
-
const dielineWidth = configService.get("dieline.width") || 500;
|
|
1347
|
-
const dielineHeight = configService.get("dieline.height") || 500;
|
|
1348
1404
|
let changed = false;
|
|
1349
1405
|
const newFeatures = features.map((f) => {
|
|
1350
1406
|
if (f.groupId === groupId) {
|
|
1351
|
-
|
|
1352
|
-
dielineWidth,
|
|
1353
|
-
dielineHeight
|
|
1354
|
-
});
|
|
1355
|
-
if (f.x !== constrained.x || f.y !== constrained.y) {
|
|
1407
|
+
if (f.x !== x || f.y !== y) {
|
|
1356
1408
|
changed = true;
|
|
1357
|
-
return { ...f, x
|
|
1409
|
+
return { ...f, x, y };
|
|
1358
1410
|
}
|
|
1359
1411
|
}
|
|
1360
1412
|
return f;
|
|
@@ -1469,7 +1521,7 @@ var DielineTool = class {
|
|
|
1469
1521
|
const layer = this.getLayer();
|
|
1470
1522
|
if (!layer) return;
|
|
1471
1523
|
const {
|
|
1472
|
-
|
|
1524
|
+
displayUnit,
|
|
1473
1525
|
shape,
|
|
1474
1526
|
radius,
|
|
1475
1527
|
offset,
|
|
@@ -1480,15 +1532,13 @@ var DielineTool = class {
|
|
|
1480
1532
|
showBleedLines,
|
|
1481
1533
|
features
|
|
1482
1534
|
} = this.state;
|
|
1483
|
-
|
|
1535
|
+
const { width, height } = this.state;
|
|
1484
1536
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1485
1537
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1486
1538
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
paddingPx
|
|
1491
|
-
);
|
|
1539
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1540
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1541
|
+
const layout = this.canvasService.viewport.layout;
|
|
1492
1542
|
const scale = layout.scale;
|
|
1493
1543
|
const cx = layout.offsetX + layout.width / 2;
|
|
1494
1544
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1675,15 +1725,22 @@ var DielineTool = class {
|
|
|
1675
1725
|
}
|
|
1676
1726
|
getGeometry() {
|
|
1677
1727
|
if (!this.canvasService) return null;
|
|
1678
|
-
const {
|
|
1728
|
+
const {
|
|
1729
|
+
displayUnit,
|
|
1730
|
+
shape,
|
|
1731
|
+
width,
|
|
1732
|
+
height,
|
|
1733
|
+
radius,
|
|
1734
|
+
offset,
|
|
1735
|
+
mainLine,
|
|
1736
|
+
pathData
|
|
1737
|
+
} = this.state;
|
|
1679
1738
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1680
1739
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1681
1740
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
paddingPx
|
|
1686
|
-
);
|
|
1741
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1742
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1743
|
+
const layout = this.canvasService.viewport.layout;
|
|
1687
1744
|
const scale = layout.scale;
|
|
1688
1745
|
const cx = layout.offsetX + layout.width / 2;
|
|
1689
1746
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1691,14 +1748,14 @@ var DielineTool = class {
|
|
|
1691
1748
|
const visualHeight = layout.height;
|
|
1692
1749
|
return {
|
|
1693
1750
|
shape,
|
|
1694
|
-
unit,
|
|
1751
|
+
unit: "mm",
|
|
1752
|
+
displayUnit,
|
|
1695
1753
|
x: cx,
|
|
1696
1754
|
y: cy,
|
|
1697
1755
|
width: visualWidth,
|
|
1698
1756
|
height: visualHeight,
|
|
1699
1757
|
radius: radius * scale,
|
|
1700
1758
|
offset: offset * scale,
|
|
1701
|
-
// Pass scale to help other tools (like FeatureTool) convert units
|
|
1702
1759
|
scale,
|
|
1703
1760
|
strokeWidth: mainLine.width,
|
|
1704
1761
|
pathData
|
|
@@ -1708,15 +1765,13 @@ var DielineTool = class {
|
|
|
1708
1765
|
if (!this.canvasService) return null;
|
|
1709
1766
|
const userLayer = this.canvasService.getLayer("user");
|
|
1710
1767
|
if (!userLayer) return null;
|
|
1711
|
-
const { shape, width, height, radius, features,
|
|
1768
|
+
const { shape, width, height, radius, features, pathData } = this.state;
|
|
1712
1769
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1713
1770
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1714
1771
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
paddingPx
|
|
1719
|
-
);
|
|
1772
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1773
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1774
|
+
const layout = this.canvasService.viewport.layout;
|
|
1720
1775
|
const scale = layout.scale;
|
|
1721
1776
|
const cx = layout.offsetX + layout.width / 2;
|
|
1722
1777
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1931,13 +1986,212 @@ var FilmTool = class {
|
|
|
1931
1986
|
// src/feature.ts
|
|
1932
1987
|
var import_core4 = require("@pooder/core");
|
|
1933
1988
|
var import_fabric4 = require("fabric");
|
|
1989
|
+
|
|
1990
|
+
// src/constraints.ts
|
|
1991
|
+
var ConstraintRegistry = class {
|
|
1992
|
+
static register(type, handler) {
|
|
1993
|
+
this.handlers.set(type, handler);
|
|
1994
|
+
}
|
|
1995
|
+
static apply(x, y, feature, context, constraints) {
|
|
1996
|
+
const list = constraints || feature.constraints;
|
|
1997
|
+
if (!list || list.length === 0) {
|
|
1998
|
+
return { x, y };
|
|
1999
|
+
}
|
|
2000
|
+
let currentX = x;
|
|
2001
|
+
let currentY = y;
|
|
2002
|
+
for (const constraint of list) {
|
|
2003
|
+
const handler = this.handlers.get(constraint.type);
|
|
2004
|
+
if (handler) {
|
|
2005
|
+
const result = handler(currentX, currentY, feature, context, constraint.params || {});
|
|
2006
|
+
currentX = result.x;
|
|
2007
|
+
currentY = result.y;
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
return { x: currentX, y: currentY };
|
|
2011
|
+
}
|
|
2012
|
+
};
|
|
2013
|
+
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
2014
|
+
var pathConstraint = (x, y, feature, context, params) => {
|
|
2015
|
+
const { dielineWidth, dielineHeight, geometry } = context;
|
|
2016
|
+
if (!geometry) return { x, y };
|
|
2017
|
+
const minX = geometry.x - geometry.width / 2;
|
|
2018
|
+
const minY = geometry.y - geometry.height / 2;
|
|
2019
|
+
const absX = minX + x * geometry.width;
|
|
2020
|
+
const absY = minY + y * geometry.height;
|
|
2021
|
+
const nearest = getNearestPointOnDieline(
|
|
2022
|
+
{ x: absX, y: absY },
|
|
2023
|
+
geometry
|
|
2024
|
+
);
|
|
2025
|
+
let finalX = nearest.x;
|
|
2026
|
+
let finalY = nearest.y;
|
|
2027
|
+
const hasOffsetParams = params.minOffset !== void 0 || params.maxOffset !== void 0;
|
|
2028
|
+
if (hasOffsetParams && nearest.normal) {
|
|
2029
|
+
const dx = absX - nearest.x;
|
|
2030
|
+
const dy = absY - nearest.y;
|
|
2031
|
+
const nx2 = nearest.normal.x;
|
|
2032
|
+
const ny2 = nearest.normal.y;
|
|
2033
|
+
const dist = dx * nx2 + dy * ny2;
|
|
2034
|
+
const scale = dielineWidth > 0 ? geometry.width / dielineWidth : 1;
|
|
2035
|
+
const rawMin = params.minOffset !== void 0 ? params.minOffset : 0;
|
|
2036
|
+
const rawMax = params.maxOffset !== void 0 ? params.maxOffset : 0;
|
|
2037
|
+
const minOffset = rawMin * scale;
|
|
2038
|
+
const maxOffset = rawMax * scale;
|
|
2039
|
+
const clampedDist = Math.max(minOffset, Math.min(dist, maxOffset));
|
|
2040
|
+
finalX = nearest.x + nx2 * clampedDist;
|
|
2041
|
+
finalY = nearest.y + ny2 * clampedDist;
|
|
2042
|
+
}
|
|
2043
|
+
const nx = geometry.width > 0 ? (finalX - minX) / geometry.width : 0.5;
|
|
2044
|
+
const ny = geometry.height > 0 ? (finalY - minY) / geometry.height : 0.5;
|
|
2045
|
+
return { x: nx, y: ny };
|
|
2046
|
+
};
|
|
2047
|
+
var edgeConstraint = (x, y, feature, context, params) => {
|
|
2048
|
+
const { dielineWidth, dielineHeight } = context;
|
|
2049
|
+
const allowedEdges = params.allowedEdges || [
|
|
2050
|
+
"top",
|
|
2051
|
+
"bottom",
|
|
2052
|
+
"left",
|
|
2053
|
+
"right"
|
|
2054
|
+
];
|
|
2055
|
+
const confine = params.confine || false;
|
|
2056
|
+
const offset = params.offset || 0;
|
|
2057
|
+
const distances = [];
|
|
2058
|
+
if (allowedEdges.includes("top"))
|
|
2059
|
+
distances.push({ edge: "top", dist: y * dielineHeight });
|
|
2060
|
+
if (allowedEdges.includes("bottom"))
|
|
2061
|
+
distances.push({ edge: "bottom", dist: (1 - y) * dielineHeight });
|
|
2062
|
+
if (allowedEdges.includes("left"))
|
|
2063
|
+
distances.push({ edge: "left", dist: x * dielineWidth });
|
|
2064
|
+
if (allowedEdges.includes("right"))
|
|
2065
|
+
distances.push({ edge: "right", dist: (1 - x) * dielineWidth });
|
|
2066
|
+
if (distances.length === 0) return { x, y };
|
|
2067
|
+
distances.sort((a, b) => a.dist - b.dist);
|
|
2068
|
+
const nearest = distances[0].edge;
|
|
2069
|
+
let newX = x;
|
|
2070
|
+
let newY = y;
|
|
2071
|
+
const fw = feature.width || 0;
|
|
2072
|
+
const fh = feature.height || 0;
|
|
2073
|
+
switch (nearest) {
|
|
2074
|
+
case "top":
|
|
2075
|
+
newY = 0 + offset / dielineHeight;
|
|
2076
|
+
if (confine) {
|
|
2077
|
+
const minX = fw / 2 / dielineWidth;
|
|
2078
|
+
const maxX = 1 - minX;
|
|
2079
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
2080
|
+
}
|
|
2081
|
+
break;
|
|
2082
|
+
case "bottom":
|
|
2083
|
+
newY = 1 - offset / dielineHeight;
|
|
2084
|
+
if (confine) {
|
|
2085
|
+
const minX = fw / 2 / dielineWidth;
|
|
2086
|
+
const maxX = 1 - minX;
|
|
2087
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
2088
|
+
}
|
|
2089
|
+
break;
|
|
2090
|
+
case "left":
|
|
2091
|
+
newX = 0 + offset / dielineWidth;
|
|
2092
|
+
if (confine) {
|
|
2093
|
+
const minY = fh / 2 / dielineHeight;
|
|
2094
|
+
const maxY = 1 - minY;
|
|
2095
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
2096
|
+
}
|
|
2097
|
+
break;
|
|
2098
|
+
case "right":
|
|
2099
|
+
newX = 1 - offset / dielineWidth;
|
|
2100
|
+
if (confine) {
|
|
2101
|
+
const minY = fh / 2 / dielineHeight;
|
|
2102
|
+
const maxY = 1 - minY;
|
|
2103
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
2104
|
+
}
|
|
2105
|
+
break;
|
|
2106
|
+
}
|
|
2107
|
+
return { x: newX, y: newY };
|
|
2108
|
+
};
|
|
2109
|
+
var internalConstraint = (x, y, feature, context, params) => {
|
|
2110
|
+
const { dielineWidth, dielineHeight } = context;
|
|
2111
|
+
const margin = params.margin || 0;
|
|
2112
|
+
const fw = feature.width || 0;
|
|
2113
|
+
const fh = feature.height || 0;
|
|
2114
|
+
const minX = (margin + fw / 2) / dielineWidth;
|
|
2115
|
+
const maxX = 1 - (margin + fw / 2) / dielineWidth;
|
|
2116
|
+
const minY = (margin + fh / 2) / dielineHeight;
|
|
2117
|
+
const maxY = 1 - (margin + fh / 2) / dielineHeight;
|
|
2118
|
+
const clampedX = minX > maxX ? 0.5 : Math.max(minX, Math.min(x, maxX));
|
|
2119
|
+
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
2120
|
+
return { x: clampedX, y: clampedY };
|
|
2121
|
+
};
|
|
2122
|
+
var tangentBottomConstraint = (x, y, feature, context, params) => {
|
|
2123
|
+
const { dielineWidth, dielineHeight } = context;
|
|
2124
|
+
const gap = params.gap || 0;
|
|
2125
|
+
const confineX = params.confineX !== false;
|
|
2126
|
+
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
2127
|
+
const newY = 1 + (extentY + gap) / dielineHeight;
|
|
2128
|
+
let newX = x;
|
|
2129
|
+
if (confineX) {
|
|
2130
|
+
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
2131
|
+
const minX = extentX / dielineWidth;
|
|
2132
|
+
const maxX = 1 - extentX / dielineWidth;
|
|
2133
|
+
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
2134
|
+
}
|
|
2135
|
+
return { x: newX, y: newY };
|
|
2136
|
+
};
|
|
2137
|
+
var lowestTangentConstraint = (x, y, feature, context, params) => {
|
|
2138
|
+
const { dielineWidth, dielineHeight, geometry } = context;
|
|
2139
|
+
if (!geometry) return { x, y };
|
|
2140
|
+
const lowest = getLowestPointOnDieline(geometry);
|
|
2141
|
+
const minY = geometry.y - geometry.height / 2;
|
|
2142
|
+
const normY = (lowest.y - minY) / geometry.height;
|
|
2143
|
+
const gap = params.gap || 0;
|
|
2144
|
+
const confineX = params.confineX !== false;
|
|
2145
|
+
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
2146
|
+
const newY = normY + (extentY + gap) / dielineHeight;
|
|
2147
|
+
let newX = x;
|
|
2148
|
+
if (confineX) {
|
|
2149
|
+
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
2150
|
+
const minX = extentX / dielineWidth;
|
|
2151
|
+
const maxX = 1 - extentX / dielineWidth;
|
|
2152
|
+
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
2153
|
+
}
|
|
2154
|
+
return { x: newX, y: newY };
|
|
2155
|
+
};
|
|
2156
|
+
ConstraintRegistry.register("path", pathConstraint);
|
|
2157
|
+
ConstraintRegistry.register("edge", edgeConstraint);
|
|
2158
|
+
ConstraintRegistry.register("internal", internalConstraint);
|
|
2159
|
+
ConstraintRegistry.register("tangent-bottom", tangentBottomConstraint);
|
|
2160
|
+
ConstraintRegistry.register("lowest-tangent", lowestTangentConstraint);
|
|
2161
|
+
|
|
2162
|
+
// src/featureComplete.ts
|
|
2163
|
+
function validateFeaturesStrict(features, context) {
|
|
2164
|
+
const eps = 1e-6;
|
|
2165
|
+
const issues = [];
|
|
2166
|
+
for (const f of features) {
|
|
2167
|
+
if (!f.constraints || f.constraints.length === 0) continue;
|
|
2168
|
+
const constrained = ConstraintRegistry.apply(f.x, f.y, f, context, f.constraints);
|
|
2169
|
+
if (Math.abs(constrained.x - f.x) > eps || Math.abs(constrained.y - f.y) > eps) {
|
|
2170
|
+
issues.push({
|
|
2171
|
+
featureId: f.id,
|
|
2172
|
+
groupId: f.groupId,
|
|
2173
|
+
reason: "Position violates constraint strategy"
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
return { ok: issues.length === 0, issues: issues.length ? issues : void 0 };
|
|
2178
|
+
}
|
|
2179
|
+
function completeFeaturesStrict(features, context, update) {
|
|
2180
|
+
const validation = validateFeaturesStrict(features, context);
|
|
2181
|
+
if (!validation.ok) return validation;
|
|
2182
|
+
const next = JSON.parse(JSON.stringify(features || []));
|
|
2183
|
+
update(next);
|
|
2184
|
+
return { ok: true };
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
// src/feature.ts
|
|
1934
2188
|
var FeatureTool = class {
|
|
1935
2189
|
constructor(options) {
|
|
1936
2190
|
this.id = "pooder.kit.feature";
|
|
1937
2191
|
this.metadata = {
|
|
1938
2192
|
name: "FeatureTool"
|
|
1939
2193
|
};
|
|
1940
|
-
this.
|
|
2194
|
+
this.workingFeatures = [];
|
|
1941
2195
|
this.isUpdatingConfig = false;
|
|
1942
2196
|
this.isToolActive = false;
|
|
1943
2197
|
this.handleMoving = null;
|
|
@@ -1963,12 +2217,15 @@ var FeatureTool = class {
|
|
|
1963
2217
|
"ConfigurationService"
|
|
1964
2218
|
);
|
|
1965
2219
|
if (configService) {
|
|
1966
|
-
|
|
2220
|
+
const features = configService.get("dieline.features", []) || [];
|
|
2221
|
+
this.workingFeatures = this.cloneFeatures(features);
|
|
1967
2222
|
configService.onAnyChange((e) => {
|
|
1968
2223
|
if (this.isUpdatingConfig) return;
|
|
1969
2224
|
if (e.key === "dieline.features") {
|
|
1970
|
-
|
|
2225
|
+
const next = e.value || [];
|
|
2226
|
+
this.workingFeatures = this.cloneFeatures(next);
|
|
1971
2227
|
this.redraw();
|
|
2228
|
+
this.emitWorkingChange();
|
|
1972
2229
|
}
|
|
1973
2230
|
});
|
|
1974
2231
|
}
|
|
@@ -2026,57 +2283,172 @@ var FeatureTool = class {
|
|
|
2026
2283
|
command: "clearFeatures",
|
|
2027
2284
|
title: "Clear Features",
|
|
2028
2285
|
handler: () => {
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
);
|
|
2033
|
-
if (configService) {
|
|
2034
|
-
configService.update("dieline.features", []);
|
|
2035
|
-
}
|
|
2286
|
+
this.setWorkingFeatures([]);
|
|
2287
|
+
this.redraw();
|
|
2288
|
+
this.emitWorkingChange();
|
|
2036
2289
|
return true;
|
|
2037
2290
|
}
|
|
2291
|
+
},
|
|
2292
|
+
{
|
|
2293
|
+
command: "getWorkingFeatures",
|
|
2294
|
+
title: "Get Working Features",
|
|
2295
|
+
handler: () => {
|
|
2296
|
+
return this.cloneFeatures(this.workingFeatures);
|
|
2297
|
+
}
|
|
2298
|
+
},
|
|
2299
|
+
{
|
|
2300
|
+
command: "setWorkingFeatures",
|
|
2301
|
+
title: "Set Working Features",
|
|
2302
|
+
handler: async (features) => {
|
|
2303
|
+
await this.refreshGeometry();
|
|
2304
|
+
this.setWorkingFeatures(this.cloneFeatures(features || []));
|
|
2305
|
+
this.redraw();
|
|
2306
|
+
this.emitWorkingChange();
|
|
2307
|
+
return { ok: true };
|
|
2308
|
+
}
|
|
2309
|
+
},
|
|
2310
|
+
{
|
|
2311
|
+
command: "updateWorkingGroupPosition",
|
|
2312
|
+
title: "Update Working Group Position",
|
|
2313
|
+
handler: (groupId, x, y) => {
|
|
2314
|
+
return this.updateWorkingGroupPosition(groupId, x, y);
|
|
2315
|
+
}
|
|
2316
|
+
},
|
|
2317
|
+
{
|
|
2318
|
+
command: "completeFeatures",
|
|
2319
|
+
title: "Complete Features",
|
|
2320
|
+
handler: () => {
|
|
2321
|
+
return this.completeFeatures();
|
|
2322
|
+
}
|
|
2038
2323
|
}
|
|
2039
2324
|
]
|
|
2040
2325
|
};
|
|
2041
2326
|
}
|
|
2042
|
-
|
|
2327
|
+
cloneFeatures(features) {
|
|
2328
|
+
return JSON.parse(JSON.stringify(features || []));
|
|
2329
|
+
}
|
|
2330
|
+
emitWorkingChange() {
|
|
2043
2331
|
var _a;
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2332
|
+
(_a = this.context) == null ? void 0 : _a.eventBus.emit("feature:working:change", {
|
|
2333
|
+
features: this.cloneFeatures(this.workingFeatures)
|
|
2334
|
+
});
|
|
2335
|
+
}
|
|
2336
|
+
async refreshGeometry() {
|
|
2337
|
+
if (!this.context) return;
|
|
2338
|
+
const commandService = this.context.services.get("CommandService");
|
|
2339
|
+
if (!commandService) return;
|
|
2340
|
+
try {
|
|
2341
|
+
const g = await Promise.resolve(commandService.executeCommand("getGeometry"));
|
|
2342
|
+
if (g) this.currentGeometry = g;
|
|
2343
|
+
} catch (e) {
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
setWorkingFeatures(next) {
|
|
2347
|
+
this.workingFeatures = next;
|
|
2348
|
+
}
|
|
2349
|
+
updateWorkingGroupPosition(groupId, x, y) {
|
|
2350
|
+
var _a, _b, _c;
|
|
2351
|
+
if (!groupId) return { ok: false };
|
|
2352
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
2353
|
+
if (!configService) return { ok: false };
|
|
2354
|
+
const dielineWidth = parseLengthToMm(
|
|
2355
|
+
(_b = configService.get("dieline.width")) != null ? _b : 500,
|
|
2356
|
+
"mm"
|
|
2357
|
+
);
|
|
2358
|
+
const dielineHeight = parseLengthToMm(
|
|
2359
|
+
(_c = configService.get("dieline.height")) != null ? _c : 500,
|
|
2360
|
+
"mm"
|
|
2361
|
+
);
|
|
2362
|
+
let changed = false;
|
|
2363
|
+
const next = this.workingFeatures.map((f) => {
|
|
2364
|
+
if (f.groupId !== groupId) return f;
|
|
2365
|
+
let nx = x;
|
|
2366
|
+
let ny = y;
|
|
2367
|
+
if (f.constraints && dielineWidth > 0 && dielineHeight > 0) {
|
|
2368
|
+
const constrained = ConstraintRegistry.apply(nx, ny, f, {
|
|
2369
|
+
dielineWidth,
|
|
2370
|
+
dielineHeight
|
|
2371
|
+
});
|
|
2372
|
+
nx = constrained.x;
|
|
2373
|
+
ny = constrained.y;
|
|
2374
|
+
}
|
|
2375
|
+
if (f.x !== nx || f.y !== ny) {
|
|
2376
|
+
changed = true;
|
|
2377
|
+
return { ...f, x: nx, y: ny };
|
|
2378
|
+
}
|
|
2379
|
+
return f;
|
|
2380
|
+
});
|
|
2381
|
+
if (!changed) return { ok: true };
|
|
2382
|
+
this.setWorkingFeatures(next);
|
|
2383
|
+
this.redraw();
|
|
2384
|
+
this.enforceConstraints();
|
|
2385
|
+
this.emitWorkingChange();
|
|
2386
|
+
return { ok: true };
|
|
2387
|
+
}
|
|
2388
|
+
completeFeatures() {
|
|
2389
|
+
var _a, _b, _c;
|
|
2390
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
2391
|
+
if (!configService) {
|
|
2392
|
+
return {
|
|
2393
|
+
ok: false,
|
|
2394
|
+
issues: [
|
|
2395
|
+
{ featureId: "unknown", reason: "ConfigurationService not found" }
|
|
2396
|
+
]
|
|
2397
|
+
};
|
|
2398
|
+
}
|
|
2399
|
+
const dielineWidth = parseLengthToMm(
|
|
2400
|
+
(_b = configService.get("dieline.width")) != null ? _b : 500,
|
|
2401
|
+
"mm"
|
|
2047
2402
|
);
|
|
2048
|
-
const
|
|
2049
|
-
|
|
2403
|
+
const dielineHeight = parseLengthToMm(
|
|
2404
|
+
(_c = configService.get("dieline.height")) != null ? _c : 500,
|
|
2405
|
+
"mm"
|
|
2406
|
+
);
|
|
2407
|
+
const result = completeFeaturesStrict(
|
|
2408
|
+
this.workingFeatures,
|
|
2409
|
+
{ dielineWidth, dielineHeight },
|
|
2410
|
+
(next) => {
|
|
2411
|
+
this.isUpdatingConfig = true;
|
|
2412
|
+
try {
|
|
2413
|
+
configService.update("dieline.features", next);
|
|
2414
|
+
} finally {
|
|
2415
|
+
this.isUpdatingConfig = false;
|
|
2416
|
+
}
|
|
2417
|
+
this.workingFeatures = this.cloneFeatures(next);
|
|
2418
|
+
this.emitWorkingChange();
|
|
2419
|
+
}
|
|
2420
|
+
);
|
|
2421
|
+
if (!result.ok) {
|
|
2422
|
+
return {
|
|
2423
|
+
ok: false,
|
|
2424
|
+
issues: result.issues
|
|
2425
|
+
};
|
|
2426
|
+
}
|
|
2427
|
+
return { ok: true };
|
|
2428
|
+
}
|
|
2429
|
+
addFeature(type) {
|
|
2430
|
+
if (!this.canvasService) return false;
|
|
2050
2431
|
const newFeature = {
|
|
2051
2432
|
id: Date.now().toString(),
|
|
2052
2433
|
operation: type,
|
|
2053
|
-
placement: "edge",
|
|
2054
2434
|
shape: "rect",
|
|
2055
2435
|
x: 0.5,
|
|
2056
2436
|
y: 0,
|
|
2057
2437
|
// Top edge
|
|
2058
|
-
width:
|
|
2059
|
-
height:
|
|
2060
|
-
rotation: 0
|
|
2438
|
+
width: 10,
|
|
2439
|
+
height: 10,
|
|
2440
|
+
rotation: 0,
|
|
2441
|
+
renderBehavior: "edge",
|
|
2442
|
+
// Default constraint: path (snap to edge)
|
|
2443
|
+
constraints: [{ type: "path" }]
|
|
2061
2444
|
};
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
[]
|
|
2066
|
-
);
|
|
2067
|
-
configService.update("dieline.features", [...current, newFeature]);
|
|
2068
|
-
}
|
|
2445
|
+
this.setWorkingFeatures([...this.workingFeatures || [], newFeature]);
|
|
2446
|
+
this.redraw();
|
|
2447
|
+
this.emitWorkingChange();
|
|
2069
2448
|
return true;
|
|
2070
2449
|
}
|
|
2071
2450
|
addDoubleLayerHole() {
|
|
2072
|
-
var _a;
|
|
2073
2451
|
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
2452
|
const groupId = Date.now().toString();
|
|
2081
2453
|
const timestamp = Date.now();
|
|
2082
2454
|
const lug = {
|
|
@@ -2084,32 +2456,28 @@ var FeatureTool = class {
|
|
|
2084
2456
|
groupId,
|
|
2085
2457
|
operation: "add",
|
|
2086
2458
|
shape: "circle",
|
|
2087
|
-
placement: "edge",
|
|
2088
2459
|
x: 0.5,
|
|
2089
2460
|
y: 0,
|
|
2090
|
-
radius:
|
|
2091
|
-
|
|
2092
|
-
|
|
2461
|
+
radius: 20,
|
|
2462
|
+
rotation: 0,
|
|
2463
|
+
renderBehavior: "edge",
|
|
2464
|
+
constraints: [{ type: "path" }]
|
|
2093
2465
|
};
|
|
2094
2466
|
const hole = {
|
|
2095
2467
|
id: `${timestamp}-hole`,
|
|
2096
2468
|
groupId,
|
|
2097
2469
|
operation: "subtract",
|
|
2098
2470
|
shape: "circle",
|
|
2099
|
-
placement: "edge",
|
|
2100
2471
|
x: 0.5,
|
|
2101
2472
|
y: 0,
|
|
2102
|
-
radius:
|
|
2103
|
-
|
|
2104
|
-
|
|
2473
|
+
radius: 15,
|
|
2474
|
+
rotation: 0,
|
|
2475
|
+
renderBehavior: "edge",
|
|
2476
|
+
constraints: [{ type: "path" }]
|
|
2105
2477
|
};
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
[]
|
|
2110
|
-
);
|
|
2111
|
-
configService.update("dieline.features", [...current, lug, hole]);
|
|
2112
|
-
}
|
|
2478
|
+
this.setWorkingFeatures([...this.workingFeatures || [], lug, hole]);
|
|
2479
|
+
this.redraw();
|
|
2480
|
+
this.emitWorkingChange();
|
|
2113
2481
|
return true;
|
|
2114
2482
|
}
|
|
2115
2483
|
getGeometryForFeature(geometry, feature) {
|
|
@@ -2153,12 +2521,12 @@ var FeatureTool = class {
|
|
|
2153
2521
|
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
2154
2522
|
const indices = (_c = target.data) == null ? void 0 : _c.indices;
|
|
2155
2523
|
if (indices && indices.length > 0) {
|
|
2156
|
-
feature = this.
|
|
2524
|
+
feature = this.workingFeatures[indices[0]];
|
|
2157
2525
|
}
|
|
2158
2526
|
} else {
|
|
2159
2527
|
const index = (_d = target.data) == null ? void 0 : _d.index;
|
|
2160
2528
|
if (index !== void 0) {
|
|
2161
|
-
feature = this.
|
|
2529
|
+
feature = this.workingFeatures[index];
|
|
2162
2530
|
}
|
|
2163
2531
|
}
|
|
2164
2532
|
const geometry = this.getGeometryForFeature(
|
|
@@ -2179,7 +2547,7 @@ var FeatureTool = class {
|
|
|
2179
2547
|
}
|
|
2180
2548
|
if (!this.handleModified) {
|
|
2181
2549
|
this.handleModified = (e) => {
|
|
2182
|
-
var _a, _b, _c
|
|
2550
|
+
var _a, _b, _c;
|
|
2183
2551
|
const target = e.target;
|
|
2184
2552
|
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "feature-marker") return;
|
|
2185
2553
|
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
@@ -2187,11 +2555,11 @@ var FeatureTool = class {
|
|
|
2187
2555
|
const indices = (_c = groupObj.data) == null ? void 0 : _c.indices;
|
|
2188
2556
|
if (!indices) return;
|
|
2189
2557
|
const groupCenter = new import_fabric4.Point(groupObj.left, groupObj.top);
|
|
2190
|
-
const newFeatures = [...this.
|
|
2558
|
+
const newFeatures = [...this.workingFeatures];
|
|
2191
2559
|
const { x, y } = this.currentGeometry;
|
|
2192
2560
|
groupObj.getObjects().forEach((child, i) => {
|
|
2193
2561
|
const originalIndex = indices[i];
|
|
2194
|
-
const feature = this.
|
|
2562
|
+
const feature = this.workingFeatures[originalIndex];
|
|
2195
2563
|
const geometry = this.getGeometryForFeature(
|
|
2196
2564
|
this.currentGeometry,
|
|
2197
2565
|
feature
|
|
@@ -2209,18 +2577,8 @@ var FeatureTool = class {
|
|
|
2209
2577
|
y: normalizedY
|
|
2210
2578
|
};
|
|
2211
2579
|
});
|
|
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
|
-
}
|
|
2580
|
+
this.setWorkingFeatures(newFeatures);
|
|
2581
|
+
this.emitWorkingChange();
|
|
2224
2582
|
} else {
|
|
2225
2583
|
this.syncFeatureFromCanvas(target);
|
|
2226
2584
|
}
|
|
@@ -2254,56 +2612,41 @@ var FeatureTool = class {
|
|
|
2254
2612
|
this.canvasService.requestRenderAll();
|
|
2255
2613
|
}
|
|
2256
2614
|
constrainPosition(p, geometry, limit, feature) {
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
const minY = geometry.y - geometry.height / 2;
|
|
2260
|
-
const nx = geometry.width > 0 ? (p.x - minX) / geometry.width : 0.5;
|
|
2261
|
-
const ny = geometry.height > 0 ? (p.y - minY) / geometry.height : 0.5;
|
|
2262
|
-
const scale2 = geometry.scale || 1;
|
|
2263
|
-
const dielineWidth = geometry.width / scale2;
|
|
2264
|
-
const dielineHeight = geometry.height / scale2;
|
|
2265
|
-
const constrained = ConstraintRegistry.apply(nx, ny, feature, {
|
|
2266
|
-
dielineWidth,
|
|
2267
|
-
dielineHeight
|
|
2268
|
-
});
|
|
2269
|
-
return {
|
|
2270
|
-
x: minX + constrained.x * geometry.width,
|
|
2271
|
-
y: minY + constrained.y * geometry.height
|
|
2272
|
-
};
|
|
2273
|
-
}
|
|
2274
|
-
if (feature && feature.placement === "internal") {
|
|
2275
|
-
const minX = geometry.x - geometry.width / 2;
|
|
2276
|
-
const maxX = geometry.x + geometry.width / 2;
|
|
2277
|
-
const minY = geometry.y - geometry.height / 2;
|
|
2278
|
-
const maxY = geometry.y + geometry.height / 2;
|
|
2279
|
-
return {
|
|
2280
|
-
x: Math.max(minX, Math.min(maxX, p.x)),
|
|
2281
|
-
y: Math.max(minY, Math.min(maxY, p.y))
|
|
2282
|
-
};
|
|
2283
|
-
}
|
|
2284
|
-
const nearest = getNearestPointOnDieline({ x: p.x, y: p.y }, {
|
|
2285
|
-
...geometry,
|
|
2286
|
-
features: []
|
|
2287
|
-
});
|
|
2288
|
-
const dx = p.x - nearest.x;
|
|
2289
|
-
const dy = p.y - nearest.y;
|
|
2290
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
2291
|
-
if (dist <= limit) {
|
|
2615
|
+
var _a;
|
|
2616
|
+
if (!feature) {
|
|
2292
2617
|
return { x: p.x, y: p.y };
|
|
2293
2618
|
}
|
|
2294
|
-
const
|
|
2619
|
+
const minX = geometry.x - geometry.width / 2;
|
|
2620
|
+
const minY = geometry.y - geometry.height / 2;
|
|
2621
|
+
const nx = geometry.width > 0 ? (p.x - minX) / geometry.width : 0.5;
|
|
2622
|
+
const ny = geometry.height > 0 ? (p.y - minY) / geometry.height : 0.5;
|
|
2623
|
+
const scale = geometry.scale || 1;
|
|
2624
|
+
const dielineWidth = geometry.width / scale;
|
|
2625
|
+
const dielineHeight = geometry.height / scale;
|
|
2626
|
+
const activeConstraints = (_a = feature.constraints) == null ? void 0 : _a.filter((c) => !c.validateOnly);
|
|
2627
|
+
const constrained = ConstraintRegistry.apply(
|
|
2628
|
+
nx,
|
|
2629
|
+
ny,
|
|
2630
|
+
feature,
|
|
2631
|
+
{
|
|
2632
|
+
dielineWidth,
|
|
2633
|
+
dielineHeight,
|
|
2634
|
+
geometry
|
|
2635
|
+
},
|
|
2636
|
+
activeConstraints
|
|
2637
|
+
);
|
|
2295
2638
|
return {
|
|
2296
|
-
x:
|
|
2297
|
-
y:
|
|
2639
|
+
x: minX + constrained.x * geometry.width,
|
|
2640
|
+
y: minY + constrained.y * geometry.height
|
|
2298
2641
|
};
|
|
2299
2642
|
}
|
|
2300
2643
|
syncFeatureFromCanvas(target) {
|
|
2301
2644
|
var _a;
|
|
2302
2645
|
if (!this.currentGeometry || !this.context) return;
|
|
2303
2646
|
const index = (_a = target.data) == null ? void 0 : _a.index;
|
|
2304
|
-
if (index === void 0 || index < 0 || index >= this.
|
|
2647
|
+
if (index === void 0 || index < 0 || index >= this.workingFeatures.length)
|
|
2305
2648
|
return;
|
|
2306
|
-
const feature = this.
|
|
2649
|
+
const feature = this.workingFeatures[index];
|
|
2307
2650
|
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
2308
2651
|
const { width, height, x, y } = geometry;
|
|
2309
2652
|
const left = x - width / 2;
|
|
@@ -2316,20 +2659,10 @@ var FeatureTool = class {
|
|
|
2316
2659
|
y: normalizedY
|
|
2317
2660
|
// Could also update rotation if we allowed rotating markers
|
|
2318
2661
|
};
|
|
2319
|
-
const newFeatures = [...this.
|
|
2662
|
+
const newFeatures = [...this.workingFeatures];
|
|
2320
2663
|
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
|
-
}
|
|
2664
|
+
this.setWorkingFeatures(newFeatures);
|
|
2665
|
+
this.emitWorkingChange();
|
|
2333
2666
|
}
|
|
2334
2667
|
redraw() {
|
|
2335
2668
|
if (!this.canvasService || !this.currentGeometry) return;
|
|
@@ -2340,7 +2673,7 @@ var FeatureTool = class {
|
|
|
2340
2673
|
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
2341
2674
|
});
|
|
2342
2675
|
existing.forEach((obj) => canvas.remove(obj));
|
|
2343
|
-
if (!this.
|
|
2676
|
+
if (!this.workingFeatures || this.workingFeatures.length === 0) {
|
|
2344
2677
|
this.canvasService.requestRenderAll();
|
|
2345
2678
|
return;
|
|
2346
2679
|
}
|
|
@@ -2348,7 +2681,7 @@ var FeatureTool = class {
|
|
|
2348
2681
|
const finalScale = scale;
|
|
2349
2682
|
const groups = {};
|
|
2350
2683
|
const singles = [];
|
|
2351
|
-
this.
|
|
2684
|
+
this.workingFeatures.forEach((f, i) => {
|
|
2352
2685
|
if (f.groupId) {
|
|
2353
2686
|
if (!groups[f.groupId]) groups[f.groupId] = [];
|
|
2354
2687
|
groups[f.groupId].push({ feature: f, index: i });
|
|
@@ -2395,6 +2728,33 @@ var FeatureTool = class {
|
|
|
2395
2728
|
if (feature.rotation) {
|
|
2396
2729
|
shape.rotate(feature.rotation);
|
|
2397
2730
|
}
|
|
2731
|
+
if (feature.bridge && feature.bridge.type === "vertical") {
|
|
2732
|
+
const bridgeIndicator = new import_fabric4.Rect({
|
|
2733
|
+
width: visualWidth,
|
|
2734
|
+
height: 100 * featureScale,
|
|
2735
|
+
// Arbitrary long length to show direction
|
|
2736
|
+
fill: "transparent",
|
|
2737
|
+
stroke: "#888",
|
|
2738
|
+
strokeWidth: 1,
|
|
2739
|
+
strokeDashArray: [2, 2],
|
|
2740
|
+
originX: "center",
|
|
2741
|
+
originY: "bottom",
|
|
2742
|
+
// Anchor at bottom so it extends up
|
|
2743
|
+
left: pos.x,
|
|
2744
|
+
top: pos.y - visualHeight / 2,
|
|
2745
|
+
// Start from top of feature
|
|
2746
|
+
opacity: 0.5,
|
|
2747
|
+
selectable: false,
|
|
2748
|
+
evented: false
|
|
2749
|
+
});
|
|
2750
|
+
const group = new import_fabric4.Group([bridgeIndicator, shape], {
|
|
2751
|
+
originX: "center",
|
|
2752
|
+
originY: "center",
|
|
2753
|
+
left: pos.x,
|
|
2754
|
+
top: pos.y
|
|
2755
|
+
});
|
|
2756
|
+
return group;
|
|
2757
|
+
}
|
|
2398
2758
|
return shape;
|
|
2399
2759
|
};
|
|
2400
2760
|
singles.forEach(({ feature, index }) => {
|
|
@@ -2416,25 +2776,6 @@ var FeatureTool = class {
|
|
|
2416
2776
|
lockScalingY: true,
|
|
2417
2777
|
data: { type: "feature-marker", index, isGroup: false }
|
|
2418
2778
|
});
|
|
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
2779
|
canvas.add(marker);
|
|
2439
2780
|
canvas.bringObjectToFront(marker);
|
|
2440
2781
|
});
|
|
@@ -2471,25 +2812,6 @@ var FeatureTool = class {
|
|
|
2471
2812
|
indices: members.map((m) => m.index)
|
|
2472
2813
|
}
|
|
2473
2814
|
});
|
|
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
2815
|
canvas.add(groupObj);
|
|
2494
2816
|
canvas.bringObjectToFront(groupObj);
|
|
2495
2817
|
});
|
|
@@ -2508,12 +2830,12 @@ var FeatureTool = class {
|
|
|
2508
2830
|
if ((_a = marker.data) == null ? void 0 : _a.isGroup) {
|
|
2509
2831
|
const indices = (_b = marker.data) == null ? void 0 : _b.indices;
|
|
2510
2832
|
if (indices && indices.length > 0) {
|
|
2511
|
-
feature = this.
|
|
2833
|
+
feature = this.workingFeatures[indices[0]];
|
|
2512
2834
|
}
|
|
2513
2835
|
} else {
|
|
2514
2836
|
const index = (_c = marker.data) == null ? void 0 : _c.index;
|
|
2515
2837
|
if (index !== void 0) {
|
|
2516
|
-
feature = this.
|
|
2838
|
+
feature = this.workingFeatures[index];
|
|
2517
2839
|
}
|
|
2518
2840
|
}
|
|
2519
2841
|
const geometry = this.getGeometryForFeature(
|
|
@@ -3237,7 +3559,7 @@ var RulerTool = class {
|
|
|
3237
3559
|
// Dieline context for sync
|
|
3238
3560
|
this.dielineWidth = 500;
|
|
3239
3561
|
this.dielineHeight = 500;
|
|
3240
|
-
this.
|
|
3562
|
+
this.dielineDisplayUnit = "mm";
|
|
3241
3563
|
this.dielinePadding = 40;
|
|
3242
3564
|
this.dielineOffset = 0;
|
|
3243
3565
|
if (options) {
|
|
@@ -3261,7 +3583,10 @@ var RulerTool = class {
|
|
|
3261
3583
|
this.textColor = configService.get("ruler.textColor", this.textColor);
|
|
3262
3584
|
this.lineColor = configService.get("ruler.lineColor", this.lineColor);
|
|
3263
3585
|
this.fontSize = configService.get("ruler.fontSize", this.fontSize);
|
|
3264
|
-
this.
|
|
3586
|
+
this.dielineDisplayUnit = configService.get(
|
|
3587
|
+
"dieline.displayUnit",
|
|
3588
|
+
this.dielineDisplayUnit
|
|
3589
|
+
);
|
|
3265
3590
|
this.dielineWidth = configService.get("dieline.width", this.dielineWidth);
|
|
3266
3591
|
this.dielineHeight = configService.get(
|
|
3267
3592
|
"dieline.height",
|
|
@@ -3284,7 +3609,8 @@ var RulerTool = class {
|
|
|
3284
3609
|
shouldUpdate = true;
|
|
3285
3610
|
}
|
|
3286
3611
|
} else if (e.key.startsWith("dieline.")) {
|
|
3287
|
-
if (e.key === "dieline.
|
|
3612
|
+
if (e.key === "dieline.displayUnit")
|
|
3613
|
+
this.dielineDisplayUnit = e.value;
|
|
3288
3614
|
if (e.key === "dieline.width") this.dielineWidth = e.value;
|
|
3289
3615
|
if (e.key === "dieline.height") this.dielineHeight = e.value;
|
|
3290
3616
|
if (e.key === "dieline.padding") this.dielinePadding = e.value;
|
|
@@ -3471,26 +3797,27 @@ var RulerTool = class {
|
|
|
3471
3797
|
const width = this.canvasService.canvas.width || 800;
|
|
3472
3798
|
const height = this.canvasService.canvas.height || 600;
|
|
3473
3799
|
const paddingPx = this.resolvePadding(width, height);
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3800
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
3801
|
+
this.canvasService.viewport.updatePhysical(
|
|
3802
|
+
this.dielineWidth,
|
|
3803
|
+
this.dielineHeight
|
|
3478
3804
|
);
|
|
3805
|
+
const layout = this.canvasService.viewport.layout;
|
|
3479
3806
|
const scale = layout.scale;
|
|
3480
3807
|
const offsetX = layout.offsetX;
|
|
3481
3808
|
const offsetY = layout.offsetY;
|
|
3482
3809
|
const visualWidth = layout.width;
|
|
3483
3810
|
const visualHeight = layout.height;
|
|
3484
|
-
const
|
|
3485
|
-
const
|
|
3486
|
-
const expandPixels =
|
|
3811
|
+
const rawOffsetMm = this.dielineOffset || 0;
|
|
3812
|
+
const effectiveOffsetMm = rawOffsetMm > 0 ? rawOffsetMm : 0;
|
|
3813
|
+
const expandPixels = effectiveOffsetMm * scale;
|
|
3487
3814
|
const gap = this.gap || 15;
|
|
3488
3815
|
const rulerLeft = offsetX - expandPixels;
|
|
3489
3816
|
const rulerTop = offsetY - expandPixels;
|
|
3490
3817
|
const rulerRight = offsetX + visualWidth + expandPixels;
|
|
3491
3818
|
const rulerBottom = offsetY + visualHeight + expandPixels;
|
|
3492
|
-
const
|
|
3493
|
-
const
|
|
3819
|
+
const displayWidthMm = this.dielineWidth + effectiveOffsetMm * 2;
|
|
3820
|
+
const displayHeightMm = this.dielineHeight + effectiveOffsetMm * 2;
|
|
3494
3821
|
const topRulerY = rulerTop - gap;
|
|
3495
3822
|
const topRulerXStart = rulerLeft;
|
|
3496
3823
|
const topRulerXEnd = rulerRight;
|
|
@@ -3533,8 +3860,8 @@ var RulerTool = class {
|
|
|
3533
3860
|
}
|
|
3534
3861
|
)
|
|
3535
3862
|
);
|
|
3536
|
-
const widthStr =
|
|
3537
|
-
const topTextContent = `${widthStr} ${this.
|
|
3863
|
+
const widthStr = formatMm(displayWidthMm, this.dielineDisplayUnit);
|
|
3864
|
+
const topTextContent = `${widthStr} ${this.dielineDisplayUnit}`;
|
|
3538
3865
|
const topText = new import_fabric7.Text(topTextContent, {
|
|
3539
3866
|
left: topRulerXStart + (rulerRight - rulerLeft) / 2,
|
|
3540
3867
|
top: topRulerY,
|
|
@@ -3589,8 +3916,8 @@ var RulerTool = class {
|
|
|
3589
3916
|
}
|
|
3590
3917
|
)
|
|
3591
3918
|
);
|
|
3592
|
-
const heightStr =
|
|
3593
|
-
const leftTextContent = `${heightStr} ${this.
|
|
3919
|
+
const heightStr = formatMm(displayHeightMm, this.dielineDisplayUnit);
|
|
3920
|
+
const leftTextContent = `${heightStr} ${this.dielineDisplayUnit}`;
|
|
3594
3921
|
const leftText = new import_fabric7.Text(leftTextContent, {
|
|
3595
3922
|
left: leftRulerX,
|
|
3596
3923
|
top: leftRulerYStart + (rulerBottom - rulerTop) / 2,
|
|
@@ -3702,6 +4029,81 @@ var MirrorTool = class {
|
|
|
3702
4029
|
|
|
3703
4030
|
// src/CanvasService.ts
|
|
3704
4031
|
var import_fabric8 = require("fabric");
|
|
4032
|
+
|
|
4033
|
+
// src/ViewportSystem.ts
|
|
4034
|
+
var ViewportSystem = class {
|
|
4035
|
+
constructor(containerSize = { width: 0, height: 0 }, physicalSize = { width: 0, height: 0 }, padding = 40) {
|
|
4036
|
+
this._containerSize = { width: 0, height: 0 };
|
|
4037
|
+
this._physicalSize = { width: 0, height: 0 };
|
|
4038
|
+
this._padding = 0;
|
|
4039
|
+
this._layout = {
|
|
4040
|
+
scale: 1,
|
|
4041
|
+
offsetX: 0,
|
|
4042
|
+
offsetY: 0,
|
|
4043
|
+
width: 0,
|
|
4044
|
+
height: 0
|
|
4045
|
+
};
|
|
4046
|
+
this._containerSize = containerSize;
|
|
4047
|
+
this._physicalSize = physicalSize;
|
|
4048
|
+
this._padding = padding;
|
|
4049
|
+
this.updateLayout();
|
|
4050
|
+
}
|
|
4051
|
+
get layout() {
|
|
4052
|
+
return this._layout;
|
|
4053
|
+
}
|
|
4054
|
+
get scale() {
|
|
4055
|
+
return this._layout.scale;
|
|
4056
|
+
}
|
|
4057
|
+
get offset() {
|
|
4058
|
+
return { x: this._layout.offsetX, y: this._layout.offsetY };
|
|
4059
|
+
}
|
|
4060
|
+
updateContainer(width, height) {
|
|
4061
|
+
if (this._containerSize.width === width && this._containerSize.height === height)
|
|
4062
|
+
return;
|
|
4063
|
+
this._containerSize = { width, height };
|
|
4064
|
+
this.updateLayout();
|
|
4065
|
+
}
|
|
4066
|
+
updatePhysical(width, height) {
|
|
4067
|
+
if (this._physicalSize.width === width && this._physicalSize.height === height)
|
|
4068
|
+
return;
|
|
4069
|
+
this._physicalSize = { width, height };
|
|
4070
|
+
this.updateLayout();
|
|
4071
|
+
}
|
|
4072
|
+
setPadding(padding) {
|
|
4073
|
+
if (this._padding === padding) return;
|
|
4074
|
+
this._padding = padding;
|
|
4075
|
+
this.updateLayout();
|
|
4076
|
+
}
|
|
4077
|
+
updateLayout() {
|
|
4078
|
+
this._layout = Coordinate.calculateLayout(
|
|
4079
|
+
this._containerSize,
|
|
4080
|
+
this._physicalSize,
|
|
4081
|
+
this._padding
|
|
4082
|
+
);
|
|
4083
|
+
}
|
|
4084
|
+
toPixel(value) {
|
|
4085
|
+
return value * this._layout.scale;
|
|
4086
|
+
}
|
|
4087
|
+
toPhysical(value) {
|
|
4088
|
+
return this._layout.scale === 0 ? 0 : value / this._layout.scale;
|
|
4089
|
+
}
|
|
4090
|
+
toPixelPoint(point) {
|
|
4091
|
+
return {
|
|
4092
|
+
x: point.x * this._layout.scale + this._layout.offsetX,
|
|
4093
|
+
y: point.y * this._layout.scale + this._layout.offsetY
|
|
4094
|
+
};
|
|
4095
|
+
}
|
|
4096
|
+
// Convert screen coordinate (e.g. mouse event) to physical coordinate (relative to content origin)
|
|
4097
|
+
toPhysicalPoint(point) {
|
|
4098
|
+
if (this._layout.scale === 0) return { x: 0, y: 0 };
|
|
4099
|
+
return {
|
|
4100
|
+
x: (point.x - this._layout.offsetX) / this._layout.scale,
|
|
4101
|
+
y: (point.y - this._layout.offsetY) / this._layout.scale
|
|
4102
|
+
};
|
|
4103
|
+
}
|
|
4104
|
+
};
|
|
4105
|
+
|
|
4106
|
+
// src/CanvasService.ts
|
|
3705
4107
|
var CanvasService = class {
|
|
3706
4108
|
constructor(el, options) {
|
|
3707
4109
|
if (el instanceof import_fabric8.Canvas) {
|
|
@@ -3712,6 +4114,10 @@ var CanvasService = class {
|
|
|
3712
4114
|
...options
|
|
3713
4115
|
});
|
|
3714
4116
|
}
|
|
4117
|
+
this.viewport = new ViewportSystem();
|
|
4118
|
+
if (this.canvas.width !== void 0 && this.canvas.height !== void 0) {
|
|
4119
|
+
this.viewport.updateContainer(this.canvas.width, this.canvas.height);
|
|
4120
|
+
}
|
|
3715
4121
|
if (options == null ? void 0 : options.eventBus) {
|
|
3716
4122
|
this.setEventBus(options.eventBus);
|
|
3717
4123
|
}
|
|
@@ -3792,5 +4198,7 @@ var CanvasService = class {
|
|
|
3792
4198
|
ImageTool,
|
|
3793
4199
|
MirrorTool,
|
|
3794
4200
|
RulerTool,
|
|
3795
|
-
WhiteInkTool
|
|
4201
|
+
WhiteInkTool,
|
|
4202
|
+
formatMm,
|
|
4203
|
+
parseLengthToMm
|
|
3796
4204
|
});
|