@pooder/kit 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/index.d.mts +39 -24
- package/dist/index.d.ts +39 -24
- package/dist/index.js +740 -534
- package/dist/index.mjs +744 -538
- package/package.json +2 -2
- package/src/coordinate.ts +57 -0
- package/src/dieline.ts +186 -129
- package/src/geometry.ts +19 -10
- package/src/hole.ts +88 -31
- package/src/image.ts +334 -365
- package/src/ruler.ts +295 -120
package/dist/index.js
CHANGED
|
@@ -434,6 +434,24 @@ var ImageTracer = class {
|
|
|
434
434
|
|
|
435
435
|
// src/coordinate.ts
|
|
436
436
|
var Coordinate = class {
|
|
437
|
+
/**
|
|
438
|
+
* Calculate layout to fit content within container while preserving aspect ratio.
|
|
439
|
+
*/
|
|
440
|
+
static calculateLayout(container, content, padding = 0) {
|
|
441
|
+
const availableWidth = Math.max(0, container.width - padding * 2);
|
|
442
|
+
const availableHeight = Math.max(0, container.height - padding * 2);
|
|
443
|
+
if (content.width === 0 || content.height === 0) {
|
|
444
|
+
return { scale: 1, offsetX: 0, offsetY: 0, width: 0, height: 0 };
|
|
445
|
+
}
|
|
446
|
+
const scaleX = availableWidth / content.width;
|
|
447
|
+
const scaleY = availableHeight / content.height;
|
|
448
|
+
const scale = Math.min(scaleX, scaleY);
|
|
449
|
+
const width = content.width * scale;
|
|
450
|
+
const height = content.height * scale;
|
|
451
|
+
const offsetX = (container.width - width) / 2;
|
|
452
|
+
const offsetY = (container.height - height) / 2;
|
|
453
|
+
return { scale, offsetX, offsetY, width, height };
|
|
454
|
+
}
|
|
437
455
|
/**
|
|
438
456
|
* Convert an absolute value to a normalized value (0-1).
|
|
439
457
|
* @param value Absolute value (e.g., pixels)
|
|
@@ -468,6 +486,21 @@ var Coordinate = class {
|
|
|
468
486
|
y: this.toAbsolute(point.y, size.height)
|
|
469
487
|
};
|
|
470
488
|
}
|
|
489
|
+
static convertUnit(value, from, to) {
|
|
490
|
+
if (from === to) return value;
|
|
491
|
+
const toMM = {
|
|
492
|
+
px: 0.264583,
|
|
493
|
+
// 1px = 0.264583mm (96 DPI)
|
|
494
|
+
mm: 1,
|
|
495
|
+
cm: 10,
|
|
496
|
+
in: 25.4
|
|
497
|
+
};
|
|
498
|
+
const mmValue = value * (from === "px" ? toMM.px : toMM[from] || 1);
|
|
499
|
+
if (to === "px") {
|
|
500
|
+
return mmValue / toMM.px;
|
|
501
|
+
}
|
|
502
|
+
return mmValue / (toMM[to] || 1);
|
|
503
|
+
}
|
|
471
504
|
};
|
|
472
505
|
|
|
473
506
|
// src/geometry.ts
|
|
@@ -524,9 +557,10 @@ function resolveHolePosition(hole, geometry, canvasSize) {
|
|
|
524
557
|
y: by + (hole.offsetY || 0)
|
|
525
558
|
};
|
|
526
559
|
} else if (hole.x !== void 0 && hole.y !== void 0) {
|
|
560
|
+
const { x, width, y, height } = geometry;
|
|
527
561
|
return {
|
|
528
|
-
x: hole.x *
|
|
529
|
-
y: hole.y *
|
|
562
|
+
x: hole.x * width + (x - width / 2) + (hole.offsetX || 0),
|
|
563
|
+
y: hole.y * height + (y - height / 2) + (hole.offsetY || 0)
|
|
530
564
|
};
|
|
531
565
|
}
|
|
532
566
|
return { x: 0, y: 0 };
|
|
@@ -632,7 +666,10 @@ function getDielineShape(options) {
|
|
|
632
666
|
cutsPath.remove();
|
|
633
667
|
mainShape = temp;
|
|
634
668
|
} catch (e) {
|
|
635
|
-
console.error(
|
|
669
|
+
console.error(
|
|
670
|
+
"Geometry: Failed to subtract cutsPath from mainShape",
|
|
671
|
+
e
|
|
672
|
+
);
|
|
636
673
|
}
|
|
637
674
|
}
|
|
638
675
|
}
|
|
@@ -725,7 +762,12 @@ function getPathBounds(pathData) {
|
|
|
725
762
|
path.pathData = pathData;
|
|
726
763
|
const bounds = path.bounds;
|
|
727
764
|
path.remove();
|
|
728
|
-
return {
|
|
765
|
+
return {
|
|
766
|
+
x: bounds.x,
|
|
767
|
+
y: bounds.y,
|
|
768
|
+
width: bounds.width,
|
|
769
|
+
height: bounds.height
|
|
770
|
+
};
|
|
729
771
|
}
|
|
730
772
|
|
|
731
773
|
// src/dieline.ts
|
|
@@ -735,6 +777,7 @@ var DielineTool = class {
|
|
|
735
777
|
this.metadata = {
|
|
736
778
|
name: "DielineTool"
|
|
737
779
|
};
|
|
780
|
+
this.unit = "mm";
|
|
738
781
|
this.shape = "rect";
|
|
739
782
|
this.width = 500;
|
|
740
783
|
this.height = 500;
|
|
@@ -745,6 +788,7 @@ var DielineTool = class {
|
|
|
745
788
|
this.outsideColor = "#ffffff";
|
|
746
789
|
this.showBleedLines = true;
|
|
747
790
|
this.holes = [];
|
|
791
|
+
this.padding = 140;
|
|
748
792
|
if (options) {
|
|
749
793
|
Object.assign(this, options);
|
|
750
794
|
}
|
|
@@ -758,14 +802,12 @@ var DielineTool = class {
|
|
|
758
802
|
}
|
|
759
803
|
const configService = context.services.get("ConfigurationService");
|
|
760
804
|
if (configService) {
|
|
805
|
+
this.unit = configService.get("dieline.unit", this.unit);
|
|
761
806
|
this.shape = configService.get("dieline.shape", this.shape);
|
|
762
807
|
this.width = configService.get("dieline.width", this.width);
|
|
763
808
|
this.height = configService.get("dieline.height", this.height);
|
|
764
809
|
this.radius = configService.get("dieline.radius", this.radius);
|
|
765
|
-
this.
|
|
766
|
-
"dieline.borderLength",
|
|
767
|
-
this.borderLength
|
|
768
|
-
);
|
|
810
|
+
this.padding = configService.get("dieline.padding", this.padding);
|
|
769
811
|
this.offset = configService.get("dieline.offset", this.offset);
|
|
770
812
|
this.style = configService.get("dieline.style", this.style);
|
|
771
813
|
this.insideColor = configService.get(
|
|
@@ -806,6 +848,13 @@ var DielineTool = class {
|
|
|
806
848
|
contribute() {
|
|
807
849
|
return {
|
|
808
850
|
[import_core2.ContributionPointIds.CONFIGURATIONS]: [
|
|
851
|
+
{
|
|
852
|
+
id: "dieline.unit",
|
|
853
|
+
type: "select",
|
|
854
|
+
label: "Unit",
|
|
855
|
+
options: ["px", "mm", "cm", "in"],
|
|
856
|
+
default: this.unit
|
|
857
|
+
},
|
|
809
858
|
{
|
|
810
859
|
id: "dieline.shape",
|
|
811
860
|
type: "select",
|
|
@@ -841,15 +890,14 @@ var DielineTool = class {
|
|
|
841
890
|
id: "dieline.position",
|
|
842
891
|
type: "json",
|
|
843
892
|
label: "Position (Normalized)",
|
|
844
|
-
default: this.
|
|
893
|
+
default: this.radius
|
|
845
894
|
},
|
|
846
895
|
{
|
|
847
|
-
id: "dieline.
|
|
848
|
-
type: "
|
|
849
|
-
label: "
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
default: this.borderLength
|
|
896
|
+
id: "dieline.padding",
|
|
897
|
+
type: "select",
|
|
898
|
+
label: "View Padding",
|
|
899
|
+
options: [0, 10, 20, 40, 60, 100, "2%", "5%", "10%", "15%", "20%"],
|
|
900
|
+
default: this.padding
|
|
853
901
|
},
|
|
854
902
|
{
|
|
855
903
|
id: "dieline.offset",
|
|
@@ -918,7 +966,9 @@ var DielineTool = class {
|
|
|
918
966
|
const scale = currentMax / Math.max(bounds.width, bounds.height);
|
|
919
967
|
const newWidth = bounds.width * scale;
|
|
920
968
|
const newHeight = bounds.height * scale;
|
|
921
|
-
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
969
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
970
|
+
"ConfigurationService"
|
|
971
|
+
);
|
|
922
972
|
if (configService) {
|
|
923
973
|
configService.update("dieline.width", newWidth);
|
|
924
974
|
configService.update("dieline.height", newHeight);
|
|
@@ -983,12 +1033,25 @@ var DielineTool = class {
|
|
|
983
1033
|
}
|
|
984
1034
|
return new import_fabric2.Pattern({ source: canvas, repetition: "repeat" });
|
|
985
1035
|
}
|
|
1036
|
+
resolvePadding(containerWidth, containerHeight) {
|
|
1037
|
+
if (typeof this.padding === "number") {
|
|
1038
|
+
return this.padding;
|
|
1039
|
+
}
|
|
1040
|
+
if (typeof this.padding === "string") {
|
|
1041
|
+
if (this.padding.endsWith("%")) {
|
|
1042
|
+
const percent = parseFloat(this.padding) / 100;
|
|
1043
|
+
return Math.min(containerWidth, containerHeight) * percent;
|
|
1044
|
+
}
|
|
1045
|
+
return parseFloat(this.padding) || 0;
|
|
1046
|
+
}
|
|
1047
|
+
return 0;
|
|
1048
|
+
}
|
|
986
1049
|
updateDieline(emitEvent = true) {
|
|
987
|
-
var _a, _b;
|
|
988
1050
|
if (!this.canvasService) return;
|
|
989
1051
|
const layer = this.getLayer();
|
|
990
1052
|
if (!layer) return;
|
|
991
1053
|
const {
|
|
1054
|
+
unit,
|
|
992
1055
|
shape,
|
|
993
1056
|
radius,
|
|
994
1057
|
offset,
|
|
@@ -996,43 +1059,60 @@ var DielineTool = class {
|
|
|
996
1059
|
insideColor,
|
|
997
1060
|
outsideColor,
|
|
998
1061
|
position,
|
|
999
|
-
borderLength,
|
|
1000
1062
|
showBleedLines,
|
|
1001
1063
|
holes
|
|
1002
1064
|
} = this;
|
|
1003
1065
|
let { width, height } = this;
|
|
1004
1066
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1005
1067
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
const
|
|
1013
|
-
const
|
|
1068
|
+
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1069
|
+
const layout = Coordinate.calculateLayout(
|
|
1070
|
+
{ width: canvasW, height: canvasH },
|
|
1071
|
+
{ width, height },
|
|
1072
|
+
paddingPx
|
|
1073
|
+
);
|
|
1074
|
+
const scale = layout.scale;
|
|
1075
|
+
const cx = layout.offsetX + layout.width / 2;
|
|
1076
|
+
const cy = layout.offsetY + layout.height / 2;
|
|
1077
|
+
const visualWidth = layout.width;
|
|
1078
|
+
const visualHeight = layout.height;
|
|
1079
|
+
const visualRadius = radius * scale;
|
|
1080
|
+
const visualOffset = offset * scale;
|
|
1014
1081
|
layer.remove(...layer.getObjects());
|
|
1015
1082
|
const geometryForHoles = {
|
|
1016
1083
|
x: cx,
|
|
1017
1084
|
y: cy,
|
|
1018
1085
|
width: visualWidth,
|
|
1019
1086
|
height: visualHeight
|
|
1087
|
+
// Pass scale/unit context if needed by resolveHolePosition (though currently unused there)
|
|
1020
1088
|
};
|
|
1021
1089
|
const absoluteHoles = (holes || []).map((h) => {
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1090
|
+
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
1091
|
+
const offsetScale = unitScale * scale;
|
|
1092
|
+
const hWithPixelOffsets = {
|
|
1093
|
+
...h,
|
|
1094
|
+
offsetX: (h.offsetX || 0) * offsetScale,
|
|
1095
|
+
offsetY: (h.offsetY || 0) * offsetScale
|
|
1096
|
+
};
|
|
1097
|
+
const pos = resolveHolePosition(hWithPixelOffsets, geometryForHoles, {
|
|
1098
|
+
width: canvasW,
|
|
1099
|
+
height: canvasH
|
|
1100
|
+
});
|
|
1027
1101
|
return {
|
|
1028
1102
|
...h,
|
|
1029
1103
|
x: pos.x,
|
|
1030
|
-
y: pos.y
|
|
1104
|
+
y: pos.y,
|
|
1105
|
+
// Scale hole radii: mm -> current unit -> pixels
|
|
1106
|
+
innerRadius: h.innerRadius * offsetScale,
|
|
1107
|
+
outerRadius: h.outerRadius * offsetScale,
|
|
1108
|
+
// Store scaled offsets in the result for consistency, though pos is already resolved
|
|
1109
|
+
offsetX: hWithPixelOffsets.offsetX,
|
|
1110
|
+
offsetY: hWithPixelOffsets.offsetY
|
|
1031
1111
|
};
|
|
1032
1112
|
});
|
|
1033
|
-
const cutW = Math.max(0,
|
|
1034
|
-
const cutH = Math.max(0,
|
|
1035
|
-
const cutR =
|
|
1113
|
+
const cutW = Math.max(0, visualWidth + visualOffset * 2);
|
|
1114
|
+
const cutH = Math.max(0, visualHeight + visualOffset * 2);
|
|
1115
|
+
const cutR = visualRadius === 0 ? 0 : Math.max(0, visualRadius + visualOffset);
|
|
1036
1116
|
const maskPathData = generateMaskPath({
|
|
1037
1117
|
canvasWidth: canvasW,
|
|
1038
1118
|
canvasHeight: canvasH,
|
|
@@ -1082,15 +1162,15 @@ var DielineTool = class {
|
|
|
1082
1162
|
const bleedPathData = generateBleedZonePath(
|
|
1083
1163
|
{
|
|
1084
1164
|
shape,
|
|
1085
|
-
width,
|
|
1086
|
-
height,
|
|
1087
|
-
radius,
|
|
1165
|
+
width: visualWidth,
|
|
1166
|
+
height: visualHeight,
|
|
1167
|
+
radius: visualRadius,
|
|
1088
1168
|
x: cx,
|
|
1089
1169
|
y: cy,
|
|
1090
1170
|
holes: absoluteHoles,
|
|
1091
1171
|
pathData: this.pathData
|
|
1092
1172
|
},
|
|
1093
|
-
|
|
1173
|
+
visualOffset
|
|
1094
1174
|
);
|
|
1095
1175
|
if (showBleedLines !== false) {
|
|
1096
1176
|
const pattern = this.createHatchPattern("red");
|
|
@@ -1133,13 +1213,12 @@ var DielineTool = class {
|
|
|
1133
1213
|
}
|
|
1134
1214
|
const borderPathData = generateDielinePath({
|
|
1135
1215
|
shape,
|
|
1136
|
-
width,
|
|
1137
|
-
height,
|
|
1138
|
-
radius,
|
|
1216
|
+
width: visualWidth,
|
|
1217
|
+
height: visualHeight,
|
|
1218
|
+
radius: visualRadius,
|
|
1139
1219
|
x: cx,
|
|
1140
1220
|
y: cy,
|
|
1141
1221
|
holes: absoluteHoles,
|
|
1142
|
-
// FIX: Use absoluteHoles instead of holes
|
|
1143
1222
|
pathData: this.pathData
|
|
1144
1223
|
});
|
|
1145
1224
|
const borderObj = new import_fabric2.Path(borderPathData, {
|
|
@@ -1177,115 +1256,107 @@ var DielineTool = class {
|
|
|
1177
1256
|
}
|
|
1178
1257
|
}
|
|
1179
1258
|
getGeometry() {
|
|
1180
|
-
var _a, _b;
|
|
1181
1259
|
if (!this.canvasService) return null;
|
|
1182
|
-
const { shape, width, height, radius, position,
|
|
1260
|
+
const { unit, shape, width, height, radius, position, offset } = this;
|
|
1183
1261
|
const canvasW = this.canvasService.canvas.width || 800;
|
|
1184
1262
|
const canvasH = this.canvasService.canvas.height || 600;
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
const
|
|
1192
|
-
const
|
|
1263
|
+
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1264
|
+
const layout = Coordinate.calculateLayout(
|
|
1265
|
+
{ width: canvasW, height: canvasH },
|
|
1266
|
+
{ width, height },
|
|
1267
|
+
paddingPx
|
|
1268
|
+
);
|
|
1269
|
+
const scale = layout.scale;
|
|
1270
|
+
const cx = layout.offsetX + layout.width / 2;
|
|
1271
|
+
const cy = layout.offsetY + layout.height / 2;
|
|
1272
|
+
const visualWidth = layout.width;
|
|
1273
|
+
const visualHeight = layout.height;
|
|
1193
1274
|
return {
|
|
1194
1275
|
shape,
|
|
1276
|
+
unit,
|
|
1195
1277
|
x: cx,
|
|
1196
1278
|
y: cy,
|
|
1197
1279
|
width: visualWidth,
|
|
1198
1280
|
height: visualHeight,
|
|
1199
|
-
radius,
|
|
1200
|
-
offset,
|
|
1201
|
-
|
|
1281
|
+
radius: radius * scale,
|
|
1282
|
+
offset: offset * scale,
|
|
1283
|
+
// Pass scale to help other tools (like HoleTool) convert units
|
|
1284
|
+
scale,
|
|
1202
1285
|
pathData: this.pathData
|
|
1203
1286
|
};
|
|
1204
1287
|
}
|
|
1205
|
-
exportCutImage() {
|
|
1206
|
-
var _a, _b, _c, _d;
|
|
1288
|
+
async exportCutImage() {
|
|
1207
1289
|
if (!this.canvasService) return null;
|
|
1208
|
-
const
|
|
1290
|
+
const userLayer = this.canvasService.getLayer("user");
|
|
1291
|
+
if (!userLayer) return null;
|
|
1209
1292
|
const { shape, width, height, radius, position, holes } = this;
|
|
1210
|
-
const canvasW = canvas.width || 800;
|
|
1211
|
-
const canvasH = canvas.height || 600;
|
|
1212
|
-
const
|
|
1213
|
-
const
|
|
1293
|
+
const canvasW = this.canvasService.canvas.width || 800;
|
|
1294
|
+
const canvasH = this.canvasService.canvas.height || 600;
|
|
1295
|
+
const paddingPx = this.resolvePadding(canvasW, canvasH);
|
|
1296
|
+
const layout = Coordinate.calculateLayout(
|
|
1297
|
+
{ width: canvasW, height: canvasH },
|
|
1298
|
+
{ width, height },
|
|
1299
|
+
paddingPx
|
|
1300
|
+
);
|
|
1301
|
+
const scale = layout.scale;
|
|
1302
|
+
const cx = layout.offsetX + layout.width / 2;
|
|
1303
|
+
const cy = layout.offsetY + layout.height / 2;
|
|
1304
|
+
const visualWidth = layout.width;
|
|
1305
|
+
const visualHeight = layout.height;
|
|
1306
|
+
const visualRadius = radius * scale;
|
|
1214
1307
|
const absoluteHoles = (holes || []).map((h) => {
|
|
1308
|
+
const unit = this.unit || "mm";
|
|
1309
|
+
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
1215
1310
|
const pos = resolveHolePosition(
|
|
1216
|
-
|
|
1217
|
-
|
|
1311
|
+
{
|
|
1312
|
+
...h,
|
|
1313
|
+
offsetX: (h.offsetX || 0) * unitScale * scale,
|
|
1314
|
+
offsetY: (h.offsetY || 0) * unitScale * scale
|
|
1315
|
+
},
|
|
1316
|
+
{ x: cx, y: cy, width: visualWidth, height: visualHeight },
|
|
1218
1317
|
{ width: canvasW, height: canvasH }
|
|
1219
1318
|
);
|
|
1220
1319
|
return {
|
|
1221
1320
|
...h,
|
|
1222
1321
|
x: pos.x,
|
|
1223
|
-
y: pos.y
|
|
1322
|
+
y: pos.y,
|
|
1323
|
+
innerRadius: h.innerRadius * unitScale * scale,
|
|
1324
|
+
outerRadius: h.outerRadius * unitScale * scale,
|
|
1325
|
+
offsetX: (h.offsetX || 0) * unitScale * scale,
|
|
1326
|
+
offsetY: (h.offsetY || 0) * unitScale * scale
|
|
1224
1327
|
};
|
|
1225
1328
|
});
|
|
1226
1329
|
const pathData = generateDielinePath({
|
|
1227
1330
|
shape,
|
|
1228
|
-
width,
|
|
1229
|
-
height,
|
|
1230
|
-
radius,
|
|
1331
|
+
width: visualWidth,
|
|
1332
|
+
height: visualHeight,
|
|
1333
|
+
radius: visualRadius,
|
|
1231
1334
|
x: cx,
|
|
1232
1335
|
y: cy,
|
|
1233
1336
|
holes: absoluteHoles,
|
|
1234
1337
|
pathData: this.pathData
|
|
1235
1338
|
});
|
|
1339
|
+
const clonedLayer = await userLayer.clone();
|
|
1236
1340
|
const clipPath = new import_fabric2.Path(pathData, {
|
|
1237
|
-
left: 0,
|
|
1238
|
-
top: 0,
|
|
1239
1341
|
originX: "left",
|
|
1240
1342
|
originY: "top",
|
|
1241
|
-
absolutePositioned: true
|
|
1242
|
-
});
|
|
1243
|
-
const layer = this.getLayer();
|
|
1244
|
-
const wasVisible = (_c = layer == null ? void 0 : layer.visible) != null ? _c : true;
|
|
1245
|
-
if (layer) layer.visible = false;
|
|
1246
|
-
const holeMarkers = canvas.getObjects().filter((o) => {
|
|
1247
|
-
var _a2;
|
|
1248
|
-
return ((_a2 = o.data) == null ? void 0 : _a2.type) === "hole-marker";
|
|
1249
|
-
});
|
|
1250
|
-
holeMarkers.forEach((o) => o.visible = false);
|
|
1251
|
-
const rulerLayer = canvas.getObjects().find((obj) => {
|
|
1252
|
-
var _a2;
|
|
1253
|
-
return ((_a2 = obj.data) == null ? void 0 : _a2.id) === "ruler-overlay";
|
|
1254
|
-
});
|
|
1255
|
-
const rulerWasVisible = (_d = rulerLayer == null ? void 0 : rulerLayer.visible) != null ? _d : true;
|
|
1256
|
-
if (rulerLayer) rulerLayer.visible = false;
|
|
1257
|
-
const originalClip = canvas.clipPath;
|
|
1258
|
-
canvas.clipPath = clipPath;
|
|
1259
|
-
const bbox = clipPath.getBoundingRect();
|
|
1260
|
-
const clipPathCorrected = new import_fabric2.Path(pathData, {
|
|
1261
|
-
absolutePositioned: true,
|
|
1262
1343
|
left: 0,
|
|
1263
|
-
top: 0
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
const tempBounds = tempPath.getBoundingRect();
|
|
1267
|
-
clipPathCorrected.set({
|
|
1268
|
-
left: tempBounds.left,
|
|
1269
|
-
top: tempBounds.top,
|
|
1270
|
-
originX: "left",
|
|
1271
|
-
originY: "top"
|
|
1344
|
+
top: 0,
|
|
1345
|
+
absolutePositioned: true
|
|
1346
|
+
// Important for groups
|
|
1272
1347
|
});
|
|
1273
|
-
|
|
1274
|
-
const
|
|
1275
|
-
const
|
|
1348
|
+
clonedLayer.clipPath = clipPath;
|
|
1349
|
+
const bounds = clipPath.getBoundingRect();
|
|
1350
|
+
const dataUrl = clonedLayer.toDataURL({
|
|
1276
1351
|
format: "png",
|
|
1277
1352
|
multiplier: 2,
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1353
|
+
// Better quality
|
|
1354
|
+
left: bounds.left,
|
|
1355
|
+
top: bounds.top,
|
|
1356
|
+
width: bounds.width,
|
|
1357
|
+
height: bounds.height
|
|
1282
1358
|
});
|
|
1283
|
-
|
|
1284
|
-
if (layer) layer.visible = wasVisible;
|
|
1285
|
-
if (rulerLayer) rulerLayer.visible = rulerWasVisible;
|
|
1286
|
-
holeMarkers.forEach((o) => o.visible = true);
|
|
1287
|
-
canvas.requestRenderAll();
|
|
1288
|
-
return dataURL;
|
|
1359
|
+
return dataUrl;
|
|
1289
1360
|
}
|
|
1290
1361
|
};
|
|
1291
1362
|
|
|
@@ -1558,11 +1629,19 @@ var HoleTool = class {
|
|
|
1558
1629
|
handler: (x, y) => {
|
|
1559
1630
|
var _a, _b, _c;
|
|
1560
1631
|
if (!this.canvasService) return false;
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
{
|
|
1565
|
-
|
|
1632
|
+
let normalizedX = 0.5;
|
|
1633
|
+
let normalizedY = 0.5;
|
|
1634
|
+
if (this.currentGeometry) {
|
|
1635
|
+
const { x: gx, y: gy, width: gw, height: gh } = this.currentGeometry;
|
|
1636
|
+
const left = gx - gw / 2;
|
|
1637
|
+
const top = gy - gh / 2;
|
|
1638
|
+
normalizedX = gw > 0 ? (x - left) / gw : 0.5;
|
|
1639
|
+
normalizedY = gh > 0 ? (y - top) / gh : 0.5;
|
|
1640
|
+
} else {
|
|
1641
|
+
const { width, height } = this.canvasService.canvas;
|
|
1642
|
+
normalizedX = Coordinate.toNormalized(x, width || 800);
|
|
1643
|
+
normalizedY = Coordinate.toNormalized(y, height || 600);
|
|
1644
|
+
}
|
|
1566
1645
|
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
1567
1646
|
"ConfigurationService"
|
|
1568
1647
|
);
|
|
@@ -1572,8 +1651,8 @@ var HoleTool = class {
|
|
|
1572
1651
|
const innerRadius = (_b = lastHole == null ? void 0 : lastHole.innerRadius) != null ? _b : 15;
|
|
1573
1652
|
const outerRadius = (_c = lastHole == null ? void 0 : lastHole.outerRadius) != null ? _c : 25;
|
|
1574
1653
|
const newHole = {
|
|
1575
|
-
x:
|
|
1576
|
-
y:
|
|
1654
|
+
x: normalizedX,
|
|
1655
|
+
y: normalizedY,
|
|
1577
1656
|
innerRadius,
|
|
1578
1657
|
outerRadius
|
|
1579
1658
|
};
|
|
@@ -1668,7 +1747,10 @@ var HoleTool = class {
|
|
|
1668
1747
|
var _a;
|
|
1669
1748
|
const target = e.target;
|
|
1670
1749
|
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "hole-marker") return;
|
|
1671
|
-
this.
|
|
1750
|
+
const changed = this.enforceConstraints();
|
|
1751
|
+
if (!changed) {
|
|
1752
|
+
this.syncHolesFromCanvas();
|
|
1753
|
+
}
|
|
1672
1754
|
};
|
|
1673
1755
|
canvas.on("object:modified", this.handleModified);
|
|
1674
1756
|
}
|
|
@@ -1726,18 +1808,21 @@ var HoleTool = class {
|
|
|
1726
1808
|
}
|
|
1727
1809
|
);
|
|
1728
1810
|
const newHoles = objects.map((obj, i) => {
|
|
1729
|
-
var _a, _b;
|
|
1811
|
+
var _a, _b, _c, _d;
|
|
1730
1812
|
const original = this.holes[i];
|
|
1731
1813
|
const newAbsX = obj.left;
|
|
1732
1814
|
const newAbsY = obj.top;
|
|
1815
|
+
const scale = ((_a = this.currentGeometry) == null ? void 0 : _a.scale) || 1;
|
|
1816
|
+
const unit = ((_b = this.currentGeometry) == null ? void 0 : _b.unit) || "mm";
|
|
1817
|
+
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
1733
1818
|
if (original && original.anchor && this.currentGeometry) {
|
|
1734
|
-
const { x, y, width
|
|
1819
|
+
const { x, y, width, height } = this.currentGeometry;
|
|
1735
1820
|
let bx = x;
|
|
1736
1821
|
let by = y;
|
|
1737
|
-
const left = x -
|
|
1738
|
-
const right = x +
|
|
1739
|
-
const top = y -
|
|
1740
|
-
const bottom = y +
|
|
1822
|
+
const left = x - width / 2;
|
|
1823
|
+
const right = x + width / 2;
|
|
1824
|
+
const top = y - height / 2;
|
|
1825
|
+
const bottom = y + height / 2;
|
|
1741
1826
|
switch (original.anchor) {
|
|
1742
1827
|
case "top-left":
|
|
1743
1828
|
bx = left;
|
|
@@ -1778,25 +1863,34 @@ var HoleTool = class {
|
|
|
1778
1863
|
}
|
|
1779
1864
|
return {
|
|
1780
1865
|
...original,
|
|
1781
|
-
|
|
1782
|
-
|
|
1866
|
+
// Denormalize offset back to physical units (mm)
|
|
1867
|
+
offsetX: (newAbsX - bx) / scale / unitScale,
|
|
1868
|
+
offsetY: (newAbsY - by) / scale / unitScale,
|
|
1783
1869
|
// Clear direct coordinates if we use anchor
|
|
1784
1870
|
x: void 0,
|
|
1785
1871
|
y: void 0
|
|
1786
1872
|
};
|
|
1787
1873
|
}
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
{
|
|
1792
|
-
|
|
1874
|
+
let normalizedX = 0.5;
|
|
1875
|
+
let normalizedY = 0.5;
|
|
1876
|
+
if (this.currentGeometry) {
|
|
1877
|
+
const { x, y, width, height } = this.currentGeometry;
|
|
1878
|
+
const left = x - width / 2;
|
|
1879
|
+
const top = y - height / 2;
|
|
1880
|
+
normalizedX = width > 0 ? (newAbsX - left) / width : 0.5;
|
|
1881
|
+
normalizedY = height > 0 ? (newAbsY - top) / height : 0.5;
|
|
1882
|
+
} else {
|
|
1883
|
+
const { width, height } = this.canvasService.canvas;
|
|
1884
|
+
normalizedX = Coordinate.toNormalized(newAbsX, width || 800);
|
|
1885
|
+
normalizedY = Coordinate.toNormalized(newAbsY, height || 600);
|
|
1886
|
+
}
|
|
1793
1887
|
return {
|
|
1794
1888
|
...original,
|
|
1795
|
-
x:
|
|
1796
|
-
y:
|
|
1889
|
+
x: normalizedX,
|
|
1890
|
+
y: normalizedY,
|
|
1797
1891
|
// Ensure radii are preserved
|
|
1798
|
-
innerRadius: (
|
|
1799
|
-
outerRadius: (
|
|
1892
|
+
innerRadius: (_c = original == null ? void 0 : original.innerRadius) != null ? _c : 15,
|
|
1893
|
+
outerRadius: (_d = original == null ? void 0 : original.outerRadius) != null ? _d : 25
|
|
1800
1894
|
};
|
|
1801
1895
|
});
|
|
1802
1896
|
this.holes = newHoles;
|
|
@@ -1834,16 +1928,28 @@ var HoleTool = class {
|
|
|
1834
1928
|
x: (width || 800) / 2,
|
|
1835
1929
|
y: (height || 600) / 2,
|
|
1836
1930
|
width: width || 800,
|
|
1837
|
-
height: height || 600
|
|
1931
|
+
height: height || 600,
|
|
1932
|
+
scale: 1
|
|
1933
|
+
// Default scale if no geometry loaded
|
|
1838
1934
|
};
|
|
1839
1935
|
holes.forEach((hole, index) => {
|
|
1936
|
+
const scale = geometry.scale || 1;
|
|
1937
|
+
const unit = geometry.unit || "mm";
|
|
1938
|
+
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
1939
|
+
const visualInnerRadius = hole.innerRadius * unitScale * scale;
|
|
1940
|
+
const visualOuterRadius = hole.outerRadius * unitScale * scale;
|
|
1840
1941
|
const pos = resolveHolePosition(
|
|
1841
|
-
|
|
1942
|
+
{
|
|
1943
|
+
...hole,
|
|
1944
|
+
offsetX: (hole.offsetX || 0) * unitScale * scale,
|
|
1945
|
+
offsetY: (hole.offsetY || 0) * unitScale * scale
|
|
1946
|
+
},
|
|
1842
1947
|
geometry,
|
|
1843
|
-
{ width: width
|
|
1948
|
+
{ width: geometry.width, height: geometry.height }
|
|
1949
|
+
// Use geometry dims instead of canvas
|
|
1844
1950
|
);
|
|
1845
1951
|
const innerCircle = new import_fabric4.Circle({
|
|
1846
|
-
radius:
|
|
1952
|
+
radius: visualInnerRadius,
|
|
1847
1953
|
fill: "transparent",
|
|
1848
1954
|
stroke: "red",
|
|
1849
1955
|
strokeWidth: 2,
|
|
@@ -1851,7 +1957,7 @@ var HoleTool = class {
|
|
|
1851
1957
|
originY: "center"
|
|
1852
1958
|
});
|
|
1853
1959
|
const outerCircle = new import_fabric4.Circle({
|
|
1854
|
-
radius:
|
|
1960
|
+
radius: visualOuterRadius,
|
|
1855
1961
|
fill: "transparent",
|
|
1856
1962
|
stroke: "#666",
|
|
1857
1963
|
strokeWidth: 1,
|
|
@@ -1931,11 +2037,16 @@ var HoleTool = class {
|
|
|
1931
2037
|
var _a, _b;
|
|
1932
2038
|
const currentPos = new import_fabric4.Point(obj.left, obj.top);
|
|
1933
2039
|
const holeData = this.holes[i];
|
|
2040
|
+
const scale = geometry.scale || 1;
|
|
2041
|
+
const unit = geometry.unit || "mm";
|
|
2042
|
+
const unitScale = Coordinate.convertUnit(1, "mm", unit);
|
|
2043
|
+
const innerR = ((_a = holeData == null ? void 0 : holeData.innerRadius) != null ? _a : 15) * unitScale * scale;
|
|
2044
|
+
const outerR = ((_b = holeData == null ? void 0 : holeData.outerRadius) != null ? _b : 25) * unitScale * scale;
|
|
1934
2045
|
const newPos = this.calculateConstrainedPosition(
|
|
1935
2046
|
currentPos,
|
|
1936
2047
|
constraintGeometry,
|
|
1937
|
-
|
|
1938
|
-
|
|
2048
|
+
innerR,
|
|
2049
|
+
outerR
|
|
1939
2050
|
);
|
|
1940
2051
|
if (currentPos.distanceFrom(newPos) > 0.1) {
|
|
1941
2052
|
obj.set({
|
|
@@ -1989,17 +2100,14 @@ var HoleTool = class {
|
|
|
1989
2100
|
var import_core5 = require("@pooder/core");
|
|
1990
2101
|
var import_fabric5 = require("fabric");
|
|
1991
2102
|
var ImageTool = class {
|
|
1992
|
-
constructor(
|
|
2103
|
+
constructor() {
|
|
1993
2104
|
this.id = "pooder.kit.image";
|
|
1994
2105
|
this.metadata = {
|
|
1995
2106
|
name: "ImageTool"
|
|
1996
2107
|
};
|
|
1997
|
-
this.
|
|
1998
|
-
this.
|
|
1999
|
-
this.
|
|
2000
|
-
if (options) {
|
|
2001
|
-
Object.assign(this, options);
|
|
2002
|
-
}
|
|
2108
|
+
this.items = [];
|
|
2109
|
+
this.objectMap = /* @__PURE__ */ new Map();
|
|
2110
|
+
this.isUpdatingConfig = false;
|
|
2003
2111
|
}
|
|
2004
2112
|
activate(context) {
|
|
2005
2113
|
this.context = context;
|
|
@@ -2010,38 +2118,33 @@ var ImageTool = class {
|
|
|
2010
2118
|
}
|
|
2011
2119
|
const configService = context.services.get("ConfigurationService");
|
|
2012
2120
|
if (configService) {
|
|
2013
|
-
this.
|
|
2014
|
-
this.opacity = configService.get("image.opacity", this.opacity);
|
|
2015
|
-
this.width = configService.get("image.width", this.width);
|
|
2016
|
-
this.height = configService.get("image.height", this.height);
|
|
2017
|
-
this.angle = configService.get("image.angle", this.angle);
|
|
2018
|
-
this.left = configService.get("image.left", this.left);
|
|
2019
|
-
this.top = configService.get("image.top", this.top);
|
|
2121
|
+
this.items = configService.get("image.items", []) || [];
|
|
2020
2122
|
configService.onAnyChange((e) => {
|
|
2021
|
-
if (
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2123
|
+
if (this.isUpdatingConfig) return;
|
|
2124
|
+
let shouldUpdate = false;
|
|
2125
|
+
if (e.key === "image.items") {
|
|
2126
|
+
this.items = e.value || [];
|
|
2127
|
+
shouldUpdate = true;
|
|
2128
|
+
} else if (e.key.startsWith("dieline.") && e.key !== "dieline.holes") {
|
|
2129
|
+
shouldUpdate = true;
|
|
2130
|
+
}
|
|
2131
|
+
if (shouldUpdate) {
|
|
2132
|
+
this.updateImages();
|
|
2030
2133
|
}
|
|
2031
2134
|
});
|
|
2032
2135
|
}
|
|
2033
2136
|
this.ensureLayer();
|
|
2034
|
-
this.
|
|
2137
|
+
this.updateImages();
|
|
2035
2138
|
}
|
|
2036
2139
|
deactivate(context) {
|
|
2037
2140
|
if (this.canvasService) {
|
|
2038
2141
|
const layer = this.canvasService.getLayer("user");
|
|
2039
2142
|
if (layer) {
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2143
|
+
this.objectMap.forEach((obj) => {
|
|
2144
|
+
layer.remove(obj);
|
|
2145
|
+
});
|
|
2146
|
+
this.objectMap.clear();
|
|
2147
|
+
this.canvasService.requestRenderAll();
|
|
2045
2148
|
}
|
|
2046
2149
|
this.canvasService = void 0;
|
|
2047
2150
|
this.context = void 0;
|
|
@@ -2051,82 +2154,103 @@ var ImageTool = class {
|
|
|
2051
2154
|
return {
|
|
2052
2155
|
[import_core5.ContributionPointIds.CONFIGURATIONS]: [
|
|
2053
2156
|
{
|
|
2054
|
-
id: "image.
|
|
2055
|
-
type: "
|
|
2056
|
-
label: "
|
|
2057
|
-
default:
|
|
2058
|
-
}
|
|
2157
|
+
id: "image.items",
|
|
2158
|
+
type: "array",
|
|
2159
|
+
label: "Images",
|
|
2160
|
+
default: []
|
|
2161
|
+
}
|
|
2162
|
+
],
|
|
2163
|
+
[import_core5.ContributionPointIds.COMMANDS]: [
|
|
2059
2164
|
{
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2165
|
+
command: "addImage",
|
|
2166
|
+
title: "Add Image",
|
|
2167
|
+
handler: (url, options) => {
|
|
2168
|
+
const newItem = {
|
|
2169
|
+
id: this.generateId(),
|
|
2170
|
+
url,
|
|
2171
|
+
opacity: 1,
|
|
2172
|
+
...options
|
|
2173
|
+
};
|
|
2174
|
+
this.updateConfig([...this.items, newItem]);
|
|
2175
|
+
return newItem.id;
|
|
2176
|
+
}
|
|
2067
2177
|
},
|
|
2068
2178
|
{
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2179
|
+
command: "removeImage",
|
|
2180
|
+
title: "Remove Image",
|
|
2181
|
+
handler: (id) => {
|
|
2182
|
+
const newItems = this.items.filter((item) => item.id !== id);
|
|
2183
|
+
if (newItems.length !== this.items.length) {
|
|
2184
|
+
this.updateConfig(newItems);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2075
2187
|
},
|
|
2076
2188
|
{
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2189
|
+
command: "updateImage",
|
|
2190
|
+
title: "Update Image",
|
|
2191
|
+
handler: (id, updates) => {
|
|
2192
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
2193
|
+
if (index !== -1) {
|
|
2194
|
+
const newItems = [...this.items];
|
|
2195
|
+
newItems[index] = { ...newItems[index], ...updates };
|
|
2196
|
+
this.updateConfig(newItems);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2083
2199
|
},
|
|
2084
2200
|
{
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
default: this.angle
|
|
2201
|
+
command: "clearImages",
|
|
2202
|
+
title: "Clear Images",
|
|
2203
|
+
handler: () => {
|
|
2204
|
+
this.updateConfig([]);
|
|
2205
|
+
}
|
|
2091
2206
|
},
|
|
2092
2207
|
{
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2208
|
+
command: "bringToFront",
|
|
2209
|
+
title: "Bring Image to Front",
|
|
2210
|
+
handler: (id) => {
|
|
2211
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
2212
|
+
if (index !== -1 && index < this.items.length - 1) {
|
|
2213
|
+
const newItems = [...this.items];
|
|
2214
|
+
const [item] = newItems.splice(index, 1);
|
|
2215
|
+
newItems.push(item);
|
|
2216
|
+
this.updateConfig(newItems);
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2099
2219
|
},
|
|
2100
2220
|
{
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
command: "setUserImage",
|
|
2112
|
-
title: "Set User Image",
|
|
2113
|
-
handler: (url, opacity, width, height, angle, left, top) => {
|
|
2114
|
-
if (this.url === url && this.opacity === opacity && this.width === width && this.height === height && this.angle === angle && this.left === left && this.top === top)
|
|
2115
|
-
return true;
|
|
2116
|
-
this.url = url;
|
|
2117
|
-
this.opacity = opacity;
|
|
2118
|
-
this.width = width;
|
|
2119
|
-
this.height = height;
|
|
2120
|
-
this.angle = angle;
|
|
2121
|
-
this.left = left;
|
|
2122
|
-
this.top = top;
|
|
2123
|
-
this.updateImage();
|
|
2124
|
-
return true;
|
|
2221
|
+
command: "sendToBack",
|
|
2222
|
+
title: "Send Image to Back",
|
|
2223
|
+
handler: (id) => {
|
|
2224
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
2225
|
+
if (index > 0) {
|
|
2226
|
+
const newItems = [...this.items];
|
|
2227
|
+
const [item] = newItems.splice(index, 1);
|
|
2228
|
+
newItems.unshift(item);
|
|
2229
|
+
this.updateConfig(newItems);
|
|
2230
|
+
}
|
|
2125
2231
|
}
|
|
2126
2232
|
}
|
|
2127
2233
|
]
|
|
2128
2234
|
};
|
|
2129
2235
|
}
|
|
2236
|
+
generateId() {
|
|
2237
|
+
return Math.random().toString(36).substring(2, 9);
|
|
2238
|
+
}
|
|
2239
|
+
updateConfig(newItems, skipCanvasUpdate = false) {
|
|
2240
|
+
if (!this.context) return;
|
|
2241
|
+
this.isUpdatingConfig = true;
|
|
2242
|
+
this.items = newItems;
|
|
2243
|
+
const configService = this.context.services.get("ConfigurationService");
|
|
2244
|
+
if (configService) {
|
|
2245
|
+
configService.update("image.items", newItems);
|
|
2246
|
+
}
|
|
2247
|
+
if (!skipCanvasUpdate) {
|
|
2248
|
+
this.updateImages();
|
|
2249
|
+
}
|
|
2250
|
+
setTimeout(() => {
|
|
2251
|
+
this.isUpdatingConfig = false;
|
|
2252
|
+
}, 50);
|
|
2253
|
+
}
|
|
2130
2254
|
ensureLayer() {
|
|
2131
2255
|
if (!this.canvasService) return;
|
|
2132
2256
|
let userLayer = this.canvasService.getLayer("user");
|
|
@@ -2158,224 +2282,176 @@ var ImageTool = class {
|
|
|
2158
2282
|
this.canvasService.requestRenderAll();
|
|
2159
2283
|
}
|
|
2160
2284
|
}
|
|
2161
|
-
|
|
2285
|
+
getLayoutInfo() {
|
|
2162
2286
|
var _a, _b;
|
|
2287
|
+
const canvasW = ((_a = this.canvasService) == null ? void 0 : _a.canvas.width) || 800;
|
|
2288
|
+
const canvasH = ((_b = this.canvasService) == null ? void 0 : _b.canvas.height) || 600;
|
|
2289
|
+
let layoutScale = 1;
|
|
2290
|
+
let layoutOffsetX = 0;
|
|
2291
|
+
let layoutOffsetY = 0;
|
|
2292
|
+
let visualWidth = canvasW;
|
|
2293
|
+
let visualHeight = canvasH;
|
|
2294
|
+
let dielinePhysicalWidth = 500;
|
|
2295
|
+
let dielinePhysicalHeight = 500;
|
|
2296
|
+
if (this.context) {
|
|
2297
|
+
const configService = this.context.services.get("ConfigurationService");
|
|
2298
|
+
if (configService) {
|
|
2299
|
+
dielinePhysicalWidth = configService.get("dieline.width") || 500;
|
|
2300
|
+
dielinePhysicalHeight = configService.get("dieline.height") || 500;
|
|
2301
|
+
const padding = configService.get("dieline.padding") || 40;
|
|
2302
|
+
const layout = Coordinate.calculateLayout(
|
|
2303
|
+
{ width: canvasW, height: canvasH },
|
|
2304
|
+
{ width: dielinePhysicalWidth, height: dielinePhysicalHeight },
|
|
2305
|
+
padding
|
|
2306
|
+
);
|
|
2307
|
+
layoutScale = layout.scale;
|
|
2308
|
+
layoutOffsetX = layout.offsetX;
|
|
2309
|
+
layoutOffsetY = layout.offsetY;
|
|
2310
|
+
visualWidth = layout.width;
|
|
2311
|
+
visualHeight = layout.height;
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
return {
|
|
2315
|
+
layoutScale,
|
|
2316
|
+
layoutOffsetX,
|
|
2317
|
+
layoutOffsetY,
|
|
2318
|
+
visualWidth,
|
|
2319
|
+
visualHeight,
|
|
2320
|
+
dielinePhysicalWidth,
|
|
2321
|
+
dielinePhysicalHeight
|
|
2322
|
+
};
|
|
2323
|
+
}
|
|
2324
|
+
updateImages() {
|
|
2163
2325
|
if (!this.canvasService) return;
|
|
2164
|
-
let { url, opacity, width, height, angle, left, top } = this;
|
|
2165
2326
|
const layer = this.canvasService.getLayer("user");
|
|
2166
2327
|
if (!layer) {
|
|
2167
2328
|
console.warn("[ImageTool] User layer not found");
|
|
2168
2329
|
return;
|
|
2169
2330
|
}
|
|
2170
|
-
const
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2331
|
+
const currentIds = new Set(this.items.map((i) => i.id));
|
|
2332
|
+
for (const [id, obj] of this.objectMap) {
|
|
2333
|
+
if (!currentIds.has(id)) {
|
|
2334
|
+
layer.remove(obj);
|
|
2335
|
+
this.objectMap.delete(id);
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
const layout = this.getLayoutInfo();
|
|
2339
|
+
this.items.forEach((item, index) => {
|
|
2340
|
+
let obj = this.objectMap.get(item.id);
|
|
2341
|
+
if (!obj) {
|
|
2342
|
+
this.loadImage(item, layer, layout);
|
|
2176
2343
|
} else {
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
const centerX = canvasW / 2;
|
|
2181
|
-
const centerY = canvasH / 2;
|
|
2182
|
-
if (userImage.opacity !== opacity) updates.opacity = opacity;
|
|
2183
|
-
if (angle !== void 0 && userImage.angle !== angle)
|
|
2184
|
-
updates.angle = angle;
|
|
2185
|
-
if (userImage.originX !== "center") {
|
|
2186
|
-
userImage.set({
|
|
2187
|
-
originX: "center",
|
|
2188
|
-
originY: "center",
|
|
2189
|
-
left: userImage.left + userImage.width * userImage.scaleX / 2,
|
|
2190
|
-
top: userImage.top + userImage.height * userImage.scaleY / 2
|
|
2191
|
-
});
|
|
2192
|
-
}
|
|
2193
|
-
if (left !== void 0) {
|
|
2194
|
-
const globalLeft = Coordinate.toAbsolute(left, canvasW);
|
|
2195
|
-
const localLeft = globalLeft - centerX;
|
|
2196
|
-
if (Math.abs(userImage.left - localLeft) > 1)
|
|
2197
|
-
updates.left = localLeft;
|
|
2198
|
-
}
|
|
2199
|
-
if (top !== void 0) {
|
|
2200
|
-
const globalTop = Coordinate.toAbsolute(top, canvasH);
|
|
2201
|
-
const localTop = globalTop - centerY;
|
|
2202
|
-
if (Math.abs(userImage.top - localTop) > 1) updates.top = localTop;
|
|
2203
|
-
}
|
|
2204
|
-
if (width !== void 0 && userImage.width)
|
|
2205
|
-
updates.scaleX = width / userImage.width;
|
|
2206
|
-
if (height !== void 0 && userImage.height)
|
|
2207
|
-
updates.scaleY = height / userImage.height;
|
|
2208
|
-
if (Object.keys(updates).length > 0) {
|
|
2209
|
-
userImage.set(updates);
|
|
2210
|
-
layer.dirty = true;
|
|
2211
|
-
this.canvasService.requestRenderAll();
|
|
2212
|
-
}
|
|
2344
|
+
this.updateObjectProperties(obj, item, layout);
|
|
2345
|
+
layer.remove(obj);
|
|
2346
|
+
layer.add(obj);
|
|
2213
2347
|
}
|
|
2214
|
-
}
|
|
2215
|
-
|
|
2348
|
+
});
|
|
2349
|
+
layer.dirty = true;
|
|
2350
|
+
this.canvasService.requestRenderAll();
|
|
2351
|
+
}
|
|
2352
|
+
updateObjectProperties(obj, item, layout) {
|
|
2353
|
+
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight } = layout;
|
|
2354
|
+
const updates = {};
|
|
2355
|
+
if (obj.opacity !== item.opacity) updates.opacity = item.opacity;
|
|
2356
|
+
if (item.angle !== void 0 && obj.angle !== item.angle) updates.angle = item.angle;
|
|
2357
|
+
if (item.left !== void 0) {
|
|
2358
|
+
const globalLeft = layoutOffsetX + item.left * visualWidth;
|
|
2359
|
+
if (Math.abs(obj.left - globalLeft) > 1) updates.left = globalLeft;
|
|
2360
|
+
}
|
|
2361
|
+
if (item.top !== void 0) {
|
|
2362
|
+
const globalTop = layoutOffsetY + item.top * visualHeight;
|
|
2363
|
+
if (Math.abs(obj.top - globalTop) > 1) updates.top = globalTop;
|
|
2364
|
+
}
|
|
2365
|
+
if (item.width !== void 0 && obj.width) {
|
|
2366
|
+
const targetScaleX = item.width * layoutScale / obj.width;
|
|
2367
|
+
if (Math.abs(obj.scaleX - targetScaleX) > 1e-3) updates.scaleX = targetScaleX;
|
|
2368
|
+
}
|
|
2369
|
+
if (item.height !== void 0 && obj.height) {
|
|
2370
|
+
const targetScaleY = item.height * layoutScale / obj.height;
|
|
2371
|
+
if (Math.abs(obj.scaleY - targetScaleY) > 1e-3) updates.scaleY = targetScaleY;
|
|
2372
|
+
}
|
|
2373
|
+
if (obj.originX !== "center") {
|
|
2374
|
+
updates.originX = "center";
|
|
2375
|
+
updates.originY = "center";
|
|
2376
|
+
}
|
|
2377
|
+
if (Object.keys(updates).length > 0) {
|
|
2378
|
+
obj.set(updates);
|
|
2216
2379
|
}
|
|
2217
2380
|
}
|
|
2218
|
-
loadImage(layer) {
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
let {
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
{
|
|
2237
|
-
widthVal: dielineWidth,
|
|
2238
|
-
heightVal: dielineHeight,
|
|
2239
|
-
// Debug: dump all keys to see what is available
|
|
2240
|
-
allKeys: Array.from(
|
|
2241
|
-
((_a = configService.configValues) == null ? void 0 : _a.keys()) || []
|
|
2242
|
-
)
|
|
2243
|
-
},
|
|
2244
|
-
configService
|
|
2245
|
-
);
|
|
2246
|
-
if (width === void 0 && height === void 0) {
|
|
2247
|
-
const scale = Math.min(
|
|
2248
|
-
dielineWidth / (image.width || 1),
|
|
2249
|
-
dielineHeight / (image.height || 1)
|
|
2250
|
-
);
|
|
2251
|
-
width = (image.width || 1) * scale;
|
|
2252
|
-
height = (image.height || 1) * scale;
|
|
2253
|
-
this.width = width;
|
|
2254
|
-
this.height = height;
|
|
2255
|
-
}
|
|
2256
|
-
if (left === void 0 && top === void 0) {
|
|
2257
|
-
const dielinePos = configService == null ? void 0 : configService.get("dieline.position");
|
|
2258
|
-
if (dielinePos) {
|
|
2259
|
-
this.left = dielinePos.x;
|
|
2260
|
-
this.top = dielinePos.y;
|
|
2261
|
-
} else {
|
|
2262
|
-
this.left = 0.5;
|
|
2263
|
-
this.top = 0.5;
|
|
2264
|
-
}
|
|
2265
|
-
left = this.left;
|
|
2266
|
-
top = this.top;
|
|
2267
|
-
}
|
|
2268
|
-
}
|
|
2269
|
-
const existingImage = this.canvasService.getObject(
|
|
2270
|
-
"user-image",
|
|
2271
|
-
"user"
|
|
2272
|
-
);
|
|
2273
|
-
if (existingImage) {
|
|
2274
|
-
const defaultLeft = existingImage.left;
|
|
2275
|
-
const defaultTop = existingImage.top;
|
|
2276
|
-
const defaultAngle = existingImage.angle;
|
|
2277
|
-
const defaultScaleX = existingImage.scaleX;
|
|
2278
|
-
const defaultScaleY = existingImage.scaleY;
|
|
2279
|
-
const canvasW = ((_b = this.canvasService) == null ? void 0 : _b.canvas.width) || 800;
|
|
2280
|
-
const canvasH = ((_c = this.canvasService) == null ? void 0 : _c.canvas.height) || 600;
|
|
2281
|
-
const centerX = canvasW / 2;
|
|
2282
|
-
const centerY = canvasH / 2;
|
|
2283
|
-
let targetLeft = left !== void 0 ? left : defaultLeft;
|
|
2284
|
-
let targetTop = top !== void 0 ? top : defaultTop;
|
|
2285
|
-
const configService = (_d = this.context) == null ? void 0 : _d.services.get(
|
|
2286
|
-
"ConfigurationService"
|
|
2287
|
-
);
|
|
2288
|
-
console.log("[ImageTool] Loading EXISTING image...", {
|
|
2289
|
-
canvasW,
|
|
2290
|
-
canvasH,
|
|
2291
|
-
centerX,
|
|
2292
|
-
centerY,
|
|
2293
|
-
incomingLeft: left,
|
|
2294
|
-
incomingTop: top,
|
|
2295
|
-
dielinePos: configService == null ? void 0 : configService.get("dieline.position"),
|
|
2296
|
-
existingImage: !!existingImage
|
|
2297
|
-
});
|
|
2298
|
-
if (left !== void 0) {
|
|
2299
|
-
const globalLeft = Coordinate.toAbsolute(left, canvasW);
|
|
2300
|
-
targetLeft = globalLeft;
|
|
2301
|
-
console.log("[ImageTool] Calculated targetLeft", {
|
|
2302
|
-
globalLeft,
|
|
2303
|
-
targetLeft
|
|
2304
|
-
});
|
|
2305
|
-
}
|
|
2306
|
-
if (top !== void 0) {
|
|
2307
|
-
const globalTop = Coordinate.toAbsolute(top, canvasH);
|
|
2308
|
-
targetTop = globalTop;
|
|
2309
|
-
console.log("[ImageTool] Calculated targetTop", {
|
|
2310
|
-
globalTop,
|
|
2311
|
-
targetTop
|
|
2312
|
-
});
|
|
2313
|
-
}
|
|
2314
|
-
image.set({
|
|
2315
|
-
originX: "center",
|
|
2316
|
-
// Use center origin for easier positioning
|
|
2317
|
-
originY: "center",
|
|
2318
|
-
left: targetLeft,
|
|
2319
|
-
top: targetTop,
|
|
2320
|
-
angle: angle !== void 0 ? angle : defaultAngle,
|
|
2321
|
-
scaleX: width !== void 0 && image.width ? width / image.width : defaultScaleX,
|
|
2322
|
-
scaleY: height !== void 0 && image.height ? height / image.height : defaultScaleY
|
|
2323
|
-
});
|
|
2324
|
-
layer.remove(existingImage);
|
|
2325
|
-
} else {
|
|
2326
|
-
image.set({
|
|
2327
|
-
originX: "center",
|
|
2328
|
-
originY: "center"
|
|
2329
|
-
});
|
|
2330
|
-
if (width !== void 0 && image.width)
|
|
2331
|
-
image.scaleX = width / image.width;
|
|
2332
|
-
if (height !== void 0 && image.height)
|
|
2333
|
-
image.scaleY = height / image.height;
|
|
2334
|
-
if (angle !== void 0) image.angle = angle;
|
|
2335
|
-
const canvasW = ((_e = this.canvasService) == null ? void 0 : _e.canvas.width) || 800;
|
|
2336
|
-
const canvasH = ((_f = this.canvasService) == null ? void 0 : _f.canvas.height) || 600;
|
|
2337
|
-
const centerX = canvasW / 2;
|
|
2338
|
-
const centerY = canvasH / 2;
|
|
2339
|
-
if (left !== void 0) {
|
|
2340
|
-
image.left = Coordinate.toAbsolute(left, canvasW);
|
|
2341
|
-
} else {
|
|
2342
|
-
image.left = centerX;
|
|
2343
|
-
}
|
|
2344
|
-
if (top !== void 0) {
|
|
2345
|
-
image.top = Coordinate.toAbsolute(top, canvasH);
|
|
2381
|
+
loadImage(item, layer, layout) {
|
|
2382
|
+
import_fabric5.Image.fromURL(item.url, { crossOrigin: "anonymous" }).then((image) => {
|
|
2383
|
+
var _a;
|
|
2384
|
+
if (!this.items.find((i) => i.id === item.id)) return;
|
|
2385
|
+
image.set({
|
|
2386
|
+
originX: "center",
|
|
2387
|
+
originY: "center",
|
|
2388
|
+
data: { id: item.id }
|
|
2389
|
+
});
|
|
2390
|
+
let { width, height, left, top } = item;
|
|
2391
|
+
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, dielinePhysicalWidth, dielinePhysicalHeight } = layout;
|
|
2392
|
+
if (width === void 0 && height === void 0) {
|
|
2393
|
+
const imgAspect = (image.width || 1) / (image.height || 1);
|
|
2394
|
+
const dielineAspect = dielinePhysicalWidth / dielinePhysicalHeight;
|
|
2395
|
+
if (imgAspect > dielineAspect) {
|
|
2396
|
+
const w = dielinePhysicalWidth;
|
|
2397
|
+
width = w;
|
|
2398
|
+
height = w / imgAspect;
|
|
2346
2399
|
} else {
|
|
2347
|
-
|
|
2400
|
+
const h = dielinePhysicalHeight;
|
|
2401
|
+
height = h;
|
|
2402
|
+
width = h * imgAspect;
|
|
2348
2403
|
}
|
|
2404
|
+
item.width = width;
|
|
2405
|
+
item.height = height;
|
|
2349
2406
|
}
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
}
|
|
2407
|
+
if (left === void 0 && top === void 0) {
|
|
2408
|
+
left = 0.5;
|
|
2409
|
+
top = 0.5;
|
|
2410
|
+
item.left = left;
|
|
2411
|
+
item.top = top;
|
|
2412
|
+
}
|
|
2413
|
+
this.updateObjectProperties(image, item, layout);
|
|
2356
2414
|
layer.add(image);
|
|
2415
|
+
this.objectMap.set(item.id, image);
|
|
2357
2416
|
image.on("modified", (e) => {
|
|
2358
|
-
|
|
2359
|
-
const matrix = image.calcTransformMatrix();
|
|
2360
|
-
const globalPoint = import_fabric5.util.transformPoint(new import_fabric5.Point(0, 0), matrix);
|
|
2361
|
-
const canvasW = ((_a2 = this.canvasService) == null ? void 0 : _a2.canvas.width) || 800;
|
|
2362
|
-
const canvasH = ((_b2 = this.canvasService) == null ? void 0 : _b2.canvas.height) || 600;
|
|
2363
|
-
this.left = Coordinate.toNormalized(globalPoint.x, canvasW);
|
|
2364
|
-
this.top = Coordinate.toNormalized(globalPoint.y, canvasH);
|
|
2365
|
-
this.angle = e.target.angle;
|
|
2366
|
-
if (image.width) this.width = e.target.width * e.target.scaleX;
|
|
2367
|
-
if (image.height) this.height = e.target.height * e.target.scaleY;
|
|
2368
|
-
if (this.context) {
|
|
2369
|
-
this.context.eventBus.emit("update");
|
|
2370
|
-
}
|
|
2417
|
+
this.handleObjectModified(item.id, image);
|
|
2371
2418
|
});
|
|
2372
2419
|
layer.dirty = true;
|
|
2373
|
-
this.canvasService.requestRenderAll();
|
|
2420
|
+
(_a = this.canvasService) == null ? void 0 : _a.requestRenderAll();
|
|
2421
|
+
if (item.width !== width || item.height !== height || item.left !== left || item.top !== top) {
|
|
2422
|
+
this.updateImageInConfig(item.id, { width, height, left, top });
|
|
2423
|
+
}
|
|
2374
2424
|
}).catch((err) => {
|
|
2375
|
-
|
|
2376
|
-
console.error("Failed to load image", url, err);
|
|
2425
|
+
console.error("Failed to load image", item.url, err);
|
|
2377
2426
|
});
|
|
2378
2427
|
}
|
|
2428
|
+
handleObjectModified(id, image) {
|
|
2429
|
+
const layout = this.getLayoutInfo();
|
|
2430
|
+
const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight } = layout;
|
|
2431
|
+
const matrix = image.calcTransformMatrix();
|
|
2432
|
+
const globalPoint = import_fabric5.util.transformPoint(new import_fabric5.Point(0, 0), matrix);
|
|
2433
|
+
const updates = {};
|
|
2434
|
+
updates.left = (globalPoint.x - layoutOffsetX) / visualWidth;
|
|
2435
|
+
updates.top = (globalPoint.y - layoutOffsetY) / visualHeight;
|
|
2436
|
+
updates.angle = image.angle;
|
|
2437
|
+
if (image.width) {
|
|
2438
|
+
const pixelWidth = image.width * image.scaleX;
|
|
2439
|
+
updates.width = pixelWidth / layoutScale;
|
|
2440
|
+
}
|
|
2441
|
+
if (image.height) {
|
|
2442
|
+
const pixelHeight = image.height * image.scaleY;
|
|
2443
|
+
updates.height = pixelHeight / layoutScale;
|
|
2444
|
+
}
|
|
2445
|
+
this.updateImageInConfig(id, updates);
|
|
2446
|
+
}
|
|
2447
|
+
updateImageInConfig(id, updates) {
|
|
2448
|
+
const index = this.items.findIndex((i) => i.id === id);
|
|
2449
|
+
if (index !== -1) {
|
|
2450
|
+
const newItems = [...this.items];
|
|
2451
|
+
newItems[index] = { ...newItems[index], ...updates };
|
|
2452
|
+
this.updateConfig(newItems, true);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2379
2455
|
};
|
|
2380
2456
|
|
|
2381
2457
|
// src/white-ink.ts
|
|
@@ -2678,12 +2754,18 @@ var RulerTool = class {
|
|
|
2678
2754
|
this.metadata = {
|
|
2679
2755
|
name: "RulerTool"
|
|
2680
2756
|
};
|
|
2681
|
-
this.unit = "px";
|
|
2682
2757
|
this.thickness = 20;
|
|
2758
|
+
this.gap = 15;
|
|
2683
2759
|
this.backgroundColor = "#f0f0f0";
|
|
2684
2760
|
this.textColor = "#333333";
|
|
2685
2761
|
this.lineColor = "#999999";
|
|
2686
2762
|
this.fontSize = 10;
|
|
2763
|
+
// Dieline context for sync
|
|
2764
|
+
this.dielineWidth = 500;
|
|
2765
|
+
this.dielineHeight = 500;
|
|
2766
|
+
this.dielineUnit = "mm";
|
|
2767
|
+
this.dielinePadding = 40;
|
|
2768
|
+
this.dielineOffset = 0;
|
|
2687
2769
|
if (options) {
|
|
2688
2770
|
Object.assign(this, options);
|
|
2689
2771
|
}
|
|
@@ -2696,8 +2778,8 @@ var RulerTool = class {
|
|
|
2696
2778
|
}
|
|
2697
2779
|
const configService = context.services.get("ConfigurationService");
|
|
2698
2780
|
if (configService) {
|
|
2699
|
-
this.unit = configService.get("ruler.unit", this.unit);
|
|
2700
2781
|
this.thickness = configService.get("ruler.thickness", this.thickness);
|
|
2782
|
+
this.gap = configService.get("ruler.gap", this.gap);
|
|
2701
2783
|
this.backgroundColor = configService.get(
|
|
2702
2784
|
"ruler.backgroundColor",
|
|
2703
2785
|
this.backgroundColor
|
|
@@ -2705,13 +2787,38 @@ var RulerTool = class {
|
|
|
2705
2787
|
this.textColor = configService.get("ruler.textColor", this.textColor);
|
|
2706
2788
|
this.lineColor = configService.get("ruler.lineColor", this.lineColor);
|
|
2707
2789
|
this.fontSize = configService.get("ruler.fontSize", this.fontSize);
|
|
2790
|
+
this.dielineUnit = configService.get("dieline.unit", this.dielineUnit);
|
|
2791
|
+
this.dielineWidth = configService.get("dieline.width", this.dielineWidth);
|
|
2792
|
+
this.dielineHeight = configService.get(
|
|
2793
|
+
"dieline.height",
|
|
2794
|
+
this.dielineHeight
|
|
2795
|
+
);
|
|
2796
|
+
this.dielinePadding = configService.get(
|
|
2797
|
+
"dieline.padding",
|
|
2798
|
+
this.dielinePadding
|
|
2799
|
+
);
|
|
2800
|
+
this.dielineOffset = configService.get(
|
|
2801
|
+
"dieline.offset",
|
|
2802
|
+
this.dielineOffset
|
|
2803
|
+
);
|
|
2708
2804
|
configService.onAnyChange((e) => {
|
|
2805
|
+
let shouldUpdate = false;
|
|
2709
2806
|
if (e.key.startsWith("ruler.")) {
|
|
2710
2807
|
const prop = e.key.split(".")[1];
|
|
2711
2808
|
if (prop && prop in this) {
|
|
2712
2809
|
this[prop] = e.value;
|
|
2713
|
-
|
|
2810
|
+
shouldUpdate = true;
|
|
2714
2811
|
}
|
|
2812
|
+
} else if (e.key.startsWith("dieline.")) {
|
|
2813
|
+
if (e.key === "dieline.unit") this.dielineUnit = e.value;
|
|
2814
|
+
if (e.key === "dieline.width") this.dielineWidth = e.value;
|
|
2815
|
+
if (e.key === "dieline.height") this.dielineHeight = e.value;
|
|
2816
|
+
if (e.key === "dieline.padding") this.dielinePadding = e.value;
|
|
2817
|
+
if (e.key === "dieline.offset") this.dielineOffset = e.value;
|
|
2818
|
+
shouldUpdate = true;
|
|
2819
|
+
}
|
|
2820
|
+
if (shouldUpdate) {
|
|
2821
|
+
this.updateRuler();
|
|
2715
2822
|
}
|
|
2716
2823
|
});
|
|
2717
2824
|
}
|
|
@@ -2725,13 +2832,6 @@ var RulerTool = class {
|
|
|
2725
2832
|
contribute() {
|
|
2726
2833
|
return {
|
|
2727
2834
|
[import_core7.ContributionPointIds.CONFIGURATIONS]: [
|
|
2728
|
-
{
|
|
2729
|
-
id: "ruler.unit",
|
|
2730
|
-
type: "select",
|
|
2731
|
-
label: "Unit",
|
|
2732
|
-
options: ["px", "mm", "cm", "in"],
|
|
2733
|
-
default: "px"
|
|
2734
|
-
},
|
|
2735
2835
|
{
|
|
2736
2836
|
id: "ruler.thickness",
|
|
2737
2837
|
type: "number",
|
|
@@ -2740,6 +2840,14 @@ var RulerTool = class {
|
|
|
2740
2840
|
max: 100,
|
|
2741
2841
|
default: 20
|
|
2742
2842
|
},
|
|
2843
|
+
{
|
|
2844
|
+
id: "ruler.gap",
|
|
2845
|
+
type: "number",
|
|
2846
|
+
label: "Gap",
|
|
2847
|
+
min: 0,
|
|
2848
|
+
max: 100,
|
|
2849
|
+
default: 15
|
|
2850
|
+
},
|
|
2743
2851
|
{
|
|
2744
2852
|
id: "ruler.backgroundColor",
|
|
2745
2853
|
type: "color",
|
|
@@ -2768,16 +2876,6 @@ var RulerTool = class {
|
|
|
2768
2876
|
}
|
|
2769
2877
|
],
|
|
2770
2878
|
[import_core7.ContributionPointIds.COMMANDS]: [
|
|
2771
|
-
{
|
|
2772
|
-
command: "setUnit",
|
|
2773
|
-
title: "Set Ruler Unit",
|
|
2774
|
-
handler: (unit) => {
|
|
2775
|
-
if (this.unit === unit) return true;
|
|
2776
|
-
this.unit = unit;
|
|
2777
|
-
this.updateRuler();
|
|
2778
|
-
return true;
|
|
2779
|
-
}
|
|
2780
|
-
},
|
|
2781
2879
|
{
|
|
2782
2880
|
command: "setTheme",
|
|
2783
2881
|
title: "Set Ruler Theme",
|
|
@@ -2828,6 +2926,68 @@ var RulerTool = class {
|
|
|
2828
2926
|
this.canvasService.canvas.remove(layer);
|
|
2829
2927
|
}
|
|
2830
2928
|
}
|
|
2929
|
+
createArrowLine(x1, y1, x2, y2, color) {
|
|
2930
|
+
const line = new import_fabric7.Line([x1, y1, x2, y2], {
|
|
2931
|
+
stroke: color,
|
|
2932
|
+
strokeWidth: this.thickness / 20,
|
|
2933
|
+
// Scale stroke width relative to thickness (default 1)
|
|
2934
|
+
selectable: false,
|
|
2935
|
+
evented: false
|
|
2936
|
+
});
|
|
2937
|
+
const arrowSize = Math.max(4, this.thickness * 0.3);
|
|
2938
|
+
const angle = Math.atan2(y2 - y1, x2 - x1);
|
|
2939
|
+
const endArrow = new import_fabric7.Polygon(
|
|
2940
|
+
[
|
|
2941
|
+
{ x: 0, y: 0 },
|
|
2942
|
+
{ x: -arrowSize, y: -arrowSize / 2 },
|
|
2943
|
+
{ x: -arrowSize, y: arrowSize / 2 }
|
|
2944
|
+
],
|
|
2945
|
+
{
|
|
2946
|
+
fill: color,
|
|
2947
|
+
left: x2,
|
|
2948
|
+
top: y2,
|
|
2949
|
+
originX: "right",
|
|
2950
|
+
originY: "center",
|
|
2951
|
+
angle: angle * 180 / Math.PI,
|
|
2952
|
+
selectable: false,
|
|
2953
|
+
evented: false
|
|
2954
|
+
}
|
|
2955
|
+
);
|
|
2956
|
+
const startArrow = new import_fabric7.Polygon(
|
|
2957
|
+
[
|
|
2958
|
+
{ x: 0, y: 0 },
|
|
2959
|
+
{ x: arrowSize, y: -arrowSize / 2 },
|
|
2960
|
+
{ x: arrowSize, y: arrowSize / 2 }
|
|
2961
|
+
],
|
|
2962
|
+
{
|
|
2963
|
+
fill: color,
|
|
2964
|
+
left: x1,
|
|
2965
|
+
top: y1,
|
|
2966
|
+
originX: "left",
|
|
2967
|
+
originY: "center",
|
|
2968
|
+
angle: angle * 180 / Math.PI,
|
|
2969
|
+
selectable: false,
|
|
2970
|
+
evented: false
|
|
2971
|
+
}
|
|
2972
|
+
);
|
|
2973
|
+
return new import_fabric7.Group([line, startArrow, endArrow], {
|
|
2974
|
+
selectable: false,
|
|
2975
|
+
evented: false
|
|
2976
|
+
});
|
|
2977
|
+
}
|
|
2978
|
+
resolvePadding(containerWidth, containerHeight) {
|
|
2979
|
+
if (typeof this.dielinePadding === "number") {
|
|
2980
|
+
return this.dielinePadding;
|
|
2981
|
+
}
|
|
2982
|
+
if (typeof this.dielinePadding === "string") {
|
|
2983
|
+
if (this.dielinePadding.endsWith("%")) {
|
|
2984
|
+
const percent = parseFloat(this.dielinePadding) / 100;
|
|
2985
|
+
return Math.min(containerWidth, containerHeight) * percent;
|
|
2986
|
+
}
|
|
2987
|
+
return parseFloat(this.dielinePadding) || 0;
|
|
2988
|
+
}
|
|
2989
|
+
return 0;
|
|
2990
|
+
}
|
|
2831
2991
|
updateRuler() {
|
|
2832
2992
|
if (!this.canvasService) return;
|
|
2833
2993
|
const layer = this.getLayer();
|
|
@@ -2836,95 +2996,141 @@ var RulerTool = class {
|
|
|
2836
2996
|
const { thickness, backgroundColor, lineColor, textColor, fontSize } = this;
|
|
2837
2997
|
const width = this.canvasService.canvas.width || 800;
|
|
2838
2998
|
const height = this.canvasService.canvas.height || 600;
|
|
2839
|
-
const
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
width,
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
const
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
const
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2999
|
+
const paddingPx = this.resolvePadding(width, height);
|
|
3000
|
+
const layout = Coordinate.calculateLayout(
|
|
3001
|
+
{ width, height },
|
|
3002
|
+
{ width: this.dielineWidth, height: this.dielineHeight },
|
|
3003
|
+
paddingPx
|
|
3004
|
+
);
|
|
3005
|
+
const scale = layout.scale;
|
|
3006
|
+
const offsetX = layout.offsetX;
|
|
3007
|
+
const offsetY = layout.offsetY;
|
|
3008
|
+
const visualWidth = layout.width;
|
|
3009
|
+
const visualHeight = layout.height;
|
|
3010
|
+
const rawOffset = this.dielineOffset || 0;
|
|
3011
|
+
const effectiveOffset = rawOffset > 0 ? rawOffset : 0;
|
|
3012
|
+
const expandPixels = effectiveOffset * scale;
|
|
3013
|
+
const gap = this.gap || 15;
|
|
3014
|
+
const rulerLeft = offsetX - expandPixels;
|
|
3015
|
+
const rulerTop = offsetY - expandPixels;
|
|
3016
|
+
const rulerRight = offsetX + visualWidth + expandPixels;
|
|
3017
|
+
const rulerBottom = offsetY + visualHeight + expandPixels;
|
|
3018
|
+
const displayWidth = this.dielineWidth + effectiveOffset * 2;
|
|
3019
|
+
const displayHeight = this.dielineHeight + effectiveOffset * 2;
|
|
3020
|
+
const topRulerY = rulerTop - gap;
|
|
3021
|
+
const topRulerXStart = rulerLeft;
|
|
3022
|
+
const topRulerXEnd = rulerRight;
|
|
3023
|
+
const leftRulerX = rulerLeft - gap;
|
|
3024
|
+
const leftRulerYStart = rulerTop;
|
|
3025
|
+
const leftRulerYEnd = rulerBottom;
|
|
3026
|
+
const topDimLine = this.createArrowLine(
|
|
3027
|
+
topRulerXStart,
|
|
3028
|
+
topRulerY,
|
|
3029
|
+
topRulerXEnd,
|
|
3030
|
+
topRulerY,
|
|
3031
|
+
lineColor
|
|
3032
|
+
);
|
|
3033
|
+
layer.add(topDimLine);
|
|
3034
|
+
const extLen = 5;
|
|
3035
|
+
layer.add(
|
|
3036
|
+
new import_fabric7.Line(
|
|
3037
|
+
[
|
|
3038
|
+
topRulerXStart,
|
|
3039
|
+
topRulerY - extLen,
|
|
3040
|
+
topRulerXStart,
|
|
3041
|
+
topRulerY + extLen
|
|
3042
|
+
],
|
|
3043
|
+
{
|
|
3044
|
+
stroke: lineColor,
|
|
3045
|
+
strokeWidth: 1,
|
|
3046
|
+
selectable: false,
|
|
3047
|
+
evented: false
|
|
3048
|
+
}
|
|
3049
|
+
)
|
|
3050
|
+
);
|
|
3051
|
+
layer.add(
|
|
3052
|
+
new import_fabric7.Line(
|
|
3053
|
+
[topRulerXEnd, topRulerY - extLen, topRulerXEnd, topRulerY + extLen],
|
|
3054
|
+
{
|
|
3055
|
+
stroke: lineColor,
|
|
3056
|
+
strokeWidth: 1,
|
|
3057
|
+
selectable: false,
|
|
3058
|
+
evented: false
|
|
3059
|
+
}
|
|
3060
|
+
)
|
|
3061
|
+
);
|
|
3062
|
+
const widthStr = parseFloat(displayWidth.toFixed(2)).toString();
|
|
3063
|
+
const topTextContent = `${widthStr} ${this.dielineUnit}`;
|
|
3064
|
+
const topText = new import_fabric7.Text(topTextContent, {
|
|
3065
|
+
left: topRulerXStart + (rulerRight - rulerLeft) / 2,
|
|
3066
|
+
top: topRulerY,
|
|
3067
|
+
fontSize,
|
|
3068
|
+
fill: textColor,
|
|
3069
|
+
fontFamily: "Arial",
|
|
3070
|
+
originX: "center",
|
|
3071
|
+
originY: "center",
|
|
3072
|
+
backgroundColor,
|
|
3073
|
+
// Background mask for readability
|
|
2865
3074
|
selectable: false,
|
|
2866
3075
|
evented: false
|
|
2867
3076
|
});
|
|
2868
|
-
layer.add(
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
left: x + 2,
|
|
2889
|
-
top: 2,
|
|
2890
|
-
fontSize,
|
|
2891
|
-
fill: textColor,
|
|
2892
|
-
fontFamily: "Arial",
|
|
3077
|
+
layer.add(topText);
|
|
3078
|
+
const leftDimLine = this.createArrowLine(
|
|
3079
|
+
leftRulerX,
|
|
3080
|
+
leftRulerYStart,
|
|
3081
|
+
leftRulerX,
|
|
3082
|
+
leftRulerYEnd,
|
|
3083
|
+
lineColor
|
|
3084
|
+
);
|
|
3085
|
+
layer.add(leftDimLine);
|
|
3086
|
+
layer.add(
|
|
3087
|
+
new import_fabric7.Line(
|
|
3088
|
+
[
|
|
3089
|
+
leftRulerX - extLen,
|
|
3090
|
+
leftRulerYStart,
|
|
3091
|
+
leftRulerX + extLen,
|
|
3092
|
+
leftRulerYStart
|
|
3093
|
+
],
|
|
3094
|
+
{
|
|
3095
|
+
stroke: lineColor,
|
|
3096
|
+
strokeWidth: 1,
|
|
2893
3097
|
selectable: false,
|
|
2894
3098
|
evented: false
|
|
2895
|
-
}
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
});
|
|
2910
|
-
layer.add(line);
|
|
2911
|
-
if (y % step === 0) {
|
|
2912
|
-
const text = new import_fabric7.Text(y.toString(), {
|
|
2913
|
-
angle: -90,
|
|
2914
|
-
left: thickness / 2 - fontSize / 3,
|
|
2915
|
-
// approximate centering
|
|
2916
|
-
top: y + fontSize,
|
|
2917
|
-
fontSize,
|
|
2918
|
-
fill: textColor,
|
|
2919
|
-
fontFamily: "Arial",
|
|
2920
|
-
originX: "center",
|
|
2921
|
-
originY: "center",
|
|
3099
|
+
}
|
|
3100
|
+
)
|
|
3101
|
+
);
|
|
3102
|
+
layer.add(
|
|
3103
|
+
new import_fabric7.Line(
|
|
3104
|
+
[
|
|
3105
|
+
leftRulerX - extLen,
|
|
3106
|
+
leftRulerYEnd,
|
|
3107
|
+
leftRulerX + extLen,
|
|
3108
|
+
leftRulerYEnd
|
|
3109
|
+
],
|
|
3110
|
+
{
|
|
3111
|
+
stroke: lineColor,
|
|
3112
|
+
strokeWidth: 1,
|
|
2922
3113
|
selectable: false,
|
|
2923
3114
|
evented: false
|
|
2924
|
-
}
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
3115
|
+
}
|
|
3116
|
+
)
|
|
3117
|
+
);
|
|
3118
|
+
const heightStr = parseFloat(displayHeight.toFixed(2)).toString();
|
|
3119
|
+
const leftTextContent = `${heightStr} ${this.dielineUnit}`;
|
|
3120
|
+
const leftText = new import_fabric7.Text(leftTextContent, {
|
|
3121
|
+
left: leftRulerX,
|
|
3122
|
+
top: leftRulerYStart + (rulerBottom - rulerTop) / 2,
|
|
3123
|
+
angle: -90,
|
|
3124
|
+
fontSize,
|
|
3125
|
+
fill: textColor,
|
|
3126
|
+
fontFamily: "Arial",
|
|
3127
|
+
originX: "center",
|
|
3128
|
+
originY: "center",
|
|
3129
|
+
backgroundColor,
|
|
3130
|
+
selectable: false,
|
|
3131
|
+
evented: false
|
|
3132
|
+
});
|
|
3133
|
+
layer.add(leftText);
|
|
2928
3134
|
this.canvasService.canvas.bringObjectToFront(layer);
|
|
2929
3135
|
this.canvasService.canvas.requestRenderAll();
|
|
2930
3136
|
}
|