@pooder/kit 6.2.0 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.test-dist/src/extensions/dieline/DielineTool.js +22 -9
- package/.test-dist/src/extensions/dieline/renderBuilder.js +28 -12
- package/.test-dist/src/extensions/feature/FeatureTool.js +20 -3
- package/.test-dist/src/extensions/featureCoordinates.js +21 -0
- package/.test-dist/src/extensions/featurePlacement.js +46 -0
- package/.test-dist/src/extensions/ruler/RulerTool.js +24 -1
- package/.test-dist/tests/run.js +25 -0
- package/CHANGELOG.md +6 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +357 -197
- package/dist/index.mjs +357 -197
- package/package.json +1 -1
- package/src/extensions/dieline/DielineTool.ts +29 -9
- package/src/extensions/dieline/renderBuilder.ts +39 -13
- package/src/extensions/feature/FeatureTool.ts +23 -3
- package/src/extensions/featureCoordinates.ts +35 -0
- package/src/extensions/featurePlacement.ts +118 -0
- package/src/extensions/ruler/RulerTool.ts +24 -2
- package/tests/run.ts +37 -0
package/dist/index.js
CHANGED
|
@@ -5656,6 +5656,259 @@ function readDielineState(configService, fallback) {
|
|
|
5656
5656
|
};
|
|
5657
5657
|
}
|
|
5658
5658
|
|
|
5659
|
+
// src/extensions/constraints.ts
|
|
5660
|
+
var ConstraintRegistry = class {
|
|
5661
|
+
static register(type, handler) {
|
|
5662
|
+
this.handlers.set(type, handler);
|
|
5663
|
+
}
|
|
5664
|
+
static apply(x, y, feature, context, constraints) {
|
|
5665
|
+
const list = constraints || feature.constraints;
|
|
5666
|
+
if (!list || list.length === 0) {
|
|
5667
|
+
return { x, y };
|
|
5668
|
+
}
|
|
5669
|
+
let currentX = x;
|
|
5670
|
+
let currentY = y;
|
|
5671
|
+
for (const constraint of list) {
|
|
5672
|
+
const handler = this.handlers.get(constraint.type);
|
|
5673
|
+
if (handler) {
|
|
5674
|
+
const result = handler(currentX, currentY, feature, context, constraint.params || {});
|
|
5675
|
+
currentX = result.x;
|
|
5676
|
+
currentY = result.y;
|
|
5677
|
+
}
|
|
5678
|
+
}
|
|
5679
|
+
return { x: currentX, y: currentY };
|
|
5680
|
+
}
|
|
5681
|
+
};
|
|
5682
|
+
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
5683
|
+
var pathConstraint = (x, y, feature, context, params) => {
|
|
5684
|
+
const { dielineWidth, dielineHeight, geometry } = context;
|
|
5685
|
+
if (!geometry) return { x, y };
|
|
5686
|
+
const minX = geometry.x - geometry.width / 2;
|
|
5687
|
+
const minY = geometry.y - geometry.height / 2;
|
|
5688
|
+
const absX = minX + x * geometry.width;
|
|
5689
|
+
const absY = minY + y * geometry.height;
|
|
5690
|
+
const nearest = getNearestPointOnDieline(
|
|
5691
|
+
{ x: absX, y: absY },
|
|
5692
|
+
geometry
|
|
5693
|
+
);
|
|
5694
|
+
let finalX = nearest.x;
|
|
5695
|
+
let finalY = nearest.y;
|
|
5696
|
+
const hasOffsetParams = params.minOffset !== void 0 || params.maxOffset !== void 0;
|
|
5697
|
+
if (hasOffsetParams && nearest.normal) {
|
|
5698
|
+
const dx = absX - nearest.x;
|
|
5699
|
+
const dy = absY - nearest.y;
|
|
5700
|
+
const nx2 = nearest.normal.x;
|
|
5701
|
+
const ny2 = nearest.normal.y;
|
|
5702
|
+
const dist = dx * nx2 + dy * ny2;
|
|
5703
|
+
const scale = dielineWidth > 0 ? geometry.width / dielineWidth : 1;
|
|
5704
|
+
const rawMin = params.minOffset !== void 0 ? params.minOffset : 0;
|
|
5705
|
+
const rawMax = params.maxOffset !== void 0 ? params.maxOffset : 0;
|
|
5706
|
+
const minOffset = rawMin * scale;
|
|
5707
|
+
const maxOffset = rawMax * scale;
|
|
5708
|
+
const clampedDist = Math.max(minOffset, Math.min(dist, maxOffset));
|
|
5709
|
+
finalX = nearest.x + nx2 * clampedDist;
|
|
5710
|
+
finalY = nearest.y + ny2 * clampedDist;
|
|
5711
|
+
}
|
|
5712
|
+
const nx = geometry.width > 0 ? (finalX - minX) / geometry.width : 0.5;
|
|
5713
|
+
const ny = geometry.height > 0 ? (finalY - minY) / geometry.height : 0.5;
|
|
5714
|
+
return { x: nx, y: ny };
|
|
5715
|
+
};
|
|
5716
|
+
var edgeConstraint = (x, y, feature, context, params) => {
|
|
5717
|
+
const { dielineWidth, dielineHeight } = context;
|
|
5718
|
+
const allowedEdges = params.allowedEdges || [
|
|
5719
|
+
"top",
|
|
5720
|
+
"bottom",
|
|
5721
|
+
"left",
|
|
5722
|
+
"right"
|
|
5723
|
+
];
|
|
5724
|
+
const confine = params.confine || false;
|
|
5725
|
+
const offset = params.offset || 0;
|
|
5726
|
+
const distances = [];
|
|
5727
|
+
if (allowedEdges.includes("top"))
|
|
5728
|
+
distances.push({ edge: "top", dist: y * dielineHeight });
|
|
5729
|
+
if (allowedEdges.includes("bottom"))
|
|
5730
|
+
distances.push({ edge: "bottom", dist: (1 - y) * dielineHeight });
|
|
5731
|
+
if (allowedEdges.includes("left"))
|
|
5732
|
+
distances.push({ edge: "left", dist: x * dielineWidth });
|
|
5733
|
+
if (allowedEdges.includes("right"))
|
|
5734
|
+
distances.push({ edge: "right", dist: (1 - x) * dielineWidth });
|
|
5735
|
+
if (distances.length === 0) return { x, y };
|
|
5736
|
+
distances.sort((a, b) => a.dist - b.dist);
|
|
5737
|
+
const nearest = distances[0].edge;
|
|
5738
|
+
let newX = x;
|
|
5739
|
+
let newY = y;
|
|
5740
|
+
const fw = feature.width || 0;
|
|
5741
|
+
const fh = feature.height || 0;
|
|
5742
|
+
switch (nearest) {
|
|
5743
|
+
case "top":
|
|
5744
|
+
newY = 0 + offset / dielineHeight;
|
|
5745
|
+
if (confine) {
|
|
5746
|
+
const minX = fw / 2 / dielineWidth;
|
|
5747
|
+
const maxX = 1 - minX;
|
|
5748
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
5749
|
+
}
|
|
5750
|
+
break;
|
|
5751
|
+
case "bottom":
|
|
5752
|
+
newY = 1 - offset / dielineHeight;
|
|
5753
|
+
if (confine) {
|
|
5754
|
+
const minX = fw / 2 / dielineWidth;
|
|
5755
|
+
const maxX = 1 - minX;
|
|
5756
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
5757
|
+
}
|
|
5758
|
+
break;
|
|
5759
|
+
case "left":
|
|
5760
|
+
newX = 0 + offset / dielineWidth;
|
|
5761
|
+
if (confine) {
|
|
5762
|
+
const minY = fh / 2 / dielineHeight;
|
|
5763
|
+
const maxY = 1 - minY;
|
|
5764
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
5765
|
+
}
|
|
5766
|
+
break;
|
|
5767
|
+
case "right":
|
|
5768
|
+
newX = 1 - offset / dielineWidth;
|
|
5769
|
+
if (confine) {
|
|
5770
|
+
const minY = fh / 2 / dielineHeight;
|
|
5771
|
+
const maxY = 1 - minY;
|
|
5772
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
5773
|
+
}
|
|
5774
|
+
break;
|
|
5775
|
+
}
|
|
5776
|
+
return { x: newX, y: newY };
|
|
5777
|
+
};
|
|
5778
|
+
var internalConstraint = (x, y, feature, context, params) => {
|
|
5779
|
+
const { dielineWidth, dielineHeight } = context;
|
|
5780
|
+
const margin = params.margin || 0;
|
|
5781
|
+
const fw = feature.width || 0;
|
|
5782
|
+
const fh = feature.height || 0;
|
|
5783
|
+
const minX = (margin + fw / 2) / dielineWidth;
|
|
5784
|
+
const maxX = 1 - (margin + fw / 2) / dielineWidth;
|
|
5785
|
+
const minY = (margin + fh / 2) / dielineHeight;
|
|
5786
|
+
const maxY = 1 - (margin + fh / 2) / dielineHeight;
|
|
5787
|
+
const clampedX = minX > maxX ? 0.5 : Math.max(minX, Math.min(x, maxX));
|
|
5788
|
+
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
5789
|
+
return { x: clampedX, y: clampedY };
|
|
5790
|
+
};
|
|
5791
|
+
var tangentBottomConstraint = (x, y, feature, context, params) => {
|
|
5792
|
+
const { dielineWidth, dielineHeight } = context;
|
|
5793
|
+
const gap = params.gap || 0;
|
|
5794
|
+
const confineX = params.confineX !== false;
|
|
5795
|
+
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
5796
|
+
const newY = 1 + (extentY + gap) / dielineHeight;
|
|
5797
|
+
let newX = x;
|
|
5798
|
+
if (confineX) {
|
|
5799
|
+
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
5800
|
+
const minX = extentX / dielineWidth;
|
|
5801
|
+
const maxX = 1 - extentX / dielineWidth;
|
|
5802
|
+
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
5803
|
+
}
|
|
5804
|
+
return { x: newX, y: newY };
|
|
5805
|
+
};
|
|
5806
|
+
var lowestTangentConstraint = (x, y, feature, context, params) => {
|
|
5807
|
+
const { dielineWidth, dielineHeight, geometry } = context;
|
|
5808
|
+
if (!geometry) return { x, y };
|
|
5809
|
+
const lowest = getLowestPointOnDieline(geometry);
|
|
5810
|
+
const minY = geometry.y - geometry.height / 2;
|
|
5811
|
+
const normY = (lowest.y - minY) / geometry.height;
|
|
5812
|
+
const gap = params.gap || 0;
|
|
5813
|
+
const confineX = params.confineX !== false;
|
|
5814
|
+
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
5815
|
+
const newY = normY + (extentY + gap) / dielineHeight;
|
|
5816
|
+
let newX = x;
|
|
5817
|
+
if (confineX) {
|
|
5818
|
+
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
5819
|
+
const minX = extentX / dielineWidth;
|
|
5820
|
+
const maxX = 1 - extentX / dielineWidth;
|
|
5821
|
+
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
5822
|
+
}
|
|
5823
|
+
return { x: newX, y: newY };
|
|
5824
|
+
};
|
|
5825
|
+
ConstraintRegistry.register("path", pathConstraint);
|
|
5826
|
+
ConstraintRegistry.register("edge", edgeConstraint);
|
|
5827
|
+
ConstraintRegistry.register("internal", internalConstraint);
|
|
5828
|
+
ConstraintRegistry.register("tangent-bottom", tangentBottomConstraint);
|
|
5829
|
+
ConstraintRegistry.register("lowest-tangent", lowestTangentConstraint);
|
|
5830
|
+
|
|
5831
|
+
// src/extensions/featureCoordinates.ts
|
|
5832
|
+
function resolveFeaturePosition2(feature, geometry) {
|
|
5833
|
+
const { x, y, width, height } = geometry;
|
|
5834
|
+
const left = x - width / 2;
|
|
5835
|
+
const top = y - height / 2;
|
|
5836
|
+
return {
|
|
5837
|
+
x: left + feature.x * width,
|
|
5838
|
+
y: top + feature.y * height
|
|
5839
|
+
};
|
|
5840
|
+
}
|
|
5841
|
+
function normalizePointInGeometry(point, geometry) {
|
|
5842
|
+
const left = geometry.x - geometry.width / 2;
|
|
5843
|
+
const top = geometry.y - geometry.height / 2;
|
|
5844
|
+
return {
|
|
5845
|
+
x: geometry.width > 0 ? (point.x - left) / geometry.width : 0.5,
|
|
5846
|
+
y: geometry.height > 0 ? (point.y - top) / geometry.height : 0.5
|
|
5847
|
+
};
|
|
5848
|
+
}
|
|
5849
|
+
|
|
5850
|
+
// src/extensions/featurePlacement.ts
|
|
5851
|
+
function scaleFeatureForRender(feature, scale, x, y) {
|
|
5852
|
+
return {
|
|
5853
|
+
...feature,
|
|
5854
|
+
x,
|
|
5855
|
+
y,
|
|
5856
|
+
width: feature.width !== void 0 ? feature.width * scale : void 0,
|
|
5857
|
+
height: feature.height !== void 0 ? feature.height * scale : void 0,
|
|
5858
|
+
radius: feature.radius !== void 0 ? feature.radius * scale : void 0
|
|
5859
|
+
};
|
|
5860
|
+
}
|
|
5861
|
+
function resolveFeaturePlacements(features, geometry) {
|
|
5862
|
+
const dielineWidth = geometry.scale > 0 ? geometry.width / geometry.scale : geometry.width;
|
|
5863
|
+
const dielineHeight = geometry.scale > 0 ? geometry.height / geometry.scale : geometry.height;
|
|
5864
|
+
return (features || []).map((feature) => {
|
|
5865
|
+
var _a;
|
|
5866
|
+
const activeConstraints = (_a = feature.constraints) == null ? void 0 : _a.filter(
|
|
5867
|
+
(constraint) => !constraint.validateOnly
|
|
5868
|
+
);
|
|
5869
|
+
const constrained = ConstraintRegistry.apply(
|
|
5870
|
+
feature.x,
|
|
5871
|
+
feature.y,
|
|
5872
|
+
feature,
|
|
5873
|
+
{
|
|
5874
|
+
dielineWidth,
|
|
5875
|
+
dielineHeight,
|
|
5876
|
+
geometry
|
|
5877
|
+
},
|
|
5878
|
+
activeConstraints
|
|
5879
|
+
);
|
|
5880
|
+
const center = resolveFeaturePosition2(
|
|
5881
|
+
{
|
|
5882
|
+
...feature,
|
|
5883
|
+
x: constrained.x,
|
|
5884
|
+
y: constrained.y
|
|
5885
|
+
},
|
|
5886
|
+
geometry
|
|
5887
|
+
);
|
|
5888
|
+
return {
|
|
5889
|
+
feature,
|
|
5890
|
+
normalizedX: constrained.x,
|
|
5891
|
+
normalizedY: constrained.y,
|
|
5892
|
+
centerX: center.x,
|
|
5893
|
+
centerY: center.y
|
|
5894
|
+
};
|
|
5895
|
+
});
|
|
5896
|
+
}
|
|
5897
|
+
function projectPlacedFeatures(placements, geometry, scale) {
|
|
5898
|
+
return placements.map((placement) => {
|
|
5899
|
+
const normalized = normalizePointInGeometry(
|
|
5900
|
+
{ x: placement.centerX, y: placement.centerY },
|
|
5901
|
+
geometry
|
|
5902
|
+
);
|
|
5903
|
+
return scaleFeatureForRender(
|
|
5904
|
+
placement.feature,
|
|
5905
|
+
scale,
|
|
5906
|
+
normalized.x,
|
|
5907
|
+
normalized.y
|
|
5908
|
+
);
|
|
5909
|
+
});
|
|
5910
|
+
}
|
|
5911
|
+
|
|
5659
5912
|
// src/extensions/dieline/renderBuilder.ts
|
|
5660
5913
|
var DEFAULT_IDS = {
|
|
5661
5914
|
inside: "dieline.inside",
|
|
@@ -5665,16 +5918,6 @@ var DEFAULT_IDS = {
|
|
|
5665
5918
|
clip: "dieline.clip.image",
|
|
5666
5919
|
clipSource: "dieline.effect.clip-path"
|
|
5667
5920
|
};
|
|
5668
|
-
function scaleFeatures(state, scale) {
|
|
5669
|
-
return (state.features || []).map((feature) => ({
|
|
5670
|
-
...feature,
|
|
5671
|
-
x: feature.x,
|
|
5672
|
-
y: feature.y,
|
|
5673
|
-
width: (feature.width || 0) * scale,
|
|
5674
|
-
height: (feature.height || 0) * scale,
|
|
5675
|
-
radius: (feature.radius || 0) * scale
|
|
5676
|
-
}));
|
|
5677
|
-
}
|
|
5678
5921
|
function buildDielineRenderBundle(options) {
|
|
5679
5922
|
const ids = { ...DEFAULT_IDS, ...options.ids || {} };
|
|
5680
5923
|
const {
|
|
@@ -5699,8 +5942,41 @@ function buildDielineRenderBundle(options) {
|
|
|
5699
5942
|
const cutH = sceneLayout.cutRect.height;
|
|
5700
5943
|
const visualOffset = (cutW - visualWidth) / 2;
|
|
5701
5944
|
const cutR = visualRadius === 0 ? 0 : Math.max(0, visualRadius + visualOffset);
|
|
5702
|
-
const
|
|
5703
|
-
|
|
5945
|
+
const placements = resolveFeaturePlacements(state.features || [], {
|
|
5946
|
+
shape,
|
|
5947
|
+
shapeStyle,
|
|
5948
|
+
pathData: state.pathData,
|
|
5949
|
+
customSourceWidthPx: state.customSourceWidthPx,
|
|
5950
|
+
customSourceHeightPx: state.customSourceHeightPx,
|
|
5951
|
+
canvasWidth,
|
|
5952
|
+
canvasHeight,
|
|
5953
|
+
x: cx,
|
|
5954
|
+
y: cy,
|
|
5955
|
+
width: visualWidth,
|
|
5956
|
+
height: visualHeight,
|
|
5957
|
+
radius: visualRadius,
|
|
5958
|
+
scale
|
|
5959
|
+
});
|
|
5960
|
+
const absoluteFeatures = projectPlacedFeatures(
|
|
5961
|
+
placements,
|
|
5962
|
+
{
|
|
5963
|
+
x: cx,
|
|
5964
|
+
y: cy,
|
|
5965
|
+
width: visualWidth,
|
|
5966
|
+
height: visualHeight
|
|
5967
|
+
},
|
|
5968
|
+
scale
|
|
5969
|
+
);
|
|
5970
|
+
const cutFeatures = projectPlacedFeatures(
|
|
5971
|
+
placements.filter((placement) => !placement.feature.skipCut),
|
|
5972
|
+
{
|
|
5973
|
+
x: cx,
|
|
5974
|
+
y: cy,
|
|
5975
|
+
width: cutW,
|
|
5976
|
+
height: cutH
|
|
5977
|
+
},
|
|
5978
|
+
scale
|
|
5979
|
+
);
|
|
5704
5980
|
const common = {
|
|
5705
5981
|
shape,
|
|
5706
5982
|
shapeStyle,
|
|
@@ -6129,15 +6405,31 @@ var DielineTool = class {
|
|
|
6129
6405
|
const visualRadius = radius * scale;
|
|
6130
6406
|
const visualOffset = (cutW - sceneLayout.trimRect.width) / 2;
|
|
6131
6407
|
const cutR = visualRadius === 0 ? 0 : Math.max(0, visualRadius + visualOffset);
|
|
6132
|
-
const
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6408
|
+
const placements = resolveFeaturePlacements(features || [], {
|
|
6409
|
+
shape,
|
|
6410
|
+
shapeStyle,
|
|
6411
|
+
pathData,
|
|
6412
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
6413
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
6414
|
+
canvasWidth: canvasW,
|
|
6415
|
+
canvasHeight: canvasH,
|
|
6416
|
+
x: cx,
|
|
6417
|
+
y: cy,
|
|
6418
|
+
width: sceneLayout.trimRect.width,
|
|
6419
|
+
height: sceneLayout.trimRect.height,
|
|
6420
|
+
radius: visualRadius,
|
|
6421
|
+
scale
|
|
6422
|
+
});
|
|
6423
|
+
const cutFeatures = projectPlacedFeatures(
|
|
6424
|
+
placements.filter((placement) => !placement.feature.skipCut),
|
|
6425
|
+
{
|
|
6426
|
+
x: cx,
|
|
6427
|
+
y: cy,
|
|
6428
|
+
width: cutW,
|
|
6429
|
+
height: cutH
|
|
6430
|
+
},
|
|
6431
|
+
scale
|
|
6432
|
+
);
|
|
6141
6433
|
const generatedPathData = generateDielinePath({
|
|
6142
6434
|
shape,
|
|
6143
6435
|
width: cutW,
|
|
@@ -6261,178 +6553,6 @@ var DielineTool = class {
|
|
|
6261
6553
|
var import_core5 = require("@pooder/core");
|
|
6262
6554
|
var import_fabric4 = require("fabric");
|
|
6263
6555
|
|
|
6264
|
-
// src/extensions/constraints.ts
|
|
6265
|
-
var ConstraintRegistry = class {
|
|
6266
|
-
static register(type, handler) {
|
|
6267
|
-
this.handlers.set(type, handler);
|
|
6268
|
-
}
|
|
6269
|
-
static apply(x, y, feature, context, constraints) {
|
|
6270
|
-
const list = constraints || feature.constraints;
|
|
6271
|
-
if (!list || list.length === 0) {
|
|
6272
|
-
return { x, y };
|
|
6273
|
-
}
|
|
6274
|
-
let currentX = x;
|
|
6275
|
-
let currentY = y;
|
|
6276
|
-
for (const constraint of list) {
|
|
6277
|
-
const handler = this.handlers.get(constraint.type);
|
|
6278
|
-
if (handler) {
|
|
6279
|
-
const result = handler(currentX, currentY, feature, context, constraint.params || {});
|
|
6280
|
-
currentX = result.x;
|
|
6281
|
-
currentY = result.y;
|
|
6282
|
-
}
|
|
6283
|
-
}
|
|
6284
|
-
return { x: currentX, y: currentY };
|
|
6285
|
-
}
|
|
6286
|
-
};
|
|
6287
|
-
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
6288
|
-
var pathConstraint = (x, y, feature, context, params) => {
|
|
6289
|
-
const { dielineWidth, dielineHeight, geometry } = context;
|
|
6290
|
-
if (!geometry) return { x, y };
|
|
6291
|
-
const minX = geometry.x - geometry.width / 2;
|
|
6292
|
-
const minY = geometry.y - geometry.height / 2;
|
|
6293
|
-
const absX = minX + x * geometry.width;
|
|
6294
|
-
const absY = minY + y * geometry.height;
|
|
6295
|
-
const nearest = getNearestPointOnDieline(
|
|
6296
|
-
{ x: absX, y: absY },
|
|
6297
|
-
geometry
|
|
6298
|
-
);
|
|
6299
|
-
let finalX = nearest.x;
|
|
6300
|
-
let finalY = nearest.y;
|
|
6301
|
-
const hasOffsetParams = params.minOffset !== void 0 || params.maxOffset !== void 0;
|
|
6302
|
-
if (hasOffsetParams && nearest.normal) {
|
|
6303
|
-
const dx = absX - nearest.x;
|
|
6304
|
-
const dy = absY - nearest.y;
|
|
6305
|
-
const nx2 = nearest.normal.x;
|
|
6306
|
-
const ny2 = nearest.normal.y;
|
|
6307
|
-
const dist = dx * nx2 + dy * ny2;
|
|
6308
|
-
const scale = dielineWidth > 0 ? geometry.width / dielineWidth : 1;
|
|
6309
|
-
const rawMin = params.minOffset !== void 0 ? params.minOffset : 0;
|
|
6310
|
-
const rawMax = params.maxOffset !== void 0 ? params.maxOffset : 0;
|
|
6311
|
-
const minOffset = rawMin * scale;
|
|
6312
|
-
const maxOffset = rawMax * scale;
|
|
6313
|
-
const clampedDist = Math.max(minOffset, Math.min(dist, maxOffset));
|
|
6314
|
-
finalX = nearest.x + nx2 * clampedDist;
|
|
6315
|
-
finalY = nearest.y + ny2 * clampedDist;
|
|
6316
|
-
}
|
|
6317
|
-
const nx = geometry.width > 0 ? (finalX - minX) / geometry.width : 0.5;
|
|
6318
|
-
const ny = geometry.height > 0 ? (finalY - minY) / geometry.height : 0.5;
|
|
6319
|
-
return { x: nx, y: ny };
|
|
6320
|
-
};
|
|
6321
|
-
var edgeConstraint = (x, y, feature, context, params) => {
|
|
6322
|
-
const { dielineWidth, dielineHeight } = context;
|
|
6323
|
-
const allowedEdges = params.allowedEdges || [
|
|
6324
|
-
"top",
|
|
6325
|
-
"bottom",
|
|
6326
|
-
"left",
|
|
6327
|
-
"right"
|
|
6328
|
-
];
|
|
6329
|
-
const confine = params.confine || false;
|
|
6330
|
-
const offset = params.offset || 0;
|
|
6331
|
-
const distances = [];
|
|
6332
|
-
if (allowedEdges.includes("top"))
|
|
6333
|
-
distances.push({ edge: "top", dist: y * dielineHeight });
|
|
6334
|
-
if (allowedEdges.includes("bottom"))
|
|
6335
|
-
distances.push({ edge: "bottom", dist: (1 - y) * dielineHeight });
|
|
6336
|
-
if (allowedEdges.includes("left"))
|
|
6337
|
-
distances.push({ edge: "left", dist: x * dielineWidth });
|
|
6338
|
-
if (allowedEdges.includes("right"))
|
|
6339
|
-
distances.push({ edge: "right", dist: (1 - x) * dielineWidth });
|
|
6340
|
-
if (distances.length === 0) return { x, y };
|
|
6341
|
-
distances.sort((a, b) => a.dist - b.dist);
|
|
6342
|
-
const nearest = distances[0].edge;
|
|
6343
|
-
let newX = x;
|
|
6344
|
-
let newY = y;
|
|
6345
|
-
const fw = feature.width || 0;
|
|
6346
|
-
const fh = feature.height || 0;
|
|
6347
|
-
switch (nearest) {
|
|
6348
|
-
case "top":
|
|
6349
|
-
newY = 0 + offset / dielineHeight;
|
|
6350
|
-
if (confine) {
|
|
6351
|
-
const minX = fw / 2 / dielineWidth;
|
|
6352
|
-
const maxX = 1 - minX;
|
|
6353
|
-
newX = Math.max(minX, Math.min(newX, maxX));
|
|
6354
|
-
}
|
|
6355
|
-
break;
|
|
6356
|
-
case "bottom":
|
|
6357
|
-
newY = 1 - offset / dielineHeight;
|
|
6358
|
-
if (confine) {
|
|
6359
|
-
const minX = fw / 2 / dielineWidth;
|
|
6360
|
-
const maxX = 1 - minX;
|
|
6361
|
-
newX = Math.max(minX, Math.min(newX, maxX));
|
|
6362
|
-
}
|
|
6363
|
-
break;
|
|
6364
|
-
case "left":
|
|
6365
|
-
newX = 0 + offset / dielineWidth;
|
|
6366
|
-
if (confine) {
|
|
6367
|
-
const minY = fh / 2 / dielineHeight;
|
|
6368
|
-
const maxY = 1 - minY;
|
|
6369
|
-
newY = Math.max(minY, Math.min(newY, maxY));
|
|
6370
|
-
}
|
|
6371
|
-
break;
|
|
6372
|
-
case "right":
|
|
6373
|
-
newX = 1 - offset / dielineWidth;
|
|
6374
|
-
if (confine) {
|
|
6375
|
-
const minY = fh / 2 / dielineHeight;
|
|
6376
|
-
const maxY = 1 - minY;
|
|
6377
|
-
newY = Math.max(minY, Math.min(newY, maxY));
|
|
6378
|
-
}
|
|
6379
|
-
break;
|
|
6380
|
-
}
|
|
6381
|
-
return { x: newX, y: newY };
|
|
6382
|
-
};
|
|
6383
|
-
var internalConstraint = (x, y, feature, context, params) => {
|
|
6384
|
-
const { dielineWidth, dielineHeight } = context;
|
|
6385
|
-
const margin = params.margin || 0;
|
|
6386
|
-
const fw = feature.width || 0;
|
|
6387
|
-
const fh = feature.height || 0;
|
|
6388
|
-
const minX = (margin + fw / 2) / dielineWidth;
|
|
6389
|
-
const maxX = 1 - (margin + fw / 2) / dielineWidth;
|
|
6390
|
-
const minY = (margin + fh / 2) / dielineHeight;
|
|
6391
|
-
const maxY = 1 - (margin + fh / 2) / dielineHeight;
|
|
6392
|
-
const clampedX = minX > maxX ? 0.5 : Math.max(minX, Math.min(x, maxX));
|
|
6393
|
-
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
6394
|
-
return { x: clampedX, y: clampedY };
|
|
6395
|
-
};
|
|
6396
|
-
var tangentBottomConstraint = (x, y, feature, context, params) => {
|
|
6397
|
-
const { dielineWidth, dielineHeight } = context;
|
|
6398
|
-
const gap = params.gap || 0;
|
|
6399
|
-
const confineX = params.confineX !== false;
|
|
6400
|
-
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
6401
|
-
const newY = 1 + (extentY + gap) / dielineHeight;
|
|
6402
|
-
let newX = x;
|
|
6403
|
-
if (confineX) {
|
|
6404
|
-
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
6405
|
-
const minX = extentX / dielineWidth;
|
|
6406
|
-
const maxX = 1 - extentX / dielineWidth;
|
|
6407
|
-
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
6408
|
-
}
|
|
6409
|
-
return { x: newX, y: newY };
|
|
6410
|
-
};
|
|
6411
|
-
var lowestTangentConstraint = (x, y, feature, context, params) => {
|
|
6412
|
-
const { dielineWidth, dielineHeight, geometry } = context;
|
|
6413
|
-
if (!geometry) return { x, y };
|
|
6414
|
-
const lowest = getLowestPointOnDieline(geometry);
|
|
6415
|
-
const minY = geometry.y - geometry.height / 2;
|
|
6416
|
-
const normY = (lowest.y - minY) / geometry.height;
|
|
6417
|
-
const gap = params.gap || 0;
|
|
6418
|
-
const confineX = params.confineX !== false;
|
|
6419
|
-
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
6420
|
-
const newY = normY + (extentY + gap) / dielineHeight;
|
|
6421
|
-
let newX = x;
|
|
6422
|
-
if (confineX) {
|
|
6423
|
-
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
6424
|
-
const minX = extentX / dielineWidth;
|
|
6425
|
-
const maxX = 1 - extentX / dielineWidth;
|
|
6426
|
-
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
6427
|
-
}
|
|
6428
|
-
return { x: newX, y: newY };
|
|
6429
|
-
};
|
|
6430
|
-
ConstraintRegistry.register("path", pathConstraint);
|
|
6431
|
-
ConstraintRegistry.register("edge", edgeConstraint);
|
|
6432
|
-
ConstraintRegistry.register("internal", internalConstraint);
|
|
6433
|
-
ConstraintRegistry.register("tangent-bottom", tangentBottomConstraint);
|
|
6434
|
-
ConstraintRegistry.register("lowest-tangent", lowestTangentConstraint);
|
|
6435
|
-
|
|
6436
6556
|
// src/extensions/featureComplete.ts
|
|
6437
6557
|
function validateFeaturesStrict(features, context) {
|
|
6438
6558
|
const eps = 1e-6;
|
|
@@ -7208,9 +7328,29 @@ var FeatureTool = class {
|
|
|
7208
7328
|
}
|
|
7209
7329
|
const groups = /* @__PURE__ */ new Map();
|
|
7210
7330
|
const singles = [];
|
|
7211
|
-
|
|
7331
|
+
const placements = resolveFeaturePlacements(
|
|
7332
|
+
this.workingFeatures,
|
|
7333
|
+
{
|
|
7334
|
+
shape: this.currentGeometry.shape,
|
|
7335
|
+
shapeStyle: this.currentGeometry.shapeStyle,
|
|
7336
|
+
pathData: this.currentGeometry.pathData,
|
|
7337
|
+
customSourceWidthPx: this.currentGeometry.customSourceWidthPx,
|
|
7338
|
+
customSourceHeightPx: this.currentGeometry.customSourceHeightPx,
|
|
7339
|
+
x: this.currentGeometry.x,
|
|
7340
|
+
y: this.currentGeometry.y,
|
|
7341
|
+
width: this.currentGeometry.width,
|
|
7342
|
+
height: this.currentGeometry.height,
|
|
7343
|
+
radius: this.currentGeometry.radius,
|
|
7344
|
+
scale: this.currentGeometry.scale || 1
|
|
7345
|
+
}
|
|
7346
|
+
);
|
|
7347
|
+
placements.forEach((placement, index) => {
|
|
7348
|
+
const feature = placement.feature;
|
|
7212
7349
|
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
7213
|
-
const position =
|
|
7350
|
+
const position = {
|
|
7351
|
+
x: placement.centerX,
|
|
7352
|
+
y: placement.centerY
|
|
7353
|
+
};
|
|
7214
7354
|
const scale = geometry.scale || 1;
|
|
7215
7355
|
const marker = {
|
|
7216
7356
|
feature,
|
|
@@ -7781,11 +7921,12 @@ var EXTENSION_LINE_LENGTH = 5;
|
|
|
7781
7921
|
var MIN_ARROW_SIZE = 4;
|
|
7782
7922
|
var THICKNESS_TO_STROKE_WIDTH_RATIO = 20;
|
|
7783
7923
|
var DEFAULT_THICKNESS = 20;
|
|
7784
|
-
var DEFAULT_GAP =
|
|
7924
|
+
var DEFAULT_GAP = 65;
|
|
7785
7925
|
var DEFAULT_FONT_SIZE = 10;
|
|
7786
7926
|
var DEFAULT_BACKGROUND_COLOR = "#f0f0f0";
|
|
7787
7927
|
var DEFAULT_TEXT_COLOR = "#333333";
|
|
7788
7928
|
var DEFAULT_LINE_COLOR = "#999999";
|
|
7929
|
+
var RULER_DEBUG_KEY = "ruler.debug";
|
|
7789
7930
|
var RULER_THICKNESS_MIN = 10;
|
|
7790
7931
|
var RULER_THICKNESS_MAX = 100;
|
|
7791
7932
|
var RULER_GAP_MIN = 0;
|
|
@@ -7804,6 +7945,7 @@ var RulerTool = class {
|
|
|
7804
7945
|
this.textColor = DEFAULT_TEXT_COLOR;
|
|
7805
7946
|
this.lineColor = DEFAULT_LINE_COLOR;
|
|
7806
7947
|
this.fontSize = DEFAULT_FONT_SIZE;
|
|
7948
|
+
this.debugEnabled = false;
|
|
7807
7949
|
this.renderSeq = 0;
|
|
7808
7950
|
this.numericProps = /* @__PURE__ */ new Set(["thickness", "gap", "fontSize"]);
|
|
7809
7951
|
this.specs = [];
|
|
@@ -7852,7 +7994,14 @@ var RulerTool = class {
|
|
|
7852
7994
|
this.syncConfig(configService);
|
|
7853
7995
|
configService.onAnyChange((e) => {
|
|
7854
7996
|
let shouldUpdate = false;
|
|
7855
|
-
if (e.key
|
|
7997
|
+
if (e.key === RULER_DEBUG_KEY) {
|
|
7998
|
+
this.debugEnabled = e.value === true;
|
|
7999
|
+
this.log("config:update", {
|
|
8000
|
+
key: e.key,
|
|
8001
|
+
raw: e.value,
|
|
8002
|
+
normalized: this.debugEnabled
|
|
8003
|
+
});
|
|
8004
|
+
} else if (e.key.startsWith("ruler.")) {
|
|
7856
8005
|
const prop = e.key.split(".")[1];
|
|
7857
8006
|
if (prop && prop in this) {
|
|
7858
8007
|
if (this.numericProps.has(prop)) {
|
|
@@ -7939,6 +8088,12 @@ var RulerTool = class {
|
|
|
7939
8088
|
min: RULER_FONT_SIZE_MIN,
|
|
7940
8089
|
max: RULER_FONT_SIZE_MAX,
|
|
7941
8090
|
default: DEFAULT_FONT_SIZE
|
|
8091
|
+
},
|
|
8092
|
+
{
|
|
8093
|
+
id: RULER_DEBUG_KEY,
|
|
8094
|
+
type: "boolean",
|
|
8095
|
+
label: "Ruler Debug Log",
|
|
8096
|
+
default: false
|
|
7942
8097
|
}
|
|
7943
8098
|
],
|
|
7944
8099
|
[import_core8.ContributionPointIds.COMMANDS]: [
|
|
@@ -7975,7 +8130,11 @@ var RulerTool = class {
|
|
|
7975
8130
|
]
|
|
7976
8131
|
};
|
|
7977
8132
|
}
|
|
8133
|
+
isDebugEnabled() {
|
|
8134
|
+
return this.debugEnabled;
|
|
8135
|
+
}
|
|
7978
8136
|
log(step, payload) {
|
|
8137
|
+
if (!this.isDebugEnabled()) return;
|
|
7979
8138
|
if (payload) {
|
|
7980
8139
|
console.debug(`[RulerTool] ${step}`, payload);
|
|
7981
8140
|
return;
|
|
@@ -8004,6 +8163,7 @@ var RulerTool = class {
|
|
|
8004
8163
|
configService.get("ruler.fontSize", this.fontSize),
|
|
8005
8164
|
DEFAULT_FONT_SIZE
|
|
8006
8165
|
);
|
|
8166
|
+
this.debugEnabled = configService.get(RULER_DEBUG_KEY, this.debugEnabled) === true;
|
|
8007
8167
|
this.log("config:loaded", {
|
|
8008
8168
|
thickness: this.thickness,
|
|
8009
8169
|
gap: this.gap,
|