@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.mjs
CHANGED
|
@@ -677,6 +677,29 @@ var Coordinate = class {
|
|
|
677
677
|
}
|
|
678
678
|
};
|
|
679
679
|
|
|
680
|
+
// src/units.ts
|
|
681
|
+
function parseLengthToMm(input, defaultUnit) {
|
|
682
|
+
var _a, _b;
|
|
683
|
+
if (typeof input === "number") {
|
|
684
|
+
if (!Number.isFinite(input)) return 0;
|
|
685
|
+
return Coordinate.convertUnit(input, defaultUnit, "mm");
|
|
686
|
+
}
|
|
687
|
+
const raw = input.trim();
|
|
688
|
+
if (!raw) return 0;
|
|
689
|
+
const match = raw.match(/^([+-]?\d+(?:\.\d+)?)\s*(px|mm|cm|in)?$/i);
|
|
690
|
+
if (!match) return 0;
|
|
691
|
+
const value = Number(match[1]);
|
|
692
|
+
if (!Number.isFinite(value)) return 0;
|
|
693
|
+
const unit = (_b = (_a = match[2]) == null ? void 0 : _a.toLowerCase()) != null ? _b : defaultUnit;
|
|
694
|
+
return Coordinate.convertUnit(value, unit, "mm");
|
|
695
|
+
}
|
|
696
|
+
function formatMm(valueMm, displayUnit, fractionDigits = 2) {
|
|
697
|
+
if (!Number.isFinite(valueMm)) return "0";
|
|
698
|
+
const value = Coordinate.convertUnit(valueMm, "mm", displayUnit);
|
|
699
|
+
const rounded = Number(value.toFixed(fractionDigits));
|
|
700
|
+
return rounded.toString();
|
|
701
|
+
}
|
|
702
|
+
|
|
680
703
|
// src/geometry.ts
|
|
681
704
|
import paper2 from "paper";
|
|
682
705
|
function resolveFeaturePosition(feature, geometry) {
|
|
@@ -758,7 +781,7 @@ function getPerimeterShape(options) {
|
|
|
758
781
|
const { features } = options;
|
|
759
782
|
if (features && features.length > 0) {
|
|
760
783
|
const edgeFeatures = features.filter(
|
|
761
|
-
(f) => !f.
|
|
784
|
+
(f) => !f.renderBehavior || f.renderBehavior === "edge"
|
|
762
785
|
);
|
|
763
786
|
const adds = [];
|
|
764
787
|
const subtracts = [];
|
|
@@ -766,10 +789,78 @@ function getPerimeterShape(options) {
|
|
|
766
789
|
const pos = resolveFeaturePosition(f, options);
|
|
767
790
|
const center = new paper2.Point(pos.x, pos.y);
|
|
768
791
|
const item = createFeatureItem(f, center);
|
|
769
|
-
if (f.
|
|
770
|
-
|
|
792
|
+
if (f.bridge && f.bridge.type === "vertical") {
|
|
793
|
+
const itemBounds = item.bounds;
|
|
794
|
+
const mainBounds = mainShape.bounds;
|
|
795
|
+
const bridgeTop = mainBounds.top;
|
|
796
|
+
const bridgeBottom = itemBounds.top;
|
|
797
|
+
if (bridgeBottom > bridgeTop) {
|
|
798
|
+
const startY = bridgeBottom + 1;
|
|
799
|
+
const bridgeRect = new paper2.Path.Rectangle({
|
|
800
|
+
from: [itemBounds.left, bridgeTop],
|
|
801
|
+
to: [itemBounds.right, startY],
|
|
802
|
+
insert: false
|
|
803
|
+
});
|
|
804
|
+
const gaps = bridgeRect.subtract(mainShape);
|
|
805
|
+
bridgeRect.remove();
|
|
806
|
+
let bridgePart = null;
|
|
807
|
+
const isBottomPart = (part) => {
|
|
808
|
+
return Math.abs(part.bounds.bottom - startY) < 2;
|
|
809
|
+
};
|
|
810
|
+
if (gaps instanceof paper2.CompoundPath) {
|
|
811
|
+
const children = gaps.children;
|
|
812
|
+
let maxBottom = -Infinity;
|
|
813
|
+
let bestChild = null;
|
|
814
|
+
for (const child of children) {
|
|
815
|
+
if (child.bounds.bottom > maxBottom) {
|
|
816
|
+
maxBottom = child.bounds.bottom;
|
|
817
|
+
bestChild = child;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
if (bestChild && isBottomPart(bestChild)) {
|
|
821
|
+
bridgePart = bestChild.clone();
|
|
822
|
+
}
|
|
823
|
+
} else if (gaps instanceof paper2.Path) {
|
|
824
|
+
if (isBottomPart(gaps)) {
|
|
825
|
+
bridgePart = gaps.clone();
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
gaps.remove();
|
|
829
|
+
if (bridgePart) {
|
|
830
|
+
const bounds = bridgePart.bounds;
|
|
831
|
+
if (bounds.height > 0) {
|
|
832
|
+
const overlap = 1;
|
|
833
|
+
const scaleY = (bounds.height + overlap) / bounds.height;
|
|
834
|
+
bridgePart.scale(1, scaleY, new paper2.Point(bounds.center.x, bounds.bottom));
|
|
835
|
+
}
|
|
836
|
+
const unitedItem = item.unite(bridgePart);
|
|
837
|
+
item.remove();
|
|
838
|
+
bridgePart.remove();
|
|
839
|
+
if (f.operation === "add") {
|
|
840
|
+
adds.push(unitedItem);
|
|
841
|
+
} else {
|
|
842
|
+
subtracts.push(unitedItem);
|
|
843
|
+
}
|
|
844
|
+
} else {
|
|
845
|
+
if (f.operation === "add") {
|
|
846
|
+
adds.push(item);
|
|
847
|
+
} else {
|
|
848
|
+
subtracts.push(item);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
} else {
|
|
852
|
+
if (f.operation === "add") {
|
|
853
|
+
adds.push(item);
|
|
854
|
+
} else {
|
|
855
|
+
subtracts.push(item);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
771
858
|
} else {
|
|
772
|
-
|
|
859
|
+
if (f.operation === "add") {
|
|
860
|
+
adds.push(item);
|
|
861
|
+
} else {
|
|
862
|
+
subtracts.push(item);
|
|
863
|
+
}
|
|
773
864
|
}
|
|
774
865
|
});
|
|
775
866
|
if (adds.length > 0) {
|
|
@@ -802,10 +893,12 @@ function getPerimeterShape(options) {
|
|
|
802
893
|
return mainShape;
|
|
803
894
|
}
|
|
804
895
|
function applySurfaceFeatures(shape, features, options) {
|
|
805
|
-
const
|
|
806
|
-
|
|
896
|
+
const surfaceFeatures = features.filter(
|
|
897
|
+
(f) => f.renderBehavior === "surface"
|
|
898
|
+
);
|
|
899
|
+
if (surfaceFeatures.length === 0) return shape;
|
|
807
900
|
let result = shape;
|
|
808
|
-
for (const f of
|
|
901
|
+
for (const f of surfaceFeatures) {
|
|
809
902
|
const pos = resolveFeaturePosition(f, options);
|
|
810
903
|
const center = new paper2.Point(pos.x, pos.y);
|
|
811
904
|
const item = createFeatureItem(f, center);
|
|
@@ -862,9 +955,17 @@ function generateBleedZonePath(originalOptions, offsetOptions, offset) {
|
|
|
862
955
|
ensurePaper(paperWidth, paperHeight);
|
|
863
956
|
paper2.project.activeLayer.removeChildren();
|
|
864
957
|
const pOriginal = getPerimeterShape(originalOptions);
|
|
865
|
-
const shapeOriginal = applySurfaceFeatures(
|
|
958
|
+
const shapeOriginal = applySurfaceFeatures(
|
|
959
|
+
pOriginal,
|
|
960
|
+
originalOptions.features,
|
|
961
|
+
originalOptions
|
|
962
|
+
);
|
|
866
963
|
const pOffset = getPerimeterShape(offsetOptions);
|
|
867
|
-
const shapeOffset = applySurfaceFeatures(
|
|
964
|
+
const shapeOffset = applySurfaceFeatures(
|
|
965
|
+
pOffset,
|
|
966
|
+
offsetOptions.features,
|
|
967
|
+
offsetOptions
|
|
968
|
+
);
|
|
868
969
|
let bleedZone;
|
|
869
970
|
if (offset > 0) {
|
|
870
971
|
bleedZone = shapeOffset.subtract(shapeOriginal);
|
|
@@ -877,13 +978,29 @@ function generateBleedZonePath(originalOptions, offsetOptions, offset) {
|
|
|
877
978
|
bleedZone.remove();
|
|
878
979
|
return pathData;
|
|
879
980
|
}
|
|
981
|
+
function getLowestPointOnDieline(options) {
|
|
982
|
+
ensurePaper(options.width * 2, options.height * 2);
|
|
983
|
+
paper2.project.activeLayer.removeChildren();
|
|
984
|
+
const shape = createBaseShape(options);
|
|
985
|
+
const bounds = shape.bounds;
|
|
986
|
+
const result = {
|
|
987
|
+
x: bounds.center.x,
|
|
988
|
+
y: bounds.bottom
|
|
989
|
+
};
|
|
990
|
+
shape.remove();
|
|
991
|
+
return result;
|
|
992
|
+
}
|
|
880
993
|
function getNearestPointOnDieline(point, options) {
|
|
881
994
|
ensurePaper(options.width * 2, options.height * 2);
|
|
882
995
|
paper2.project.activeLayer.removeChildren();
|
|
883
996
|
const shape = createBaseShape(options);
|
|
884
997
|
const p = new paper2.Point(point.x, point.y);
|
|
885
|
-
const
|
|
886
|
-
const result = {
|
|
998
|
+
const location = shape.getNearestLocation(p);
|
|
999
|
+
const result = {
|
|
1000
|
+
x: location.point.x,
|
|
1001
|
+
y: location.point.y,
|
|
1002
|
+
normal: location.normal ? { x: location.normal.x, y: location.normal.y } : void 0
|
|
1003
|
+
};
|
|
887
1004
|
shape.remove();
|
|
888
1005
|
return result;
|
|
889
1006
|
}
|
|
@@ -900,105 +1017,6 @@ function getPathBounds(pathData) {
|
|
|
900
1017
|
};
|
|
901
1018
|
}
|
|
902
1019
|
|
|
903
|
-
// src/constraints.ts
|
|
904
|
-
var ConstraintRegistry = class {
|
|
905
|
-
static register(type, handler) {
|
|
906
|
-
this.handlers.set(type, handler);
|
|
907
|
-
}
|
|
908
|
-
static apply(x, y, feature, context) {
|
|
909
|
-
if (!feature.constraints || !feature.constraints.type) {
|
|
910
|
-
return { x, y };
|
|
911
|
-
}
|
|
912
|
-
const handler = this.handlers.get(feature.constraints.type);
|
|
913
|
-
if (handler) {
|
|
914
|
-
return handler(x, y, feature, context);
|
|
915
|
-
}
|
|
916
|
-
return { x, y };
|
|
917
|
-
}
|
|
918
|
-
};
|
|
919
|
-
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
920
|
-
var edgeConstraint = (x, y, feature, context) => {
|
|
921
|
-
var _a;
|
|
922
|
-
const { dielineWidth, dielineHeight } = context;
|
|
923
|
-
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
924
|
-
const allowedEdges = params.allowedEdges || [
|
|
925
|
-
"top",
|
|
926
|
-
"bottom",
|
|
927
|
-
"left",
|
|
928
|
-
"right"
|
|
929
|
-
];
|
|
930
|
-
const confine = params.confine || false;
|
|
931
|
-
const offset = params.offset || 0;
|
|
932
|
-
const distances = [];
|
|
933
|
-
if (allowedEdges.includes("top"))
|
|
934
|
-
distances.push({ edge: "top", dist: y * dielineHeight });
|
|
935
|
-
if (allowedEdges.includes("bottom"))
|
|
936
|
-
distances.push({ edge: "bottom", dist: (1 - y) * dielineHeight });
|
|
937
|
-
if (allowedEdges.includes("left"))
|
|
938
|
-
distances.push({ edge: "left", dist: x * dielineWidth });
|
|
939
|
-
if (allowedEdges.includes("right"))
|
|
940
|
-
distances.push({ edge: "right", dist: (1 - x) * dielineWidth });
|
|
941
|
-
if (distances.length === 0) return { x, y };
|
|
942
|
-
distances.sort((a, b) => a.dist - b.dist);
|
|
943
|
-
const nearest = distances[0].edge;
|
|
944
|
-
let newX = x;
|
|
945
|
-
let newY = y;
|
|
946
|
-
const fw = feature.width || 0;
|
|
947
|
-
const fh = feature.height || 0;
|
|
948
|
-
switch (nearest) {
|
|
949
|
-
case "top":
|
|
950
|
-
newY = 0 + offset / dielineHeight;
|
|
951
|
-
if (confine) {
|
|
952
|
-
const minX = fw / 2 / dielineWidth;
|
|
953
|
-
const maxX = 1 - minX;
|
|
954
|
-
newX = Math.max(minX, Math.min(newX, maxX));
|
|
955
|
-
}
|
|
956
|
-
break;
|
|
957
|
-
case "bottom":
|
|
958
|
-
newY = 1 - offset / dielineHeight;
|
|
959
|
-
if (confine) {
|
|
960
|
-
const minX = fw / 2 / dielineWidth;
|
|
961
|
-
const maxX = 1 - minX;
|
|
962
|
-
newX = Math.max(minX, Math.min(newX, maxX));
|
|
963
|
-
}
|
|
964
|
-
break;
|
|
965
|
-
case "left":
|
|
966
|
-
newX = 0 + offset / dielineWidth;
|
|
967
|
-
if (confine) {
|
|
968
|
-
const minY = fh / 2 / dielineHeight;
|
|
969
|
-
const maxY = 1 - minY;
|
|
970
|
-
newY = Math.max(minY, Math.min(newY, maxY));
|
|
971
|
-
}
|
|
972
|
-
break;
|
|
973
|
-
case "right":
|
|
974
|
-
newX = 1 - offset / dielineWidth;
|
|
975
|
-
if (confine) {
|
|
976
|
-
const minY = fh / 2 / dielineHeight;
|
|
977
|
-
const maxY = 1 - minY;
|
|
978
|
-
newY = Math.max(minY, Math.min(newY, maxY));
|
|
979
|
-
}
|
|
980
|
-
break;
|
|
981
|
-
}
|
|
982
|
-
return { x: newX, y: newY };
|
|
983
|
-
};
|
|
984
|
-
var internalConstraint = (x, y, feature, context) => {
|
|
985
|
-
var _a;
|
|
986
|
-
const { dielineWidth, dielineHeight } = context;
|
|
987
|
-
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
988
|
-
const margin = params.margin || 0;
|
|
989
|
-
const fw = feature.width || 0;
|
|
990
|
-
const fh = feature.height || 0;
|
|
991
|
-
const minX = (margin + fw / 2) / dielineWidth;
|
|
992
|
-
const maxX = 1 - (margin + fw / 2) / dielineWidth;
|
|
993
|
-
const minY = (margin + fh / 2) / dielineHeight;
|
|
994
|
-
const maxY = 1 - (margin + fh / 2) / dielineHeight;
|
|
995
|
-
const clampedX = minX > maxX ? 0.5 : Math.max(minX, Math.min(x, maxX));
|
|
996
|
-
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
997
|
-
return { x: clampedX, y: clampedY };
|
|
998
|
-
};
|
|
999
|
-
ConstraintRegistry.register("edge", edgeConstraint);
|
|
1000
|
-
ConstraintRegistry.register("internal", internalConstraint);
|
|
1001
|
-
|
|
1002
1020
|
// src/dieline.ts
|
|
1003
1021
|
var DielineTool = class {
|
|
1004
1022
|
constructor(options) {
|
|
@@ -1007,7 +1025,7 @@ var DielineTool = class {
|
|
|
1007
1025
|
name: "DielineTool"
|
|
1008
1026
|
};
|
|
1009
1027
|
this.state = {
|
|
1010
|
-
|
|
1028
|
+
displayUnit: "mm",
|
|
1011
1029
|
shape: "rect",
|
|
1012
1030
|
width: 500,
|
|
1013
1031
|
height: 500,
|
|
@@ -1053,50 +1071,88 @@ var DielineTool = class {
|
|
|
1053
1071
|
const configService = context.services.get("ConfigurationService");
|
|
1054
1072
|
if (configService) {
|
|
1055
1073
|
const s = this.state;
|
|
1056
|
-
s.
|
|
1074
|
+
s.displayUnit = configService.get("dieline.displayUnit", s.displayUnit);
|
|
1057
1075
|
s.shape = configService.get("dieline.shape", s.shape);
|
|
1058
|
-
s.width =
|
|
1059
|
-
|
|
1060
|
-
|
|
1076
|
+
s.width = parseLengthToMm(
|
|
1077
|
+
configService.get("dieline.width", s.width),
|
|
1078
|
+
"mm"
|
|
1079
|
+
);
|
|
1080
|
+
s.height = parseLengthToMm(
|
|
1081
|
+
configService.get("dieline.height", s.height),
|
|
1082
|
+
"mm"
|
|
1083
|
+
);
|
|
1084
|
+
s.radius = parseLengthToMm(
|
|
1085
|
+
configService.get("dieline.radius", s.radius),
|
|
1086
|
+
"mm"
|
|
1087
|
+
);
|
|
1061
1088
|
s.padding = configService.get("dieline.padding", s.padding);
|
|
1062
|
-
s.offset =
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1089
|
+
s.offset = parseLengthToMm(
|
|
1090
|
+
configService.get("dieline.offset", s.offset),
|
|
1091
|
+
"mm"
|
|
1092
|
+
);
|
|
1093
|
+
s.mainLine.width = configService.get(
|
|
1094
|
+
"dieline.strokeWidth",
|
|
1095
|
+
s.mainLine.width
|
|
1096
|
+
);
|
|
1097
|
+
s.mainLine.color = configService.get(
|
|
1098
|
+
"dieline.strokeColor",
|
|
1099
|
+
s.mainLine.color
|
|
1100
|
+
);
|
|
1101
|
+
s.mainLine.dashLength = configService.get(
|
|
1102
|
+
"dieline.dashLength",
|
|
1103
|
+
s.mainLine.dashLength
|
|
1104
|
+
);
|
|
1066
1105
|
s.mainLine.style = configService.get("dieline.style", s.mainLine.style);
|
|
1067
|
-
s.offsetLine.width = configService.get(
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1106
|
+
s.offsetLine.width = configService.get(
|
|
1107
|
+
"dieline.offsetStrokeWidth",
|
|
1108
|
+
s.offsetLine.width
|
|
1109
|
+
);
|
|
1110
|
+
s.offsetLine.color = configService.get(
|
|
1111
|
+
"dieline.offsetStrokeColor",
|
|
1112
|
+
s.offsetLine.color
|
|
1113
|
+
);
|
|
1114
|
+
s.offsetLine.dashLength = configService.get(
|
|
1115
|
+
"dieline.offsetDashLength",
|
|
1116
|
+
s.offsetLine.dashLength
|
|
1117
|
+
);
|
|
1118
|
+
s.offsetLine.style = configService.get(
|
|
1119
|
+
"dieline.offsetStyle",
|
|
1120
|
+
s.offsetLine.style
|
|
1121
|
+
);
|
|
1071
1122
|
s.insideColor = configService.get("dieline.insideColor", s.insideColor);
|
|
1072
|
-
s.outsideColor = configService.get(
|
|
1073
|
-
|
|
1123
|
+
s.outsideColor = configService.get(
|
|
1124
|
+
"dieline.outsideColor",
|
|
1125
|
+
s.outsideColor
|
|
1126
|
+
);
|
|
1127
|
+
s.showBleedLines = configService.get(
|
|
1128
|
+
"dieline.showBleedLines",
|
|
1129
|
+
s.showBleedLines
|
|
1130
|
+
);
|
|
1074
1131
|
s.features = configService.get("dieline.features", s.features);
|
|
1075
1132
|
s.pathData = configService.get("dieline.pathData", s.pathData);
|
|
1076
1133
|
configService.onAnyChange((e) => {
|
|
1077
1134
|
if (e.key.startsWith("dieline.")) {
|
|
1078
|
-
console.log(`[DielineTool] Config change detected: ${e.key} -> ${e.value}`);
|
|
1079
1135
|
switch (e.key) {
|
|
1080
|
-
case "dieline.
|
|
1081
|
-
s.
|
|
1136
|
+
case "dieline.displayUnit":
|
|
1137
|
+
s.displayUnit = e.value;
|
|
1082
1138
|
break;
|
|
1083
1139
|
case "dieline.shape":
|
|
1084
1140
|
s.shape = e.value;
|
|
1085
1141
|
break;
|
|
1086
1142
|
case "dieline.width":
|
|
1087
|
-
s.width = e.value;
|
|
1143
|
+
s.width = parseLengthToMm(e.value, "mm");
|
|
1088
1144
|
break;
|
|
1089
1145
|
case "dieline.height":
|
|
1090
|
-
s.height = e.value;
|
|
1146
|
+
s.height = parseLengthToMm(e.value, "mm");
|
|
1091
1147
|
break;
|
|
1092
1148
|
case "dieline.radius":
|
|
1093
|
-
s.radius = e.value;
|
|
1149
|
+
s.radius = parseLengthToMm(e.value, "mm");
|
|
1094
1150
|
break;
|
|
1095
1151
|
case "dieline.padding":
|
|
1096
1152
|
s.padding = e.value;
|
|
1097
1153
|
break;
|
|
1098
1154
|
case "dieline.offset":
|
|
1099
|
-
s.offset = e.value;
|
|
1155
|
+
s.offset = parseLengthToMm(e.value, "mm");
|
|
1100
1156
|
break;
|
|
1101
1157
|
case "dieline.strokeWidth":
|
|
1102
1158
|
s.mainLine.width = e.value;
|
|
@@ -1155,11 +1211,11 @@ var DielineTool = class {
|
|
|
1155
1211
|
return {
|
|
1156
1212
|
[ContributionPointIds2.CONFIGURATIONS]: [
|
|
1157
1213
|
{
|
|
1158
|
-
id: "dieline.
|
|
1214
|
+
id: "dieline.displayUnit",
|
|
1159
1215
|
type: "select",
|
|
1160
|
-
label: "Unit",
|
|
1161
|
-
options: ["
|
|
1162
|
-
default: s.
|
|
1216
|
+
label: "Display Unit",
|
|
1217
|
+
options: ["mm", "cm", "in"],
|
|
1218
|
+
default: s.displayUnit
|
|
1163
1219
|
},
|
|
1164
1220
|
{
|
|
1165
1221
|
id: "dieline.shape",
|
|
@@ -1171,7 +1227,7 @@ var DielineTool = class {
|
|
|
1171
1227
|
{
|
|
1172
1228
|
id: "dieline.width",
|
|
1173
1229
|
type: "number",
|
|
1174
|
-
label: "Width",
|
|
1230
|
+
label: "Width (mm)",
|
|
1175
1231
|
min: 10,
|
|
1176
1232
|
max: 2e3,
|
|
1177
1233
|
default: s.width
|
|
@@ -1179,7 +1235,7 @@ var DielineTool = class {
|
|
|
1179
1235
|
{
|
|
1180
1236
|
id: "dieline.height",
|
|
1181
1237
|
type: "number",
|
|
1182
|
-
label: "Height",
|
|
1238
|
+
label: "Height (mm)",
|
|
1183
1239
|
min: 10,
|
|
1184
1240
|
max: 2e3,
|
|
1185
1241
|
default: s.height
|
|
@@ -1187,7 +1243,7 @@ var DielineTool = class {
|
|
|
1187
1243
|
{
|
|
1188
1244
|
id: "dieline.radius",
|
|
1189
1245
|
type: "number",
|
|
1190
|
-
label: "Corner Radius",
|
|
1246
|
+
label: "Corner Radius (mm)",
|
|
1191
1247
|
min: 0,
|
|
1192
1248
|
max: 500,
|
|
1193
1249
|
default: s.radius
|
|
@@ -1202,7 +1258,7 @@ var DielineTool = class {
|
|
|
1202
1258
|
{
|
|
1203
1259
|
id: "dieline.offset",
|
|
1204
1260
|
type: "number",
|
|
1205
|
-
label: "Bleed Offset",
|
|
1261
|
+
label: "Bleed Offset (mm)",
|
|
1206
1262
|
min: -100,
|
|
1207
1263
|
max: 100,
|
|
1208
1264
|
default: s.offset
|
|
@@ -1303,18 +1359,12 @@ var DielineTool = class {
|
|
|
1303
1359
|
);
|
|
1304
1360
|
if (!configService) return;
|
|
1305
1361
|
const features = configService.get("dieline.features") || [];
|
|
1306
|
-
const dielineWidth = configService.get("dieline.width") || 500;
|
|
1307
|
-
const dielineHeight = configService.get("dieline.height") || 500;
|
|
1308
1362
|
let changed = false;
|
|
1309
1363
|
const newFeatures = features.map((f) => {
|
|
1310
1364
|
if (f.groupId === groupId) {
|
|
1311
|
-
|
|
1312
|
-
dielineWidth,
|
|
1313
|
-
dielineHeight
|
|
1314
|
-
});
|
|
1315
|
-
if (f.x !== constrained.x || f.y !== constrained.y) {
|
|
1365
|
+
if (f.x !== x || f.y !== y) {
|
|
1316
1366
|
changed = true;
|
|
1317
|
-
return { ...f, x
|
|
1367
|
+
return { ...f, x, y };
|
|
1318
1368
|
}
|
|
1319
1369
|
}
|
|
1320
1370
|
return f;
|
|
@@ -1429,7 +1479,7 @@ var DielineTool = class {
|
|
|
1429
1479
|
const layer = this.getLayer();
|
|
1430
1480
|
if (!layer) return;
|
|
1431
1481
|
const {
|
|
1432
|
-
|
|
1482
|
+
displayUnit,
|
|
1433
1483
|
shape,
|
|
1434
1484
|
radius,
|
|
1435
1485
|
offset,
|
|
@@ -1440,15 +1490,13 @@ var DielineTool = class {
|
|
|
1440
1490
|
showBleedLines,
|
|
1441
1491
|
features
|
|
1442
1492
|
} = this.state;
|
|
1443
|
-
|
|
1493
|
+
const { width, height } = this.state;
|
|
1444
1494
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1445
1495
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1446
1496
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
paddingPx
|
|
1451
|
-
);
|
|
1497
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1498
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1499
|
+
const layout = this.canvasService.viewport.layout;
|
|
1452
1500
|
const scale = layout.scale;
|
|
1453
1501
|
const cx = layout.offsetX + layout.width / 2;
|
|
1454
1502
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1635,15 +1683,22 @@ var DielineTool = class {
|
|
|
1635
1683
|
}
|
|
1636
1684
|
getGeometry() {
|
|
1637
1685
|
if (!this.canvasService) return null;
|
|
1638
|
-
const {
|
|
1686
|
+
const {
|
|
1687
|
+
displayUnit,
|
|
1688
|
+
shape,
|
|
1689
|
+
width,
|
|
1690
|
+
height,
|
|
1691
|
+
radius,
|
|
1692
|
+
offset,
|
|
1693
|
+
mainLine,
|
|
1694
|
+
pathData
|
|
1695
|
+
} = this.state;
|
|
1639
1696
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1640
1697
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1641
1698
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
paddingPx
|
|
1646
|
-
);
|
|
1699
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1700
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1701
|
+
const layout = this.canvasService.viewport.layout;
|
|
1647
1702
|
const scale = layout.scale;
|
|
1648
1703
|
const cx = layout.offsetX + layout.width / 2;
|
|
1649
1704
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1651,14 +1706,14 @@ var DielineTool = class {
|
|
|
1651
1706
|
const visualHeight = layout.height;
|
|
1652
1707
|
return {
|
|
1653
1708
|
shape,
|
|
1654
|
-
unit,
|
|
1709
|
+
unit: "mm",
|
|
1710
|
+
displayUnit,
|
|
1655
1711
|
x: cx,
|
|
1656
1712
|
y: cy,
|
|
1657
1713
|
width: visualWidth,
|
|
1658
1714
|
height: visualHeight,
|
|
1659
1715
|
radius: radius * scale,
|
|
1660
1716
|
offset: offset * scale,
|
|
1661
|
-
// Pass scale to help other tools (like FeatureTool) convert units
|
|
1662
1717
|
scale,
|
|
1663
1718
|
strokeWidth: mainLine.width,
|
|
1664
1719
|
pathData
|
|
@@ -1668,15 +1723,13 @@ var DielineTool = class {
|
|
|
1668
1723
|
if (!this.canvasService) return null;
|
|
1669
1724
|
const userLayer = this.canvasService.getLayer("user");
|
|
1670
1725
|
if (!userLayer) return null;
|
|
1671
|
-
const { shape, width, height, radius, features,
|
|
1726
|
+
const { shape, width, height, radius, features, pathData } = this.state;
|
|
1672
1727
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1673
1728
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1674
1729
|
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
paddingPx
|
|
1679
|
-
);
|
|
1730
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
1731
|
+
this.canvasService.viewport.updatePhysical(width, height);
|
|
1732
|
+
const layout = this.canvasService.viewport.layout;
|
|
1680
1733
|
const scale = layout.scale;
|
|
1681
1734
|
const cx = layout.offsetX + layout.width / 2;
|
|
1682
1735
|
const cy = layout.offsetY + layout.height / 2;
|
|
@@ -1895,13 +1948,212 @@ import {
|
|
|
1895
1948
|
ContributionPointIds as ContributionPointIds4
|
|
1896
1949
|
} from "@pooder/core";
|
|
1897
1950
|
import { Circle, Group, Point, Rect as Rect2 } from "fabric";
|
|
1951
|
+
|
|
1952
|
+
// src/constraints.ts
|
|
1953
|
+
var ConstraintRegistry = class {
|
|
1954
|
+
static register(type, handler) {
|
|
1955
|
+
this.handlers.set(type, handler);
|
|
1956
|
+
}
|
|
1957
|
+
static apply(x, y, feature, context, constraints) {
|
|
1958
|
+
const list = constraints || feature.constraints;
|
|
1959
|
+
if (!list || list.length === 0) {
|
|
1960
|
+
return { x, y };
|
|
1961
|
+
}
|
|
1962
|
+
let currentX = x;
|
|
1963
|
+
let currentY = y;
|
|
1964
|
+
for (const constraint of list) {
|
|
1965
|
+
const handler = this.handlers.get(constraint.type);
|
|
1966
|
+
if (handler) {
|
|
1967
|
+
const result = handler(currentX, currentY, feature, context, constraint.params || {});
|
|
1968
|
+
currentX = result.x;
|
|
1969
|
+
currentY = result.y;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
return { x: currentX, y: currentY };
|
|
1973
|
+
}
|
|
1974
|
+
};
|
|
1975
|
+
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
1976
|
+
var pathConstraint = (x, y, feature, context, params) => {
|
|
1977
|
+
const { dielineWidth, dielineHeight, geometry } = context;
|
|
1978
|
+
if (!geometry) return { x, y };
|
|
1979
|
+
const minX = geometry.x - geometry.width / 2;
|
|
1980
|
+
const minY = geometry.y - geometry.height / 2;
|
|
1981
|
+
const absX = minX + x * geometry.width;
|
|
1982
|
+
const absY = minY + y * geometry.height;
|
|
1983
|
+
const nearest = getNearestPointOnDieline(
|
|
1984
|
+
{ x: absX, y: absY },
|
|
1985
|
+
geometry
|
|
1986
|
+
);
|
|
1987
|
+
let finalX = nearest.x;
|
|
1988
|
+
let finalY = nearest.y;
|
|
1989
|
+
const hasOffsetParams = params.minOffset !== void 0 || params.maxOffset !== void 0;
|
|
1990
|
+
if (hasOffsetParams && nearest.normal) {
|
|
1991
|
+
const dx = absX - nearest.x;
|
|
1992
|
+
const dy = absY - nearest.y;
|
|
1993
|
+
const nx2 = nearest.normal.x;
|
|
1994
|
+
const ny2 = nearest.normal.y;
|
|
1995
|
+
const dist = dx * nx2 + dy * ny2;
|
|
1996
|
+
const scale = dielineWidth > 0 ? geometry.width / dielineWidth : 1;
|
|
1997
|
+
const rawMin = params.minOffset !== void 0 ? params.minOffset : 0;
|
|
1998
|
+
const rawMax = params.maxOffset !== void 0 ? params.maxOffset : 0;
|
|
1999
|
+
const minOffset = rawMin * scale;
|
|
2000
|
+
const maxOffset = rawMax * scale;
|
|
2001
|
+
const clampedDist = Math.max(minOffset, Math.min(dist, maxOffset));
|
|
2002
|
+
finalX = nearest.x + nx2 * clampedDist;
|
|
2003
|
+
finalY = nearest.y + ny2 * clampedDist;
|
|
2004
|
+
}
|
|
2005
|
+
const nx = geometry.width > 0 ? (finalX - minX) / geometry.width : 0.5;
|
|
2006
|
+
const ny = geometry.height > 0 ? (finalY - minY) / geometry.height : 0.5;
|
|
2007
|
+
return { x: nx, y: ny };
|
|
2008
|
+
};
|
|
2009
|
+
var edgeConstraint = (x, y, feature, context, params) => {
|
|
2010
|
+
const { dielineWidth, dielineHeight } = context;
|
|
2011
|
+
const allowedEdges = params.allowedEdges || [
|
|
2012
|
+
"top",
|
|
2013
|
+
"bottom",
|
|
2014
|
+
"left",
|
|
2015
|
+
"right"
|
|
2016
|
+
];
|
|
2017
|
+
const confine = params.confine || false;
|
|
2018
|
+
const offset = params.offset || 0;
|
|
2019
|
+
const distances = [];
|
|
2020
|
+
if (allowedEdges.includes("top"))
|
|
2021
|
+
distances.push({ edge: "top", dist: y * dielineHeight });
|
|
2022
|
+
if (allowedEdges.includes("bottom"))
|
|
2023
|
+
distances.push({ edge: "bottom", dist: (1 - y) * dielineHeight });
|
|
2024
|
+
if (allowedEdges.includes("left"))
|
|
2025
|
+
distances.push({ edge: "left", dist: x * dielineWidth });
|
|
2026
|
+
if (allowedEdges.includes("right"))
|
|
2027
|
+
distances.push({ edge: "right", dist: (1 - x) * dielineWidth });
|
|
2028
|
+
if (distances.length === 0) return { x, y };
|
|
2029
|
+
distances.sort((a, b) => a.dist - b.dist);
|
|
2030
|
+
const nearest = distances[0].edge;
|
|
2031
|
+
let newX = x;
|
|
2032
|
+
let newY = y;
|
|
2033
|
+
const fw = feature.width || 0;
|
|
2034
|
+
const fh = feature.height || 0;
|
|
2035
|
+
switch (nearest) {
|
|
2036
|
+
case "top":
|
|
2037
|
+
newY = 0 + offset / dielineHeight;
|
|
2038
|
+
if (confine) {
|
|
2039
|
+
const minX = fw / 2 / dielineWidth;
|
|
2040
|
+
const maxX = 1 - minX;
|
|
2041
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
2042
|
+
}
|
|
2043
|
+
break;
|
|
2044
|
+
case "bottom":
|
|
2045
|
+
newY = 1 - offset / dielineHeight;
|
|
2046
|
+
if (confine) {
|
|
2047
|
+
const minX = fw / 2 / dielineWidth;
|
|
2048
|
+
const maxX = 1 - minX;
|
|
2049
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
2050
|
+
}
|
|
2051
|
+
break;
|
|
2052
|
+
case "left":
|
|
2053
|
+
newX = 0 + offset / dielineWidth;
|
|
2054
|
+
if (confine) {
|
|
2055
|
+
const minY = fh / 2 / dielineHeight;
|
|
2056
|
+
const maxY = 1 - minY;
|
|
2057
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
2058
|
+
}
|
|
2059
|
+
break;
|
|
2060
|
+
case "right":
|
|
2061
|
+
newX = 1 - offset / dielineWidth;
|
|
2062
|
+
if (confine) {
|
|
2063
|
+
const minY = fh / 2 / dielineHeight;
|
|
2064
|
+
const maxY = 1 - minY;
|
|
2065
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
2066
|
+
}
|
|
2067
|
+
break;
|
|
2068
|
+
}
|
|
2069
|
+
return { x: newX, y: newY };
|
|
2070
|
+
};
|
|
2071
|
+
var internalConstraint = (x, y, feature, context, params) => {
|
|
2072
|
+
const { dielineWidth, dielineHeight } = context;
|
|
2073
|
+
const margin = params.margin || 0;
|
|
2074
|
+
const fw = feature.width || 0;
|
|
2075
|
+
const fh = feature.height || 0;
|
|
2076
|
+
const minX = (margin + fw / 2) / dielineWidth;
|
|
2077
|
+
const maxX = 1 - (margin + fw / 2) / dielineWidth;
|
|
2078
|
+
const minY = (margin + fh / 2) / dielineHeight;
|
|
2079
|
+
const maxY = 1 - (margin + fh / 2) / dielineHeight;
|
|
2080
|
+
const clampedX = minX > maxX ? 0.5 : Math.max(minX, Math.min(x, maxX));
|
|
2081
|
+
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
2082
|
+
return { x: clampedX, y: clampedY };
|
|
2083
|
+
};
|
|
2084
|
+
var tangentBottomConstraint = (x, y, feature, context, params) => {
|
|
2085
|
+
const { dielineWidth, dielineHeight } = context;
|
|
2086
|
+
const gap = params.gap || 0;
|
|
2087
|
+
const confineX = params.confineX !== false;
|
|
2088
|
+
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
2089
|
+
const newY = 1 + (extentY + gap) / dielineHeight;
|
|
2090
|
+
let newX = x;
|
|
2091
|
+
if (confineX) {
|
|
2092
|
+
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
2093
|
+
const minX = extentX / dielineWidth;
|
|
2094
|
+
const maxX = 1 - extentX / dielineWidth;
|
|
2095
|
+
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
2096
|
+
}
|
|
2097
|
+
return { x: newX, y: newY };
|
|
2098
|
+
};
|
|
2099
|
+
var lowestTangentConstraint = (x, y, feature, context, params) => {
|
|
2100
|
+
const { dielineWidth, dielineHeight, geometry } = context;
|
|
2101
|
+
if (!geometry) return { x, y };
|
|
2102
|
+
const lowest = getLowestPointOnDieline(geometry);
|
|
2103
|
+
const minY = geometry.y - geometry.height / 2;
|
|
2104
|
+
const normY = (lowest.y - minY) / geometry.height;
|
|
2105
|
+
const gap = params.gap || 0;
|
|
2106
|
+
const confineX = params.confineX !== false;
|
|
2107
|
+
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
2108
|
+
const newY = normY + (extentY + gap) / dielineHeight;
|
|
2109
|
+
let newX = x;
|
|
2110
|
+
if (confineX) {
|
|
2111
|
+
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
2112
|
+
const minX = extentX / dielineWidth;
|
|
2113
|
+
const maxX = 1 - extentX / dielineWidth;
|
|
2114
|
+
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
2115
|
+
}
|
|
2116
|
+
return { x: newX, y: newY };
|
|
2117
|
+
};
|
|
2118
|
+
ConstraintRegistry.register("path", pathConstraint);
|
|
2119
|
+
ConstraintRegistry.register("edge", edgeConstraint);
|
|
2120
|
+
ConstraintRegistry.register("internal", internalConstraint);
|
|
2121
|
+
ConstraintRegistry.register("tangent-bottom", tangentBottomConstraint);
|
|
2122
|
+
ConstraintRegistry.register("lowest-tangent", lowestTangentConstraint);
|
|
2123
|
+
|
|
2124
|
+
// src/featureComplete.ts
|
|
2125
|
+
function validateFeaturesStrict(features, context) {
|
|
2126
|
+
const eps = 1e-6;
|
|
2127
|
+
const issues = [];
|
|
2128
|
+
for (const f of features) {
|
|
2129
|
+
if (!f.constraints || f.constraints.length === 0) continue;
|
|
2130
|
+
const constrained = ConstraintRegistry.apply(f.x, f.y, f, context, f.constraints);
|
|
2131
|
+
if (Math.abs(constrained.x - f.x) > eps || Math.abs(constrained.y - f.y) > eps) {
|
|
2132
|
+
issues.push({
|
|
2133
|
+
featureId: f.id,
|
|
2134
|
+
groupId: f.groupId,
|
|
2135
|
+
reason: "Position violates constraint strategy"
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
return { ok: issues.length === 0, issues: issues.length ? issues : void 0 };
|
|
2140
|
+
}
|
|
2141
|
+
function completeFeaturesStrict(features, context, update) {
|
|
2142
|
+
const validation = validateFeaturesStrict(features, context);
|
|
2143
|
+
if (!validation.ok) return validation;
|
|
2144
|
+
const next = JSON.parse(JSON.stringify(features || []));
|
|
2145
|
+
update(next);
|
|
2146
|
+
return { ok: true };
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
// src/feature.ts
|
|
1898
2150
|
var FeatureTool = class {
|
|
1899
2151
|
constructor(options) {
|
|
1900
2152
|
this.id = "pooder.kit.feature";
|
|
1901
2153
|
this.metadata = {
|
|
1902
2154
|
name: "FeatureTool"
|
|
1903
2155
|
};
|
|
1904
|
-
this.
|
|
2156
|
+
this.workingFeatures = [];
|
|
1905
2157
|
this.isUpdatingConfig = false;
|
|
1906
2158
|
this.isToolActive = false;
|
|
1907
2159
|
this.handleMoving = null;
|
|
@@ -1927,12 +2179,15 @@ var FeatureTool = class {
|
|
|
1927
2179
|
"ConfigurationService"
|
|
1928
2180
|
);
|
|
1929
2181
|
if (configService) {
|
|
1930
|
-
|
|
2182
|
+
const features = configService.get("dieline.features", []) || [];
|
|
2183
|
+
this.workingFeatures = this.cloneFeatures(features);
|
|
1931
2184
|
configService.onAnyChange((e) => {
|
|
1932
2185
|
if (this.isUpdatingConfig) return;
|
|
1933
2186
|
if (e.key === "dieline.features") {
|
|
1934
|
-
|
|
2187
|
+
const next = e.value || [];
|
|
2188
|
+
this.workingFeatures = this.cloneFeatures(next);
|
|
1935
2189
|
this.redraw();
|
|
2190
|
+
this.emitWorkingChange();
|
|
1936
2191
|
}
|
|
1937
2192
|
});
|
|
1938
2193
|
}
|
|
@@ -1990,57 +2245,172 @@ var FeatureTool = class {
|
|
|
1990
2245
|
command: "clearFeatures",
|
|
1991
2246
|
title: "Clear Features",
|
|
1992
2247
|
handler: () => {
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
);
|
|
1997
|
-
if (configService) {
|
|
1998
|
-
configService.update("dieline.features", []);
|
|
1999
|
-
}
|
|
2248
|
+
this.setWorkingFeatures([]);
|
|
2249
|
+
this.redraw();
|
|
2250
|
+
this.emitWorkingChange();
|
|
2000
2251
|
return true;
|
|
2001
2252
|
}
|
|
2253
|
+
},
|
|
2254
|
+
{
|
|
2255
|
+
command: "getWorkingFeatures",
|
|
2256
|
+
title: "Get Working Features",
|
|
2257
|
+
handler: () => {
|
|
2258
|
+
return this.cloneFeatures(this.workingFeatures);
|
|
2259
|
+
}
|
|
2260
|
+
},
|
|
2261
|
+
{
|
|
2262
|
+
command: "setWorkingFeatures",
|
|
2263
|
+
title: "Set Working Features",
|
|
2264
|
+
handler: async (features) => {
|
|
2265
|
+
await this.refreshGeometry();
|
|
2266
|
+
this.setWorkingFeatures(this.cloneFeatures(features || []));
|
|
2267
|
+
this.redraw();
|
|
2268
|
+
this.emitWorkingChange();
|
|
2269
|
+
return { ok: true };
|
|
2270
|
+
}
|
|
2271
|
+
},
|
|
2272
|
+
{
|
|
2273
|
+
command: "updateWorkingGroupPosition",
|
|
2274
|
+
title: "Update Working Group Position",
|
|
2275
|
+
handler: (groupId, x, y) => {
|
|
2276
|
+
return this.updateWorkingGroupPosition(groupId, x, y);
|
|
2277
|
+
}
|
|
2278
|
+
},
|
|
2279
|
+
{
|
|
2280
|
+
command: "completeFeatures",
|
|
2281
|
+
title: "Complete Features",
|
|
2282
|
+
handler: () => {
|
|
2283
|
+
return this.completeFeatures();
|
|
2284
|
+
}
|
|
2002
2285
|
}
|
|
2003
2286
|
]
|
|
2004
2287
|
};
|
|
2005
2288
|
}
|
|
2006
|
-
|
|
2289
|
+
cloneFeatures(features) {
|
|
2290
|
+
return JSON.parse(JSON.stringify(features || []));
|
|
2291
|
+
}
|
|
2292
|
+
emitWorkingChange() {
|
|
2007
2293
|
var _a;
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2294
|
+
(_a = this.context) == null ? void 0 : _a.eventBus.emit("feature:working:change", {
|
|
2295
|
+
features: this.cloneFeatures(this.workingFeatures)
|
|
2296
|
+
});
|
|
2297
|
+
}
|
|
2298
|
+
async refreshGeometry() {
|
|
2299
|
+
if (!this.context) return;
|
|
2300
|
+
const commandService = this.context.services.get("CommandService");
|
|
2301
|
+
if (!commandService) return;
|
|
2302
|
+
try {
|
|
2303
|
+
const g = await Promise.resolve(commandService.executeCommand("getGeometry"));
|
|
2304
|
+
if (g) this.currentGeometry = g;
|
|
2305
|
+
} catch (e) {
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
setWorkingFeatures(next) {
|
|
2309
|
+
this.workingFeatures = next;
|
|
2310
|
+
}
|
|
2311
|
+
updateWorkingGroupPosition(groupId, x, y) {
|
|
2312
|
+
var _a, _b, _c;
|
|
2313
|
+
if (!groupId) return { ok: false };
|
|
2314
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
2315
|
+
if (!configService) return { ok: false };
|
|
2316
|
+
const dielineWidth = parseLengthToMm(
|
|
2317
|
+
(_b = configService.get("dieline.width")) != null ? _b : 500,
|
|
2318
|
+
"mm"
|
|
2319
|
+
);
|
|
2320
|
+
const dielineHeight = parseLengthToMm(
|
|
2321
|
+
(_c = configService.get("dieline.height")) != null ? _c : 500,
|
|
2322
|
+
"mm"
|
|
2323
|
+
);
|
|
2324
|
+
let changed = false;
|
|
2325
|
+
const next = this.workingFeatures.map((f) => {
|
|
2326
|
+
if (f.groupId !== groupId) return f;
|
|
2327
|
+
let nx = x;
|
|
2328
|
+
let ny = y;
|
|
2329
|
+
if (f.constraints && dielineWidth > 0 && dielineHeight > 0) {
|
|
2330
|
+
const constrained = ConstraintRegistry.apply(nx, ny, f, {
|
|
2331
|
+
dielineWidth,
|
|
2332
|
+
dielineHeight
|
|
2333
|
+
});
|
|
2334
|
+
nx = constrained.x;
|
|
2335
|
+
ny = constrained.y;
|
|
2336
|
+
}
|
|
2337
|
+
if (f.x !== nx || f.y !== ny) {
|
|
2338
|
+
changed = true;
|
|
2339
|
+
return { ...f, x: nx, y: ny };
|
|
2340
|
+
}
|
|
2341
|
+
return f;
|
|
2342
|
+
});
|
|
2343
|
+
if (!changed) return { ok: true };
|
|
2344
|
+
this.setWorkingFeatures(next);
|
|
2345
|
+
this.redraw();
|
|
2346
|
+
this.enforceConstraints();
|
|
2347
|
+
this.emitWorkingChange();
|
|
2348
|
+
return { ok: true };
|
|
2349
|
+
}
|
|
2350
|
+
completeFeatures() {
|
|
2351
|
+
var _a, _b, _c;
|
|
2352
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
2353
|
+
if (!configService) {
|
|
2354
|
+
return {
|
|
2355
|
+
ok: false,
|
|
2356
|
+
issues: [
|
|
2357
|
+
{ featureId: "unknown", reason: "ConfigurationService not found" }
|
|
2358
|
+
]
|
|
2359
|
+
};
|
|
2360
|
+
}
|
|
2361
|
+
const dielineWidth = parseLengthToMm(
|
|
2362
|
+
(_b = configService.get("dieline.width")) != null ? _b : 500,
|
|
2363
|
+
"mm"
|
|
2011
2364
|
);
|
|
2012
|
-
const
|
|
2013
|
-
|
|
2365
|
+
const dielineHeight = parseLengthToMm(
|
|
2366
|
+
(_c = configService.get("dieline.height")) != null ? _c : 500,
|
|
2367
|
+
"mm"
|
|
2368
|
+
);
|
|
2369
|
+
const result = completeFeaturesStrict(
|
|
2370
|
+
this.workingFeatures,
|
|
2371
|
+
{ dielineWidth, dielineHeight },
|
|
2372
|
+
(next) => {
|
|
2373
|
+
this.isUpdatingConfig = true;
|
|
2374
|
+
try {
|
|
2375
|
+
configService.update("dieline.features", next);
|
|
2376
|
+
} finally {
|
|
2377
|
+
this.isUpdatingConfig = false;
|
|
2378
|
+
}
|
|
2379
|
+
this.workingFeatures = this.cloneFeatures(next);
|
|
2380
|
+
this.emitWorkingChange();
|
|
2381
|
+
}
|
|
2382
|
+
);
|
|
2383
|
+
if (!result.ok) {
|
|
2384
|
+
return {
|
|
2385
|
+
ok: false,
|
|
2386
|
+
issues: result.issues
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2389
|
+
return { ok: true };
|
|
2390
|
+
}
|
|
2391
|
+
addFeature(type) {
|
|
2392
|
+
if (!this.canvasService) return false;
|
|
2014
2393
|
const newFeature = {
|
|
2015
2394
|
id: Date.now().toString(),
|
|
2016
2395
|
operation: type,
|
|
2017
|
-
placement: "edge",
|
|
2018
2396
|
shape: "rect",
|
|
2019
2397
|
x: 0.5,
|
|
2020
2398
|
y: 0,
|
|
2021
2399
|
// Top edge
|
|
2022
|
-
width:
|
|
2023
|
-
height:
|
|
2024
|
-
rotation: 0
|
|
2400
|
+
width: 10,
|
|
2401
|
+
height: 10,
|
|
2402
|
+
rotation: 0,
|
|
2403
|
+
renderBehavior: "edge",
|
|
2404
|
+
// Default constraint: path (snap to edge)
|
|
2405
|
+
constraints: [{ type: "path" }]
|
|
2025
2406
|
};
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
[]
|
|
2030
|
-
);
|
|
2031
|
-
configService.update("dieline.features", [...current, newFeature]);
|
|
2032
|
-
}
|
|
2407
|
+
this.setWorkingFeatures([...this.workingFeatures || [], newFeature]);
|
|
2408
|
+
this.redraw();
|
|
2409
|
+
this.emitWorkingChange();
|
|
2033
2410
|
return true;
|
|
2034
2411
|
}
|
|
2035
2412
|
addDoubleLayerHole() {
|
|
2036
|
-
var _a;
|
|
2037
2413
|
if (!this.canvasService) return false;
|
|
2038
|
-
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
2039
|
-
"ConfigurationService"
|
|
2040
|
-
);
|
|
2041
|
-
const unit = (configService == null ? void 0 : configService.get("dieline.unit", "mm")) || "mm";
|
|
2042
|
-
const lugRadius = Coordinate.convertUnit(20, "mm", unit);
|
|
2043
|
-
const holeRadius = Coordinate.convertUnit(15, "mm", unit);
|
|
2044
2414
|
const groupId = Date.now().toString();
|
|
2045
2415
|
const timestamp = Date.now();
|
|
2046
2416
|
const lug = {
|
|
@@ -2048,32 +2418,28 @@ var FeatureTool = class {
|
|
|
2048
2418
|
groupId,
|
|
2049
2419
|
operation: "add",
|
|
2050
2420
|
shape: "circle",
|
|
2051
|
-
placement: "edge",
|
|
2052
2421
|
x: 0.5,
|
|
2053
2422
|
y: 0,
|
|
2054
|
-
radius:
|
|
2055
|
-
|
|
2056
|
-
|
|
2423
|
+
radius: 20,
|
|
2424
|
+
rotation: 0,
|
|
2425
|
+
renderBehavior: "edge",
|
|
2426
|
+
constraints: [{ type: "path" }]
|
|
2057
2427
|
};
|
|
2058
2428
|
const hole = {
|
|
2059
2429
|
id: `${timestamp}-hole`,
|
|
2060
2430
|
groupId,
|
|
2061
2431
|
operation: "subtract",
|
|
2062
2432
|
shape: "circle",
|
|
2063
|
-
placement: "edge",
|
|
2064
2433
|
x: 0.5,
|
|
2065
2434
|
y: 0,
|
|
2066
|
-
radius:
|
|
2067
|
-
|
|
2068
|
-
|
|
2435
|
+
radius: 15,
|
|
2436
|
+
rotation: 0,
|
|
2437
|
+
renderBehavior: "edge",
|
|
2438
|
+
constraints: [{ type: "path" }]
|
|
2069
2439
|
};
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
[]
|
|
2074
|
-
);
|
|
2075
|
-
configService.update("dieline.features", [...current, lug, hole]);
|
|
2076
|
-
}
|
|
2440
|
+
this.setWorkingFeatures([...this.workingFeatures || [], lug, hole]);
|
|
2441
|
+
this.redraw();
|
|
2442
|
+
this.emitWorkingChange();
|
|
2077
2443
|
return true;
|
|
2078
2444
|
}
|
|
2079
2445
|
getGeometryForFeature(geometry, feature) {
|
|
@@ -2117,12 +2483,12 @@ var FeatureTool = class {
|
|
|
2117
2483
|
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
2118
2484
|
const indices = (_c = target.data) == null ? void 0 : _c.indices;
|
|
2119
2485
|
if (indices && indices.length > 0) {
|
|
2120
|
-
feature = this.
|
|
2486
|
+
feature = this.workingFeatures[indices[0]];
|
|
2121
2487
|
}
|
|
2122
2488
|
} else {
|
|
2123
2489
|
const index = (_d = target.data) == null ? void 0 : _d.index;
|
|
2124
2490
|
if (index !== void 0) {
|
|
2125
|
-
feature = this.
|
|
2491
|
+
feature = this.workingFeatures[index];
|
|
2126
2492
|
}
|
|
2127
2493
|
}
|
|
2128
2494
|
const geometry = this.getGeometryForFeature(
|
|
@@ -2143,7 +2509,7 @@ var FeatureTool = class {
|
|
|
2143
2509
|
}
|
|
2144
2510
|
if (!this.handleModified) {
|
|
2145
2511
|
this.handleModified = (e) => {
|
|
2146
|
-
var _a, _b, _c
|
|
2512
|
+
var _a, _b, _c;
|
|
2147
2513
|
const target = e.target;
|
|
2148
2514
|
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "feature-marker") return;
|
|
2149
2515
|
if ((_b = target.data) == null ? void 0 : _b.isGroup) {
|
|
@@ -2151,11 +2517,11 @@ var FeatureTool = class {
|
|
|
2151
2517
|
const indices = (_c = groupObj.data) == null ? void 0 : _c.indices;
|
|
2152
2518
|
if (!indices) return;
|
|
2153
2519
|
const groupCenter = new Point(groupObj.left, groupObj.top);
|
|
2154
|
-
const newFeatures = [...this.
|
|
2520
|
+
const newFeatures = [...this.workingFeatures];
|
|
2155
2521
|
const { x, y } = this.currentGeometry;
|
|
2156
2522
|
groupObj.getObjects().forEach((child, i) => {
|
|
2157
2523
|
const originalIndex = indices[i];
|
|
2158
|
-
const feature = this.
|
|
2524
|
+
const feature = this.workingFeatures[originalIndex];
|
|
2159
2525
|
const geometry = this.getGeometryForFeature(
|
|
2160
2526
|
this.currentGeometry,
|
|
2161
2527
|
feature
|
|
@@ -2173,18 +2539,8 @@ var FeatureTool = class {
|
|
|
2173
2539
|
y: normalizedY
|
|
2174
2540
|
};
|
|
2175
2541
|
});
|
|
2176
|
-
this.
|
|
2177
|
-
|
|
2178
|
-
"ConfigurationService"
|
|
2179
|
-
);
|
|
2180
|
-
if (configService) {
|
|
2181
|
-
this.isUpdatingConfig = true;
|
|
2182
|
-
try {
|
|
2183
|
-
configService.update("dieline.features", this.features);
|
|
2184
|
-
} finally {
|
|
2185
|
-
this.isUpdatingConfig = false;
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2542
|
+
this.setWorkingFeatures(newFeatures);
|
|
2543
|
+
this.emitWorkingChange();
|
|
2188
2544
|
} else {
|
|
2189
2545
|
this.syncFeatureFromCanvas(target);
|
|
2190
2546
|
}
|
|
@@ -2218,56 +2574,41 @@ var FeatureTool = class {
|
|
|
2218
2574
|
this.canvasService.requestRenderAll();
|
|
2219
2575
|
}
|
|
2220
2576
|
constrainPosition(p, geometry, limit, feature) {
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
const minY = geometry.y - geometry.height / 2;
|
|
2224
|
-
const nx = geometry.width > 0 ? (p.x - minX) / geometry.width : 0.5;
|
|
2225
|
-
const ny = geometry.height > 0 ? (p.y - minY) / geometry.height : 0.5;
|
|
2226
|
-
const scale2 = geometry.scale || 1;
|
|
2227
|
-
const dielineWidth = geometry.width / scale2;
|
|
2228
|
-
const dielineHeight = geometry.height / scale2;
|
|
2229
|
-
const constrained = ConstraintRegistry.apply(nx, ny, feature, {
|
|
2230
|
-
dielineWidth,
|
|
2231
|
-
dielineHeight
|
|
2232
|
-
});
|
|
2233
|
-
return {
|
|
2234
|
-
x: minX + constrained.x * geometry.width,
|
|
2235
|
-
y: minY + constrained.y * geometry.height
|
|
2236
|
-
};
|
|
2237
|
-
}
|
|
2238
|
-
if (feature && feature.placement === "internal") {
|
|
2239
|
-
const minX = geometry.x - geometry.width / 2;
|
|
2240
|
-
const maxX = geometry.x + geometry.width / 2;
|
|
2241
|
-
const minY = geometry.y - geometry.height / 2;
|
|
2242
|
-
const maxY = geometry.y + geometry.height / 2;
|
|
2243
|
-
return {
|
|
2244
|
-
x: Math.max(minX, Math.min(maxX, p.x)),
|
|
2245
|
-
y: Math.max(minY, Math.min(maxY, p.y))
|
|
2246
|
-
};
|
|
2247
|
-
}
|
|
2248
|
-
const nearest = getNearestPointOnDieline({ x: p.x, y: p.y }, {
|
|
2249
|
-
...geometry,
|
|
2250
|
-
features: []
|
|
2251
|
-
});
|
|
2252
|
-
const dx = p.x - nearest.x;
|
|
2253
|
-
const dy = p.y - nearest.y;
|
|
2254
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
2255
|
-
if (dist <= limit) {
|
|
2577
|
+
var _a;
|
|
2578
|
+
if (!feature) {
|
|
2256
2579
|
return { x: p.x, y: p.y };
|
|
2257
2580
|
}
|
|
2258
|
-
const
|
|
2581
|
+
const minX = geometry.x - geometry.width / 2;
|
|
2582
|
+
const minY = geometry.y - geometry.height / 2;
|
|
2583
|
+
const nx = geometry.width > 0 ? (p.x - minX) / geometry.width : 0.5;
|
|
2584
|
+
const ny = geometry.height > 0 ? (p.y - minY) / geometry.height : 0.5;
|
|
2585
|
+
const scale = geometry.scale || 1;
|
|
2586
|
+
const dielineWidth = geometry.width / scale;
|
|
2587
|
+
const dielineHeight = geometry.height / scale;
|
|
2588
|
+
const activeConstraints = (_a = feature.constraints) == null ? void 0 : _a.filter((c) => !c.validateOnly);
|
|
2589
|
+
const constrained = ConstraintRegistry.apply(
|
|
2590
|
+
nx,
|
|
2591
|
+
ny,
|
|
2592
|
+
feature,
|
|
2593
|
+
{
|
|
2594
|
+
dielineWidth,
|
|
2595
|
+
dielineHeight,
|
|
2596
|
+
geometry
|
|
2597
|
+
},
|
|
2598
|
+
activeConstraints
|
|
2599
|
+
);
|
|
2259
2600
|
return {
|
|
2260
|
-
x:
|
|
2261
|
-
y:
|
|
2601
|
+
x: minX + constrained.x * geometry.width,
|
|
2602
|
+
y: minY + constrained.y * geometry.height
|
|
2262
2603
|
};
|
|
2263
2604
|
}
|
|
2264
2605
|
syncFeatureFromCanvas(target) {
|
|
2265
2606
|
var _a;
|
|
2266
2607
|
if (!this.currentGeometry || !this.context) return;
|
|
2267
2608
|
const index = (_a = target.data) == null ? void 0 : _a.index;
|
|
2268
|
-
if (index === void 0 || index < 0 || index >= this.
|
|
2609
|
+
if (index === void 0 || index < 0 || index >= this.workingFeatures.length)
|
|
2269
2610
|
return;
|
|
2270
|
-
const feature = this.
|
|
2611
|
+
const feature = this.workingFeatures[index];
|
|
2271
2612
|
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
2272
2613
|
const { width, height, x, y } = geometry;
|
|
2273
2614
|
const left = x - width / 2;
|
|
@@ -2280,20 +2621,10 @@ var FeatureTool = class {
|
|
|
2280
2621
|
y: normalizedY
|
|
2281
2622
|
// Could also update rotation if we allowed rotating markers
|
|
2282
2623
|
};
|
|
2283
|
-
const newFeatures = [...this.
|
|
2624
|
+
const newFeatures = [...this.workingFeatures];
|
|
2284
2625
|
newFeatures[index] = updatedFeature;
|
|
2285
|
-
this.
|
|
2286
|
-
|
|
2287
|
-
"ConfigurationService"
|
|
2288
|
-
);
|
|
2289
|
-
if (configService) {
|
|
2290
|
-
this.isUpdatingConfig = true;
|
|
2291
|
-
try {
|
|
2292
|
-
configService.update("dieline.features", this.features);
|
|
2293
|
-
} finally {
|
|
2294
|
-
this.isUpdatingConfig = false;
|
|
2295
|
-
}
|
|
2296
|
-
}
|
|
2626
|
+
this.setWorkingFeatures(newFeatures);
|
|
2627
|
+
this.emitWorkingChange();
|
|
2297
2628
|
}
|
|
2298
2629
|
redraw() {
|
|
2299
2630
|
if (!this.canvasService || !this.currentGeometry) return;
|
|
@@ -2304,7 +2635,7 @@ var FeatureTool = class {
|
|
|
2304
2635
|
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
2305
2636
|
});
|
|
2306
2637
|
existing.forEach((obj) => canvas.remove(obj));
|
|
2307
|
-
if (!this.
|
|
2638
|
+
if (!this.workingFeatures || this.workingFeatures.length === 0) {
|
|
2308
2639
|
this.canvasService.requestRenderAll();
|
|
2309
2640
|
return;
|
|
2310
2641
|
}
|
|
@@ -2312,7 +2643,7 @@ var FeatureTool = class {
|
|
|
2312
2643
|
const finalScale = scale;
|
|
2313
2644
|
const groups = {};
|
|
2314
2645
|
const singles = [];
|
|
2315
|
-
this.
|
|
2646
|
+
this.workingFeatures.forEach((f, i) => {
|
|
2316
2647
|
if (f.groupId) {
|
|
2317
2648
|
if (!groups[f.groupId]) groups[f.groupId] = [];
|
|
2318
2649
|
groups[f.groupId].push({ feature: f, index: i });
|
|
@@ -2359,6 +2690,33 @@ var FeatureTool = class {
|
|
|
2359
2690
|
if (feature.rotation) {
|
|
2360
2691
|
shape.rotate(feature.rotation);
|
|
2361
2692
|
}
|
|
2693
|
+
if (feature.bridge && feature.bridge.type === "vertical") {
|
|
2694
|
+
const bridgeIndicator = new Rect2({
|
|
2695
|
+
width: visualWidth,
|
|
2696
|
+
height: 100 * featureScale,
|
|
2697
|
+
// Arbitrary long length to show direction
|
|
2698
|
+
fill: "transparent",
|
|
2699
|
+
stroke: "#888",
|
|
2700
|
+
strokeWidth: 1,
|
|
2701
|
+
strokeDashArray: [2, 2],
|
|
2702
|
+
originX: "center",
|
|
2703
|
+
originY: "bottom",
|
|
2704
|
+
// Anchor at bottom so it extends up
|
|
2705
|
+
left: pos.x,
|
|
2706
|
+
top: pos.y - visualHeight / 2,
|
|
2707
|
+
// Start from top of feature
|
|
2708
|
+
opacity: 0.5,
|
|
2709
|
+
selectable: false,
|
|
2710
|
+
evented: false
|
|
2711
|
+
});
|
|
2712
|
+
const group = new Group([bridgeIndicator, shape], {
|
|
2713
|
+
originX: "center",
|
|
2714
|
+
originY: "center",
|
|
2715
|
+
left: pos.x,
|
|
2716
|
+
top: pos.y
|
|
2717
|
+
});
|
|
2718
|
+
return group;
|
|
2719
|
+
}
|
|
2362
2720
|
return shape;
|
|
2363
2721
|
};
|
|
2364
2722
|
singles.forEach(({ feature, index }) => {
|
|
@@ -2380,25 +2738,6 @@ var FeatureTool = class {
|
|
|
2380
2738
|
lockScalingY: true,
|
|
2381
2739
|
data: { type: "feature-marker", index, isGroup: false }
|
|
2382
2740
|
});
|
|
2383
|
-
marker.set("opacity", 0);
|
|
2384
|
-
marker.on("mouseover", () => {
|
|
2385
|
-
marker.set("opacity", 1);
|
|
2386
|
-
canvas.requestRenderAll();
|
|
2387
|
-
});
|
|
2388
|
-
marker.on("mouseout", () => {
|
|
2389
|
-
if (canvas.getActiveObject() !== marker) {
|
|
2390
|
-
marker.set("opacity", 0);
|
|
2391
|
-
canvas.requestRenderAll();
|
|
2392
|
-
}
|
|
2393
|
-
});
|
|
2394
|
-
marker.on("selected", () => {
|
|
2395
|
-
marker.set("opacity", 1);
|
|
2396
|
-
canvas.requestRenderAll();
|
|
2397
|
-
});
|
|
2398
|
-
marker.on("deselected", () => {
|
|
2399
|
-
marker.set("opacity", 0);
|
|
2400
|
-
canvas.requestRenderAll();
|
|
2401
|
-
});
|
|
2402
2741
|
canvas.add(marker);
|
|
2403
2742
|
canvas.bringObjectToFront(marker);
|
|
2404
2743
|
});
|
|
@@ -2435,25 +2774,6 @@ var FeatureTool = class {
|
|
|
2435
2774
|
indices: members.map((m) => m.index)
|
|
2436
2775
|
}
|
|
2437
2776
|
});
|
|
2438
|
-
groupObj.set("opacity", 0);
|
|
2439
|
-
groupObj.on("mouseover", () => {
|
|
2440
|
-
groupObj.set("opacity", 1);
|
|
2441
|
-
canvas.requestRenderAll();
|
|
2442
|
-
});
|
|
2443
|
-
groupObj.on("mouseout", () => {
|
|
2444
|
-
if (canvas.getActiveObject() !== groupObj) {
|
|
2445
|
-
groupObj.set("opacity", 0);
|
|
2446
|
-
canvas.requestRenderAll();
|
|
2447
|
-
}
|
|
2448
|
-
});
|
|
2449
|
-
groupObj.on("selected", () => {
|
|
2450
|
-
groupObj.set("opacity", 1);
|
|
2451
|
-
canvas.requestRenderAll();
|
|
2452
|
-
});
|
|
2453
|
-
groupObj.on("deselected", () => {
|
|
2454
|
-
groupObj.set("opacity", 0);
|
|
2455
|
-
canvas.requestRenderAll();
|
|
2456
|
-
});
|
|
2457
2777
|
canvas.add(groupObj);
|
|
2458
2778
|
canvas.bringObjectToFront(groupObj);
|
|
2459
2779
|
});
|
|
@@ -2472,12 +2792,12 @@ var FeatureTool = class {
|
|
|
2472
2792
|
if ((_a = marker.data) == null ? void 0 : _a.isGroup) {
|
|
2473
2793
|
const indices = (_b = marker.data) == null ? void 0 : _b.indices;
|
|
2474
2794
|
if (indices && indices.length > 0) {
|
|
2475
|
-
feature = this.
|
|
2795
|
+
feature = this.workingFeatures[indices[0]];
|
|
2476
2796
|
}
|
|
2477
2797
|
} else {
|
|
2478
2798
|
const index = (_c = marker.data) == null ? void 0 : _c.index;
|
|
2479
2799
|
if (index !== void 0) {
|
|
2480
|
-
feature = this.
|
|
2800
|
+
feature = this.workingFeatures[index];
|
|
2481
2801
|
}
|
|
2482
2802
|
}
|
|
2483
2803
|
const geometry = this.getGeometryForFeature(
|
|
@@ -3207,7 +3527,7 @@ var RulerTool = class {
|
|
|
3207
3527
|
// Dieline context for sync
|
|
3208
3528
|
this.dielineWidth = 500;
|
|
3209
3529
|
this.dielineHeight = 500;
|
|
3210
|
-
this.
|
|
3530
|
+
this.dielineDisplayUnit = "mm";
|
|
3211
3531
|
this.dielinePadding = 40;
|
|
3212
3532
|
this.dielineOffset = 0;
|
|
3213
3533
|
if (options) {
|
|
@@ -3231,7 +3551,10 @@ var RulerTool = class {
|
|
|
3231
3551
|
this.textColor = configService.get("ruler.textColor", this.textColor);
|
|
3232
3552
|
this.lineColor = configService.get("ruler.lineColor", this.lineColor);
|
|
3233
3553
|
this.fontSize = configService.get("ruler.fontSize", this.fontSize);
|
|
3234
|
-
this.
|
|
3554
|
+
this.dielineDisplayUnit = configService.get(
|
|
3555
|
+
"dieline.displayUnit",
|
|
3556
|
+
this.dielineDisplayUnit
|
|
3557
|
+
);
|
|
3235
3558
|
this.dielineWidth = configService.get("dieline.width", this.dielineWidth);
|
|
3236
3559
|
this.dielineHeight = configService.get(
|
|
3237
3560
|
"dieline.height",
|
|
@@ -3254,7 +3577,8 @@ var RulerTool = class {
|
|
|
3254
3577
|
shouldUpdate = true;
|
|
3255
3578
|
}
|
|
3256
3579
|
} else if (e.key.startsWith("dieline.")) {
|
|
3257
|
-
if (e.key === "dieline.
|
|
3580
|
+
if (e.key === "dieline.displayUnit")
|
|
3581
|
+
this.dielineDisplayUnit = e.value;
|
|
3258
3582
|
if (e.key === "dieline.width") this.dielineWidth = e.value;
|
|
3259
3583
|
if (e.key === "dieline.height") this.dielineHeight = e.value;
|
|
3260
3584
|
if (e.key === "dieline.padding") this.dielinePadding = e.value;
|
|
@@ -3441,26 +3765,27 @@ var RulerTool = class {
|
|
|
3441
3765
|
const width = this.canvasService.canvas.width || 800;
|
|
3442
3766
|
const height = this.canvasService.canvas.height || 600;
|
|
3443
3767
|
const paddingPx = this.resolvePadding(width, height);
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3768
|
+
this.canvasService.viewport.setPadding(paddingPx);
|
|
3769
|
+
this.canvasService.viewport.updatePhysical(
|
|
3770
|
+
this.dielineWidth,
|
|
3771
|
+
this.dielineHeight
|
|
3448
3772
|
);
|
|
3773
|
+
const layout = this.canvasService.viewport.layout;
|
|
3449
3774
|
const scale = layout.scale;
|
|
3450
3775
|
const offsetX = layout.offsetX;
|
|
3451
3776
|
const offsetY = layout.offsetY;
|
|
3452
3777
|
const visualWidth = layout.width;
|
|
3453
3778
|
const visualHeight = layout.height;
|
|
3454
|
-
const
|
|
3455
|
-
const
|
|
3456
|
-
const expandPixels =
|
|
3779
|
+
const rawOffsetMm = this.dielineOffset || 0;
|
|
3780
|
+
const effectiveOffsetMm = rawOffsetMm > 0 ? rawOffsetMm : 0;
|
|
3781
|
+
const expandPixels = effectiveOffsetMm * scale;
|
|
3457
3782
|
const gap = this.gap || 15;
|
|
3458
3783
|
const rulerLeft = offsetX - expandPixels;
|
|
3459
3784
|
const rulerTop = offsetY - expandPixels;
|
|
3460
3785
|
const rulerRight = offsetX + visualWidth + expandPixels;
|
|
3461
3786
|
const rulerBottom = offsetY + visualHeight + expandPixels;
|
|
3462
|
-
const
|
|
3463
|
-
const
|
|
3787
|
+
const displayWidthMm = this.dielineWidth + effectiveOffsetMm * 2;
|
|
3788
|
+
const displayHeightMm = this.dielineHeight + effectiveOffsetMm * 2;
|
|
3464
3789
|
const topRulerY = rulerTop - gap;
|
|
3465
3790
|
const topRulerXStart = rulerLeft;
|
|
3466
3791
|
const topRulerXEnd = rulerRight;
|
|
@@ -3503,8 +3828,8 @@ var RulerTool = class {
|
|
|
3503
3828
|
}
|
|
3504
3829
|
)
|
|
3505
3830
|
);
|
|
3506
|
-
const widthStr =
|
|
3507
|
-
const topTextContent = `${widthStr} ${this.
|
|
3831
|
+
const widthStr = formatMm(displayWidthMm, this.dielineDisplayUnit);
|
|
3832
|
+
const topTextContent = `${widthStr} ${this.dielineDisplayUnit}`;
|
|
3508
3833
|
const topText = new Text(topTextContent, {
|
|
3509
3834
|
left: topRulerXStart + (rulerRight - rulerLeft) / 2,
|
|
3510
3835
|
top: topRulerY,
|
|
@@ -3559,8 +3884,8 @@ var RulerTool = class {
|
|
|
3559
3884
|
}
|
|
3560
3885
|
)
|
|
3561
3886
|
);
|
|
3562
|
-
const heightStr =
|
|
3563
|
-
const leftTextContent = `${heightStr} ${this.
|
|
3887
|
+
const heightStr = formatMm(displayHeightMm, this.dielineDisplayUnit);
|
|
3888
|
+
const leftTextContent = `${heightStr} ${this.dielineDisplayUnit}`;
|
|
3564
3889
|
const leftText = new Text(leftTextContent, {
|
|
3565
3890
|
left: leftRulerX,
|
|
3566
3891
|
top: leftRulerYStart + (rulerBottom - rulerTop) / 2,
|
|
@@ -3674,6 +3999,81 @@ var MirrorTool = class {
|
|
|
3674
3999
|
|
|
3675
4000
|
// src/CanvasService.ts
|
|
3676
4001
|
import { Canvas, Group as Group3 } from "fabric";
|
|
4002
|
+
|
|
4003
|
+
// src/ViewportSystem.ts
|
|
4004
|
+
var ViewportSystem = class {
|
|
4005
|
+
constructor(containerSize = { width: 0, height: 0 }, physicalSize = { width: 0, height: 0 }, padding = 40) {
|
|
4006
|
+
this._containerSize = { width: 0, height: 0 };
|
|
4007
|
+
this._physicalSize = { width: 0, height: 0 };
|
|
4008
|
+
this._padding = 0;
|
|
4009
|
+
this._layout = {
|
|
4010
|
+
scale: 1,
|
|
4011
|
+
offsetX: 0,
|
|
4012
|
+
offsetY: 0,
|
|
4013
|
+
width: 0,
|
|
4014
|
+
height: 0
|
|
4015
|
+
};
|
|
4016
|
+
this._containerSize = containerSize;
|
|
4017
|
+
this._physicalSize = physicalSize;
|
|
4018
|
+
this._padding = padding;
|
|
4019
|
+
this.updateLayout();
|
|
4020
|
+
}
|
|
4021
|
+
get layout() {
|
|
4022
|
+
return this._layout;
|
|
4023
|
+
}
|
|
4024
|
+
get scale() {
|
|
4025
|
+
return this._layout.scale;
|
|
4026
|
+
}
|
|
4027
|
+
get offset() {
|
|
4028
|
+
return { x: this._layout.offsetX, y: this._layout.offsetY };
|
|
4029
|
+
}
|
|
4030
|
+
updateContainer(width, height) {
|
|
4031
|
+
if (this._containerSize.width === width && this._containerSize.height === height)
|
|
4032
|
+
return;
|
|
4033
|
+
this._containerSize = { width, height };
|
|
4034
|
+
this.updateLayout();
|
|
4035
|
+
}
|
|
4036
|
+
updatePhysical(width, height) {
|
|
4037
|
+
if (this._physicalSize.width === width && this._physicalSize.height === height)
|
|
4038
|
+
return;
|
|
4039
|
+
this._physicalSize = { width, height };
|
|
4040
|
+
this.updateLayout();
|
|
4041
|
+
}
|
|
4042
|
+
setPadding(padding) {
|
|
4043
|
+
if (this._padding === padding) return;
|
|
4044
|
+
this._padding = padding;
|
|
4045
|
+
this.updateLayout();
|
|
4046
|
+
}
|
|
4047
|
+
updateLayout() {
|
|
4048
|
+
this._layout = Coordinate.calculateLayout(
|
|
4049
|
+
this._containerSize,
|
|
4050
|
+
this._physicalSize,
|
|
4051
|
+
this._padding
|
|
4052
|
+
);
|
|
4053
|
+
}
|
|
4054
|
+
toPixel(value) {
|
|
4055
|
+
return value * this._layout.scale;
|
|
4056
|
+
}
|
|
4057
|
+
toPhysical(value) {
|
|
4058
|
+
return this._layout.scale === 0 ? 0 : value / this._layout.scale;
|
|
4059
|
+
}
|
|
4060
|
+
toPixelPoint(point) {
|
|
4061
|
+
return {
|
|
4062
|
+
x: point.x * this._layout.scale + this._layout.offsetX,
|
|
4063
|
+
y: point.y * this._layout.scale + this._layout.offsetY
|
|
4064
|
+
};
|
|
4065
|
+
}
|
|
4066
|
+
// Convert screen coordinate (e.g. mouse event) to physical coordinate (relative to content origin)
|
|
4067
|
+
toPhysicalPoint(point) {
|
|
4068
|
+
if (this._layout.scale === 0) return { x: 0, y: 0 };
|
|
4069
|
+
return {
|
|
4070
|
+
x: (point.x - this._layout.offsetX) / this._layout.scale,
|
|
4071
|
+
y: (point.y - this._layout.offsetY) / this._layout.scale
|
|
4072
|
+
};
|
|
4073
|
+
}
|
|
4074
|
+
};
|
|
4075
|
+
|
|
4076
|
+
// src/CanvasService.ts
|
|
3677
4077
|
var CanvasService = class {
|
|
3678
4078
|
constructor(el, options) {
|
|
3679
4079
|
if (el instanceof Canvas) {
|
|
@@ -3684,6 +4084,10 @@ var CanvasService = class {
|
|
|
3684
4084
|
...options
|
|
3685
4085
|
});
|
|
3686
4086
|
}
|
|
4087
|
+
this.viewport = new ViewportSystem();
|
|
4088
|
+
if (this.canvas.width !== void 0 && this.canvas.height !== void 0) {
|
|
4089
|
+
this.viewport.updateContainer(this.canvas.width, this.canvas.height);
|
|
4090
|
+
}
|
|
3687
4091
|
if (options == null ? void 0 : options.eventBus) {
|
|
3688
4092
|
this.setEventBus(options.eventBus);
|
|
3689
4093
|
}
|
|
@@ -3763,5 +4167,7 @@ export {
|
|
|
3763
4167
|
ImageTool,
|
|
3764
4168
|
MirrorTool,
|
|
3765
4169
|
RulerTool,
|
|
3766
|
-
WhiteInkTool
|
|
4170
|
+
WhiteInkTool,
|
|
4171
|
+
formatMm,
|
|
4172
|
+
parseLengthToMm
|
|
3767
4173
|
};
|