@crazyhappyone/auto-graph 0.1.3 → 0.1.4
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/dist/cli/index.cjs +143 -13
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +143 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +143 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +143 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -96,6 +96,9 @@ function applyLayoutConstraints(input) {
|
|
|
96
96
|
const nodeById = new Map(input.nodes.map((node) => [node.id, node]));
|
|
97
97
|
applyFixedPositionLocks(input.nodes, boxes, locks, diagnostics);
|
|
98
98
|
applyExactPositions(input.constraints, boxes, locks, diagnostics, nodeById);
|
|
99
|
+
if (input.distributeContainedChildren) {
|
|
100
|
+
yieldFixedPositionLocks(input, boxes, locks);
|
|
101
|
+
}
|
|
99
102
|
applyContainment(input.constraints, boxes, locks, diagnostics, false);
|
|
100
103
|
applyRelative(input.constraints, boxes, locks, diagnostics);
|
|
101
104
|
applyAlign(input.constraints, boxes, locks, diagnostics);
|
|
@@ -109,6 +112,13 @@ function applyLayoutConstraints(input) {
|
|
|
109
112
|
);
|
|
110
113
|
applyContainment(input.constraints, boxes, locks, diagnostics, true);
|
|
111
114
|
applyDistributeContained(input, boxes, locks, diagnostics);
|
|
115
|
+
if (input.distributeContainedChildren) {
|
|
116
|
+
const diagBefore = diagnostics.length;
|
|
117
|
+
applyContainment(input.constraints, boxes, locks, diagnostics, true);
|
|
118
|
+
applyDistributeContained(input, boxes, locks, diagnostics);
|
|
119
|
+
dedupReplayDiagnostics(diagnostics, diagBefore);
|
|
120
|
+
}
|
|
121
|
+
removeResolvedConstraintDiagnostics(input.constraints, boxes, diagnostics);
|
|
112
122
|
reportOverlaps(boxes, diagnostics, containmentOverlapKeys(input.constraints));
|
|
113
123
|
reportIntraContainerOverflow(input, boxes, diagnostics);
|
|
114
124
|
return { boxes, locks, diagnostics };
|
|
@@ -154,6 +164,62 @@ function applyFixedPositionLocks(nodes, boxes, locks, diagnostics) {
|
|
|
154
164
|
locks.set(node.id, { nodeId: node.id, source: "fixed-position" });
|
|
155
165
|
}
|
|
156
166
|
}
|
|
167
|
+
function dedupReplayDiagnostics(diagnostics, keepUpTo) {
|
|
168
|
+
const seen = /* @__PURE__ */ new Set();
|
|
169
|
+
for (let i = 0; i < keepUpTo && i < diagnostics.length; i += 1) {
|
|
170
|
+
const d = diagnostics[i];
|
|
171
|
+
if (d === void 0) continue;
|
|
172
|
+
seen.add(diagnosticFingerprint(d));
|
|
173
|
+
}
|
|
174
|
+
for (let i = diagnostics.length - 1; i >= keepUpTo; i -= 1) {
|
|
175
|
+
const d = diagnostics[i];
|
|
176
|
+
if (d === void 0) continue;
|
|
177
|
+
const fp = diagnosticFingerprint(d);
|
|
178
|
+
if (seen.has(fp)) {
|
|
179
|
+
diagnostics.splice(i, 1);
|
|
180
|
+
} else {
|
|
181
|
+
seen.add(fp);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function diagnosticFingerprint(d) {
|
|
186
|
+
const nodeId = typeof d.detail?.nodeId === "string" ? d.detail.nodeId : "";
|
|
187
|
+
const containerId = typeof d.detail?.containerId === "string" ? d.detail.containerId : "";
|
|
188
|
+
return `${d.code}|${nodeId}|${containerId}`;
|
|
189
|
+
}
|
|
190
|
+
function yieldFixedPositionLocks(input, boxes, locks) {
|
|
191
|
+
for (const c of input.constraints) {
|
|
192
|
+
if (c.kind !== "containment") continue;
|
|
193
|
+
const container = boxes.get(c.containerId);
|
|
194
|
+
if (container === void 0) continue;
|
|
195
|
+
const content = contentBox(container, c.padding);
|
|
196
|
+
const mainAxis = input.direction === "LR" || input.direction === "RL" ? "width" : "height";
|
|
197
|
+
const crossAxis = mainAxis === "width" ? "height" : "width";
|
|
198
|
+
let eligible = 0;
|
|
199
|
+
for (const childId of c.childIds) {
|
|
200
|
+
const box = boxes.get(childId);
|
|
201
|
+
if (box === void 0) continue;
|
|
202
|
+
const lock = locks.get(childId);
|
|
203
|
+
if (lock?.source === "exact-position") continue;
|
|
204
|
+
const fits = box[mainAxis] <= content[mainAxis] && box[crossAxis] <= content[crossAxis];
|
|
205
|
+
if (fits) {
|
|
206
|
+
eligible += 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (eligible < 2) continue;
|
|
210
|
+
for (const childId of c.childIds) {
|
|
211
|
+
const lock = locks.get(childId);
|
|
212
|
+
if (lock?.source === "fixed-position") {
|
|
213
|
+
const box = boxes.get(childId);
|
|
214
|
+
if (box === void 0) continue;
|
|
215
|
+
const fits = box[mainAxis] <= content[mainAxis] && box[crossAxis] <= content[crossAxis];
|
|
216
|
+
if (fits) {
|
|
217
|
+
locks.delete(childId);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
157
223
|
function applyExactPositions(constraints, boxes, locks, diagnostics, nodeById) {
|
|
158
224
|
for (const constraint of constraints) {
|
|
159
225
|
if (constraint.kind !== "exact-position") {
|
|
@@ -226,7 +292,7 @@ function applyContainment(constraints, boxes, locks, diagnostics, reportOverflow
|
|
|
226
292
|
code: "constraints.locked-target-not-moved",
|
|
227
293
|
message: `Locked child ${childId} was not moved into containment.`,
|
|
228
294
|
path: ["constraints", constraint.id ?? constraint.containerId],
|
|
229
|
-
detail: { nodeId: childId }
|
|
295
|
+
detail: { nodeId: childId, containerId: constraint.containerId }
|
|
230
296
|
});
|
|
231
297
|
if (!isInside(child, content)) {
|
|
232
298
|
diagnostics.push({
|
|
@@ -378,6 +444,60 @@ function repairOverlaps(input, boxes, locks, diagnostics, siblingPairs) {
|
|
|
378
444
|
}
|
|
379
445
|
reportOverlaps(boxes, diagnostics, ignoredPairs);
|
|
380
446
|
}
|
|
447
|
+
function removeResolvedConstraintDiagnostics(constraints, boxes, diagnostics) {
|
|
448
|
+
for (let i = diagnostics.length - 1; i >= 0; i -= 1) {
|
|
449
|
+
const d = diagnostics[i];
|
|
450
|
+
if (d === void 0) continue;
|
|
451
|
+
if (d.code === "constraints.overlap.unresolved") {
|
|
452
|
+
const aId = d.detail?.firstId;
|
|
453
|
+
const bId = d.detail?.secondId;
|
|
454
|
+
if (typeof aId !== "string" || typeof bId !== "string") continue;
|
|
455
|
+
const a = boxes.get(aId);
|
|
456
|
+
const b = boxes.get(bId);
|
|
457
|
+
if (a !== void 0 && b !== void 0 && !intersectsAabb(a, b)) {
|
|
458
|
+
diagnostics.splice(i, 1);
|
|
459
|
+
}
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
if (d.code === "constraints.containment.impossible" || d.code === "constraints.locked-target-not-moved" && typeof d.message === "string" && d.message.includes("not moved into containment")) {
|
|
463
|
+
const nodeId = d.detail?.nodeId;
|
|
464
|
+
if (typeof nodeId !== "string") continue;
|
|
465
|
+
const child = boxes.get(nodeId);
|
|
466
|
+
if (child === void 0) continue;
|
|
467
|
+
const diagContainerId = typeof d.detail?.containerId === "string" ? d.detail.containerId : void 0;
|
|
468
|
+
let resolved = false;
|
|
469
|
+
for (const c of constraints) {
|
|
470
|
+
if (c.kind !== "containment") continue;
|
|
471
|
+
if (!c.childIds.includes(nodeId)) continue;
|
|
472
|
+
if (diagContainerId !== void 0 && c.containerId !== diagContainerId) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
const container = boxes.get(c.containerId);
|
|
476
|
+
if (container === void 0) continue;
|
|
477
|
+
const content = contentBox(container, c.padding);
|
|
478
|
+
if (isInside(child, content)) {
|
|
479
|
+
diagnostics.splice(i, 1);
|
|
480
|
+
resolved = true;
|
|
481
|
+
}
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
if (!resolved && diagContainerId !== void 0) {
|
|
485
|
+
for (const c of constraints) {
|
|
486
|
+
if (c.kind !== "containment") continue;
|
|
487
|
+
if (c.containerId !== diagContainerId) continue;
|
|
488
|
+
if (!c.childIds.includes(nodeId)) continue;
|
|
489
|
+
const container = boxes.get(c.containerId);
|
|
490
|
+
if (container === void 0) continue;
|
|
491
|
+
const content = contentBox(container, c.padding);
|
|
492
|
+
if (isInside(child, content)) {
|
|
493
|
+
diagnostics.splice(i, 1);
|
|
494
|
+
}
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
381
501
|
function reportOverlaps(boxes, diagnostics, ignoredPairs = /* @__PURE__ */ new Set()) {
|
|
382
502
|
const ids = [...boxes.keys()].sort();
|
|
383
503
|
const reported = new Set(
|
|
@@ -685,6 +805,12 @@ function applyDistributeContained(input, boxes, locks, diagnostics) {
|
|
|
685
805
|
continue;
|
|
686
806
|
}
|
|
687
807
|
if (locks.has(childId)) {
|
|
808
|
+
const lock = locks.get(childId);
|
|
809
|
+
if (lock?.source === "fixed-position") {
|
|
810
|
+
unlocked.push({ id: childId, box });
|
|
811
|
+
locks.delete(childId);
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
688
814
|
diagnostics.push({
|
|
689
815
|
severity: "warning",
|
|
690
816
|
code: "constraints.locked-target-not-moved",
|
|
@@ -743,6 +869,7 @@ function applyDistributeContained(input, boxes, locks, diagnostics) {
|
|
|
743
869
|
});
|
|
744
870
|
}
|
|
745
871
|
boxes.set(child.id, clamped);
|
|
872
|
+
locks.delete(child.id);
|
|
746
873
|
pos = clamped[axis] + clamped[mainSize] + minGap;
|
|
747
874
|
}
|
|
748
875
|
diagnostics.push({
|
|
@@ -3988,7 +4115,7 @@ function routeEdge(input) {
|
|
|
3988
4115
|
const rerouted = greedyRerouteAroundObstacles(
|
|
3989
4116
|
bestPoints2,
|
|
3990
4117
|
allObstacles,
|
|
3991
|
-
|
|
4118
|
+
maxAttempts
|
|
3992
4119
|
);
|
|
3993
4120
|
const reroutedAvoidsEndpointInteriors = !routeIntersectsEndpointInteriors(
|
|
3994
4121
|
rerouted,
|
|
@@ -4750,9 +4877,7 @@ function solveDiagram(diagram, options = {}) {
|
|
|
4750
4877
|
options?.overlapSpacing ?? 40,
|
|
4751
4878
|
Math.max(0, options?.minLaneGutter ?? 0)
|
|
4752
4879
|
);
|
|
4753
|
-
|
|
4754
|
-
removeResolvedOverlapDiagnostics(diagnostics, constrained.boxes);
|
|
4755
|
-
}
|
|
4880
|
+
removeResolvedOverlapDiagnostics(diagnostics, constrained.boxes);
|
|
4756
4881
|
diagnostics.push(...swimlaneContracts.diagnostics);
|
|
4757
4882
|
const coordinatedNodes = coordinateNodes(
|
|
4758
4883
|
styledNodes,
|
|
@@ -6698,7 +6823,8 @@ function coordinateEdges(edges, nodes, coordinatedNodes, obstacles, softObstacle
|
|
|
6698
6823
|
...softObstacles,
|
|
6699
6824
|
...routeTextObstacles
|
|
6700
6825
|
],
|
|
6701
|
-
hardObstacles
|
|
6826
|
+
hardObstacles,
|
|
6827
|
+
...options.maxRoutingAttempts === void 0 ? {} : { maxRoutingAttempts: options.maxRoutingAttempts }
|
|
6702
6828
|
});
|
|
6703
6829
|
diagnostics.push(
|
|
6704
6830
|
...route.diagnostics.map((diagnostic) => ({
|
|
@@ -7181,7 +7307,8 @@ function edgeLabelAnchor(edge, layout2, edges, obstacleBoxes, placedLabelBoxes,
|
|
|
7181
7307
|
for (const candidate of edgeLabelAnchorCandidates(
|
|
7182
7308
|
edge.points,
|
|
7183
7309
|
placement,
|
|
7184
|
-
layout2
|
|
7310
|
+
layout2,
|
|
7311
|
+
baseOffset
|
|
7185
7312
|
)) {
|
|
7186
7313
|
const labelBox = {
|
|
7187
7314
|
x: candidate.x - layout2.box.width / 2,
|
|
@@ -7213,8 +7340,8 @@ function edgeLabelAnchor(edge, layout2, edges, obstacleBoxes, placedLabelBoxes,
|
|
|
7213
7340
|
}
|
|
7214
7341
|
return placement;
|
|
7215
7342
|
}
|
|
7216
|
-
function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
7217
|
-
const segment = labelSegmentOnPolyline(points);
|
|
7343
|
+
function edgeLabelAnchorCandidates(points, placement, layout2, baseOffset = 10) {
|
|
7344
|
+
const segment = labelSegmentOnPolyline(points, baseOffset);
|
|
7218
7345
|
if (segment === void 0) {
|
|
7219
7346
|
return [placement];
|
|
7220
7347
|
}
|
|
@@ -7264,7 +7391,7 @@ function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
|
7264
7391
|
}, 0);
|
|
7265
7392
|
if (totalLen > 200) {
|
|
7266
7393
|
for (const ratio of [0.25, 0.75]) {
|
|
7267
|
-
const qp = labelPlacementAtRatio(points, ratio, totalLen);
|
|
7394
|
+
const qp = labelPlacementAtRatio(points, ratio, totalLen, baseOffset);
|
|
7268
7395
|
if (qp !== void 0) {
|
|
7269
7396
|
candidates.push(qp);
|
|
7270
7397
|
const qTargetDist = totalLen * ratio;
|
|
@@ -7350,7 +7477,7 @@ function labelSegmentOnPolyline(points, baseOffset = 10) {
|
|
|
7350
7477
|
if (last === void 0) {
|
|
7351
7478
|
return void 0;
|
|
7352
7479
|
}
|
|
7353
|
-
const offset = labelOffset2(last);
|
|
7480
|
+
const offset = labelOffset2(last, baseOffset);
|
|
7354
7481
|
return {
|
|
7355
7482
|
start: last.start,
|
|
7356
7483
|
end: last.end,
|
|
@@ -7372,7 +7499,7 @@ function nonZeroSegments2(points) {
|
|
|
7372
7499
|
}
|
|
7373
7500
|
return segments;
|
|
7374
7501
|
}
|
|
7375
|
-
function labelPlacementAtRatio(points, ratio, totalLength) {
|
|
7502
|
+
function labelPlacementAtRatio(points, ratio, totalLength, baseOffset = 10) {
|
|
7376
7503
|
if (points.length < 2 || ratio < 0 || ratio > 1) {
|
|
7377
7504
|
return void 0;
|
|
7378
7505
|
}
|
|
@@ -7390,7 +7517,10 @@ function labelPlacementAtRatio(points, ratio, totalLength) {
|
|
|
7390
7517
|
}
|
|
7391
7518
|
if (travelled + segLen >= targetDist) {
|
|
7392
7519
|
const t = (targetDist - travelled) / segLen;
|
|
7393
|
-
const offset = labelOffset2(
|
|
7520
|
+
const offset = labelOffset2(
|
|
7521
|
+
{ start: prev, end: curr, length: segLen },
|
|
7522
|
+
baseOffset
|
|
7523
|
+
);
|
|
7394
7524
|
return {
|
|
7395
7525
|
x: prev.x + (curr.x - prev.x) * t + offset.x,
|
|
7396
7526
|
y: prev.y + (curr.y - prev.y) * t + offset.y
|