@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.cjs
CHANGED
|
@@ -99,6 +99,9 @@ function applyLayoutConstraints(input) {
|
|
|
99
99
|
const nodeById = new Map(input.nodes.map((node) => [node.id, node]));
|
|
100
100
|
applyFixedPositionLocks(input.nodes, boxes, locks, diagnostics);
|
|
101
101
|
applyExactPositions(input.constraints, boxes, locks, diagnostics, nodeById);
|
|
102
|
+
if (input.distributeContainedChildren) {
|
|
103
|
+
yieldFixedPositionLocks(input, boxes, locks);
|
|
104
|
+
}
|
|
102
105
|
applyContainment(input.constraints, boxes, locks, diagnostics, false);
|
|
103
106
|
applyRelative(input.constraints, boxes, locks, diagnostics);
|
|
104
107
|
applyAlign(input.constraints, boxes, locks, diagnostics);
|
|
@@ -112,6 +115,13 @@ function applyLayoutConstraints(input) {
|
|
|
112
115
|
);
|
|
113
116
|
applyContainment(input.constraints, boxes, locks, diagnostics, true);
|
|
114
117
|
applyDistributeContained(input, boxes, locks, diagnostics);
|
|
118
|
+
if (input.distributeContainedChildren) {
|
|
119
|
+
const diagBefore = diagnostics.length;
|
|
120
|
+
applyContainment(input.constraints, boxes, locks, diagnostics, true);
|
|
121
|
+
applyDistributeContained(input, boxes, locks, diagnostics);
|
|
122
|
+
dedupReplayDiagnostics(diagnostics, diagBefore);
|
|
123
|
+
}
|
|
124
|
+
removeResolvedConstraintDiagnostics(input.constraints, boxes, diagnostics);
|
|
115
125
|
reportOverlaps(boxes, diagnostics, containmentOverlapKeys(input.constraints));
|
|
116
126
|
reportIntraContainerOverflow(input, boxes, diagnostics);
|
|
117
127
|
return { boxes, locks, diagnostics };
|
|
@@ -157,6 +167,62 @@ function applyFixedPositionLocks(nodes, boxes, locks, diagnostics) {
|
|
|
157
167
|
locks.set(node.id, { nodeId: node.id, source: "fixed-position" });
|
|
158
168
|
}
|
|
159
169
|
}
|
|
170
|
+
function dedupReplayDiagnostics(diagnostics, keepUpTo) {
|
|
171
|
+
const seen = /* @__PURE__ */ new Set();
|
|
172
|
+
for (let i = 0; i < keepUpTo && i < diagnostics.length; i += 1) {
|
|
173
|
+
const d = diagnostics[i];
|
|
174
|
+
if (d === void 0) continue;
|
|
175
|
+
seen.add(diagnosticFingerprint(d));
|
|
176
|
+
}
|
|
177
|
+
for (let i = diagnostics.length - 1; i >= keepUpTo; i -= 1) {
|
|
178
|
+
const d = diagnostics[i];
|
|
179
|
+
if (d === void 0) continue;
|
|
180
|
+
const fp = diagnosticFingerprint(d);
|
|
181
|
+
if (seen.has(fp)) {
|
|
182
|
+
diagnostics.splice(i, 1);
|
|
183
|
+
} else {
|
|
184
|
+
seen.add(fp);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function diagnosticFingerprint(d) {
|
|
189
|
+
const nodeId = typeof d.detail?.nodeId === "string" ? d.detail.nodeId : "";
|
|
190
|
+
const containerId = typeof d.detail?.containerId === "string" ? d.detail.containerId : "";
|
|
191
|
+
return `${d.code}|${nodeId}|${containerId}`;
|
|
192
|
+
}
|
|
193
|
+
function yieldFixedPositionLocks(input, boxes, locks) {
|
|
194
|
+
for (const c of input.constraints) {
|
|
195
|
+
if (c.kind !== "containment") continue;
|
|
196
|
+
const container = boxes.get(c.containerId);
|
|
197
|
+
if (container === void 0) continue;
|
|
198
|
+
const content = contentBox(container, c.padding);
|
|
199
|
+
const mainAxis = input.direction === "LR" || input.direction === "RL" ? "width" : "height";
|
|
200
|
+
const crossAxis = mainAxis === "width" ? "height" : "width";
|
|
201
|
+
let eligible = 0;
|
|
202
|
+
for (const childId of c.childIds) {
|
|
203
|
+
const box = boxes.get(childId);
|
|
204
|
+
if (box === void 0) continue;
|
|
205
|
+
const lock = locks.get(childId);
|
|
206
|
+
if (lock?.source === "exact-position") continue;
|
|
207
|
+
const fits = box[mainAxis] <= content[mainAxis] && box[crossAxis] <= content[crossAxis];
|
|
208
|
+
if (fits) {
|
|
209
|
+
eligible += 1;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (eligible < 2) continue;
|
|
213
|
+
for (const childId of c.childIds) {
|
|
214
|
+
const lock = locks.get(childId);
|
|
215
|
+
if (lock?.source === "fixed-position") {
|
|
216
|
+
const box = boxes.get(childId);
|
|
217
|
+
if (box === void 0) continue;
|
|
218
|
+
const fits = box[mainAxis] <= content[mainAxis] && box[crossAxis] <= content[crossAxis];
|
|
219
|
+
if (fits) {
|
|
220
|
+
locks.delete(childId);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
160
226
|
function applyExactPositions(constraints, boxes, locks, diagnostics, nodeById) {
|
|
161
227
|
for (const constraint of constraints) {
|
|
162
228
|
if (constraint.kind !== "exact-position") {
|
|
@@ -229,7 +295,7 @@ function applyContainment(constraints, boxes, locks, diagnostics, reportOverflow
|
|
|
229
295
|
code: "constraints.locked-target-not-moved",
|
|
230
296
|
message: `Locked child ${childId} was not moved into containment.`,
|
|
231
297
|
path: ["constraints", constraint.id ?? constraint.containerId],
|
|
232
|
-
detail: { nodeId: childId }
|
|
298
|
+
detail: { nodeId: childId, containerId: constraint.containerId }
|
|
233
299
|
});
|
|
234
300
|
if (!isInside(child, content)) {
|
|
235
301
|
diagnostics.push({
|
|
@@ -381,6 +447,60 @@ function repairOverlaps(input, boxes, locks, diagnostics, siblingPairs) {
|
|
|
381
447
|
}
|
|
382
448
|
reportOverlaps(boxes, diagnostics, ignoredPairs);
|
|
383
449
|
}
|
|
450
|
+
function removeResolvedConstraintDiagnostics(constraints, boxes, diagnostics) {
|
|
451
|
+
for (let i = diagnostics.length - 1; i >= 0; i -= 1) {
|
|
452
|
+
const d = diagnostics[i];
|
|
453
|
+
if (d === void 0) continue;
|
|
454
|
+
if (d.code === "constraints.overlap.unresolved") {
|
|
455
|
+
const aId = d.detail?.firstId;
|
|
456
|
+
const bId = d.detail?.secondId;
|
|
457
|
+
if (typeof aId !== "string" || typeof bId !== "string") continue;
|
|
458
|
+
const a = boxes.get(aId);
|
|
459
|
+
const b = boxes.get(bId);
|
|
460
|
+
if (a !== void 0 && b !== void 0 && !intersectsAabb(a, b)) {
|
|
461
|
+
diagnostics.splice(i, 1);
|
|
462
|
+
}
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
if (d.code === "constraints.containment.impossible" || d.code === "constraints.locked-target-not-moved" && typeof d.message === "string" && d.message.includes("not moved into containment")) {
|
|
466
|
+
const nodeId = d.detail?.nodeId;
|
|
467
|
+
if (typeof nodeId !== "string") continue;
|
|
468
|
+
const child = boxes.get(nodeId);
|
|
469
|
+
if (child === void 0) continue;
|
|
470
|
+
const diagContainerId = typeof d.detail?.containerId === "string" ? d.detail.containerId : void 0;
|
|
471
|
+
let resolved = false;
|
|
472
|
+
for (const c of constraints) {
|
|
473
|
+
if (c.kind !== "containment") continue;
|
|
474
|
+
if (!c.childIds.includes(nodeId)) continue;
|
|
475
|
+
if (diagContainerId !== void 0 && c.containerId !== diagContainerId) {
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
const container = boxes.get(c.containerId);
|
|
479
|
+
if (container === void 0) continue;
|
|
480
|
+
const content = contentBox(container, c.padding);
|
|
481
|
+
if (isInside(child, content)) {
|
|
482
|
+
diagnostics.splice(i, 1);
|
|
483
|
+
resolved = true;
|
|
484
|
+
}
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
if (!resolved && diagContainerId !== void 0) {
|
|
488
|
+
for (const c of constraints) {
|
|
489
|
+
if (c.kind !== "containment") continue;
|
|
490
|
+
if (c.containerId !== diagContainerId) continue;
|
|
491
|
+
if (!c.childIds.includes(nodeId)) continue;
|
|
492
|
+
const container = boxes.get(c.containerId);
|
|
493
|
+
if (container === void 0) continue;
|
|
494
|
+
const content = contentBox(container, c.padding);
|
|
495
|
+
if (isInside(child, content)) {
|
|
496
|
+
diagnostics.splice(i, 1);
|
|
497
|
+
}
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
384
504
|
function reportOverlaps(boxes, diagnostics, ignoredPairs = /* @__PURE__ */ new Set()) {
|
|
385
505
|
const ids = [...boxes.keys()].sort();
|
|
386
506
|
const reported = new Set(
|
|
@@ -688,6 +808,12 @@ function applyDistributeContained(input, boxes, locks, diagnostics) {
|
|
|
688
808
|
continue;
|
|
689
809
|
}
|
|
690
810
|
if (locks.has(childId)) {
|
|
811
|
+
const lock = locks.get(childId);
|
|
812
|
+
if (lock?.source === "fixed-position") {
|
|
813
|
+
unlocked.push({ id: childId, box });
|
|
814
|
+
locks.delete(childId);
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
691
817
|
diagnostics.push({
|
|
692
818
|
severity: "warning",
|
|
693
819
|
code: "constraints.locked-target-not-moved",
|
|
@@ -746,6 +872,7 @@ function applyDistributeContained(input, boxes, locks, diagnostics) {
|
|
|
746
872
|
});
|
|
747
873
|
}
|
|
748
874
|
boxes.set(child.id, clamped);
|
|
875
|
+
locks.delete(child.id);
|
|
749
876
|
pos = clamped[axis] + clamped[mainSize] + minGap;
|
|
750
877
|
}
|
|
751
878
|
diagnostics.push({
|
|
@@ -3991,7 +4118,7 @@ function routeEdge(input) {
|
|
|
3991
4118
|
const rerouted = greedyRerouteAroundObstacles(
|
|
3992
4119
|
bestPoints2,
|
|
3993
4120
|
allObstacles,
|
|
3994
|
-
|
|
4121
|
+
maxAttempts
|
|
3995
4122
|
);
|
|
3996
4123
|
const reroutedAvoidsEndpointInteriors = !routeIntersectsEndpointInteriors(
|
|
3997
4124
|
rerouted,
|
|
@@ -4753,9 +4880,7 @@ function solveDiagram(diagram, options = {}) {
|
|
|
4753
4880
|
options?.overlapSpacing ?? 40,
|
|
4754
4881
|
Math.max(0, options?.minLaneGutter ?? 0)
|
|
4755
4882
|
);
|
|
4756
|
-
|
|
4757
|
-
removeResolvedOverlapDiagnostics(diagnostics, constrained.boxes);
|
|
4758
|
-
}
|
|
4883
|
+
removeResolvedOverlapDiagnostics(diagnostics, constrained.boxes);
|
|
4759
4884
|
diagnostics.push(...swimlaneContracts.diagnostics);
|
|
4760
4885
|
const coordinatedNodes = coordinateNodes(
|
|
4761
4886
|
styledNodes,
|
|
@@ -6701,7 +6826,8 @@ function coordinateEdges(edges, nodes, coordinatedNodes, obstacles, softObstacle
|
|
|
6701
6826
|
...softObstacles,
|
|
6702
6827
|
...routeTextObstacles
|
|
6703
6828
|
],
|
|
6704
|
-
hardObstacles
|
|
6829
|
+
hardObstacles,
|
|
6830
|
+
...options.maxRoutingAttempts === void 0 ? {} : { maxRoutingAttempts: options.maxRoutingAttempts }
|
|
6705
6831
|
});
|
|
6706
6832
|
diagnostics.push(
|
|
6707
6833
|
...route.diagnostics.map((diagnostic) => ({
|
|
@@ -7184,7 +7310,8 @@ function edgeLabelAnchor(edge, layout2, edges, obstacleBoxes, placedLabelBoxes,
|
|
|
7184
7310
|
for (const candidate of edgeLabelAnchorCandidates(
|
|
7185
7311
|
edge.points,
|
|
7186
7312
|
placement,
|
|
7187
|
-
layout2
|
|
7313
|
+
layout2,
|
|
7314
|
+
baseOffset
|
|
7188
7315
|
)) {
|
|
7189
7316
|
const labelBox = {
|
|
7190
7317
|
x: candidate.x - layout2.box.width / 2,
|
|
@@ -7216,8 +7343,8 @@ function edgeLabelAnchor(edge, layout2, edges, obstacleBoxes, placedLabelBoxes,
|
|
|
7216
7343
|
}
|
|
7217
7344
|
return placement;
|
|
7218
7345
|
}
|
|
7219
|
-
function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
7220
|
-
const segment = labelSegmentOnPolyline(points);
|
|
7346
|
+
function edgeLabelAnchorCandidates(points, placement, layout2, baseOffset = 10) {
|
|
7347
|
+
const segment = labelSegmentOnPolyline(points, baseOffset);
|
|
7221
7348
|
if (segment === void 0) {
|
|
7222
7349
|
return [placement];
|
|
7223
7350
|
}
|
|
@@ -7267,7 +7394,7 @@ function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
|
7267
7394
|
}, 0);
|
|
7268
7395
|
if (totalLen > 200) {
|
|
7269
7396
|
for (const ratio of [0.25, 0.75]) {
|
|
7270
|
-
const qp = labelPlacementAtRatio(points, ratio, totalLen);
|
|
7397
|
+
const qp = labelPlacementAtRatio(points, ratio, totalLen, baseOffset);
|
|
7271
7398
|
if (qp !== void 0) {
|
|
7272
7399
|
candidates.push(qp);
|
|
7273
7400
|
const qTargetDist = totalLen * ratio;
|
|
@@ -7353,7 +7480,7 @@ function labelSegmentOnPolyline(points, baseOffset = 10) {
|
|
|
7353
7480
|
if (last === void 0) {
|
|
7354
7481
|
return void 0;
|
|
7355
7482
|
}
|
|
7356
|
-
const offset = labelOffset2(last);
|
|
7483
|
+
const offset = labelOffset2(last, baseOffset);
|
|
7357
7484
|
return {
|
|
7358
7485
|
start: last.start,
|
|
7359
7486
|
end: last.end,
|
|
@@ -7375,7 +7502,7 @@ function nonZeroSegments2(points) {
|
|
|
7375
7502
|
}
|
|
7376
7503
|
return segments;
|
|
7377
7504
|
}
|
|
7378
|
-
function labelPlacementAtRatio(points, ratio, totalLength) {
|
|
7505
|
+
function labelPlacementAtRatio(points, ratio, totalLength, baseOffset = 10) {
|
|
7379
7506
|
if (points.length < 2 || ratio < 0 || ratio > 1) {
|
|
7380
7507
|
return void 0;
|
|
7381
7508
|
}
|
|
@@ -7393,7 +7520,10 @@ function labelPlacementAtRatio(points, ratio, totalLength) {
|
|
|
7393
7520
|
}
|
|
7394
7521
|
if (travelled + segLen >= targetDist) {
|
|
7395
7522
|
const t = (targetDist - travelled) / segLen;
|
|
7396
|
-
const offset = labelOffset2(
|
|
7523
|
+
const offset = labelOffset2(
|
|
7524
|
+
{ start: prev, end: curr, length: segLen },
|
|
7525
|
+
baseOffset
|
|
7526
|
+
);
|
|
7397
7527
|
return {
|
|
7398
7528
|
x: prev.x + (curr.x - prev.x) * t + offset.x,
|
|
7399
7529
|
y: prev.y + (curr.y - prev.y) * t + offset.y
|