@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/cli/index.cjs
CHANGED
|
@@ -1292,6 +1292,9 @@ function applyLayoutConstraints(input) {
|
|
|
1292
1292
|
const nodeById = new Map(input.nodes.map((node) => [node.id, node]));
|
|
1293
1293
|
applyFixedPositionLocks(input.nodes, boxes, locks, diagnostics);
|
|
1294
1294
|
applyExactPositions(input.constraints, boxes, locks, diagnostics, nodeById);
|
|
1295
|
+
if (input.distributeContainedChildren) {
|
|
1296
|
+
yieldFixedPositionLocks(input, boxes, locks);
|
|
1297
|
+
}
|
|
1295
1298
|
applyContainment(input.constraints, boxes, locks, diagnostics, false);
|
|
1296
1299
|
applyRelative(input.constraints, boxes, locks, diagnostics);
|
|
1297
1300
|
applyAlign(input.constraints, boxes, locks, diagnostics);
|
|
@@ -1305,6 +1308,13 @@ function applyLayoutConstraints(input) {
|
|
|
1305
1308
|
);
|
|
1306
1309
|
applyContainment(input.constraints, boxes, locks, diagnostics, true);
|
|
1307
1310
|
applyDistributeContained(input, boxes, locks, diagnostics);
|
|
1311
|
+
if (input.distributeContainedChildren) {
|
|
1312
|
+
const diagBefore = diagnostics.length;
|
|
1313
|
+
applyContainment(input.constraints, boxes, locks, diagnostics, true);
|
|
1314
|
+
applyDistributeContained(input, boxes, locks, diagnostics);
|
|
1315
|
+
dedupReplayDiagnostics(diagnostics, diagBefore);
|
|
1316
|
+
}
|
|
1317
|
+
removeResolvedConstraintDiagnostics(input.constraints, boxes, diagnostics);
|
|
1308
1318
|
reportOverlaps(boxes, diagnostics, containmentOverlapKeys(input.constraints));
|
|
1309
1319
|
reportIntraContainerOverflow(input, boxes, diagnostics);
|
|
1310
1320
|
return { boxes, locks, diagnostics };
|
|
@@ -1350,6 +1360,62 @@ function applyFixedPositionLocks(nodes, boxes, locks, diagnostics) {
|
|
|
1350
1360
|
locks.set(node.id, { nodeId: node.id, source: "fixed-position" });
|
|
1351
1361
|
}
|
|
1352
1362
|
}
|
|
1363
|
+
function dedupReplayDiagnostics(diagnostics, keepUpTo) {
|
|
1364
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1365
|
+
for (let i = 0; i < keepUpTo && i < diagnostics.length; i += 1) {
|
|
1366
|
+
const d = diagnostics[i];
|
|
1367
|
+
if (d === void 0) continue;
|
|
1368
|
+
seen.add(diagnosticFingerprint(d));
|
|
1369
|
+
}
|
|
1370
|
+
for (let i = diagnostics.length - 1; i >= keepUpTo; i -= 1) {
|
|
1371
|
+
const d = diagnostics[i];
|
|
1372
|
+
if (d === void 0) continue;
|
|
1373
|
+
const fp = diagnosticFingerprint(d);
|
|
1374
|
+
if (seen.has(fp)) {
|
|
1375
|
+
diagnostics.splice(i, 1);
|
|
1376
|
+
} else {
|
|
1377
|
+
seen.add(fp);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
function diagnosticFingerprint(d) {
|
|
1382
|
+
const nodeId = typeof d.detail?.nodeId === "string" ? d.detail.nodeId : "";
|
|
1383
|
+
const containerId = typeof d.detail?.containerId === "string" ? d.detail.containerId : "";
|
|
1384
|
+
return `${d.code}|${nodeId}|${containerId}`;
|
|
1385
|
+
}
|
|
1386
|
+
function yieldFixedPositionLocks(input, boxes, locks) {
|
|
1387
|
+
for (const c of input.constraints) {
|
|
1388
|
+
if (c.kind !== "containment") continue;
|
|
1389
|
+
const container = boxes.get(c.containerId);
|
|
1390
|
+
if (container === void 0) continue;
|
|
1391
|
+
const content = contentBox(container, c.padding);
|
|
1392
|
+
const mainAxis = input.direction === "LR" || input.direction === "RL" ? "width" : "height";
|
|
1393
|
+
const crossAxis = mainAxis === "width" ? "height" : "width";
|
|
1394
|
+
let eligible = 0;
|
|
1395
|
+
for (const childId of c.childIds) {
|
|
1396
|
+
const box = boxes.get(childId);
|
|
1397
|
+
if (box === void 0) continue;
|
|
1398
|
+
const lock = locks.get(childId);
|
|
1399
|
+
if (lock?.source === "exact-position") continue;
|
|
1400
|
+
const fits = box[mainAxis] <= content[mainAxis] && box[crossAxis] <= content[crossAxis];
|
|
1401
|
+
if (fits) {
|
|
1402
|
+
eligible += 1;
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
if (eligible < 2) continue;
|
|
1406
|
+
for (const childId of c.childIds) {
|
|
1407
|
+
const lock = locks.get(childId);
|
|
1408
|
+
if (lock?.source === "fixed-position") {
|
|
1409
|
+
const box = boxes.get(childId);
|
|
1410
|
+
if (box === void 0) continue;
|
|
1411
|
+
const fits = box[mainAxis] <= content[mainAxis] && box[crossAxis] <= content[crossAxis];
|
|
1412
|
+
if (fits) {
|
|
1413
|
+
locks.delete(childId);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1353
1419
|
function applyExactPositions(constraints, boxes, locks, diagnostics, nodeById) {
|
|
1354
1420
|
for (const constraint of constraints) {
|
|
1355
1421
|
if (constraint.kind !== "exact-position") {
|
|
@@ -1422,7 +1488,7 @@ function applyContainment(constraints, boxes, locks, diagnostics, reportOverflow
|
|
|
1422
1488
|
code: "constraints.locked-target-not-moved",
|
|
1423
1489
|
message: `Locked child ${childId} was not moved into containment.`,
|
|
1424
1490
|
path: ["constraints", constraint.id ?? constraint.containerId],
|
|
1425
|
-
detail: { nodeId: childId }
|
|
1491
|
+
detail: { nodeId: childId, containerId: constraint.containerId }
|
|
1426
1492
|
});
|
|
1427
1493
|
if (!isInside(child, content)) {
|
|
1428
1494
|
diagnostics.push({
|
|
@@ -1574,6 +1640,60 @@ function repairOverlaps(input, boxes, locks, diagnostics, siblingPairs) {
|
|
|
1574
1640
|
}
|
|
1575
1641
|
reportOverlaps(boxes, diagnostics, ignoredPairs);
|
|
1576
1642
|
}
|
|
1643
|
+
function removeResolvedConstraintDiagnostics(constraints, boxes, diagnostics) {
|
|
1644
|
+
for (let i = diagnostics.length - 1; i >= 0; i -= 1) {
|
|
1645
|
+
const d = diagnostics[i];
|
|
1646
|
+
if (d === void 0) continue;
|
|
1647
|
+
if (d.code === "constraints.overlap.unresolved") {
|
|
1648
|
+
const aId = d.detail?.firstId;
|
|
1649
|
+
const bId = d.detail?.secondId;
|
|
1650
|
+
if (typeof aId !== "string" || typeof bId !== "string") continue;
|
|
1651
|
+
const a = boxes.get(aId);
|
|
1652
|
+
const b = boxes.get(bId);
|
|
1653
|
+
if (a !== void 0 && b !== void 0 && !intersectsAabb(a, b)) {
|
|
1654
|
+
diagnostics.splice(i, 1);
|
|
1655
|
+
}
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
if (d.code === "constraints.containment.impossible" || d.code === "constraints.locked-target-not-moved" && typeof d.message === "string" && d.message.includes("not moved into containment")) {
|
|
1659
|
+
const nodeId = d.detail?.nodeId;
|
|
1660
|
+
if (typeof nodeId !== "string") continue;
|
|
1661
|
+
const child = boxes.get(nodeId);
|
|
1662
|
+
if (child === void 0) continue;
|
|
1663
|
+
const diagContainerId = typeof d.detail?.containerId === "string" ? d.detail.containerId : void 0;
|
|
1664
|
+
let resolved = false;
|
|
1665
|
+
for (const c of constraints) {
|
|
1666
|
+
if (c.kind !== "containment") continue;
|
|
1667
|
+
if (!c.childIds.includes(nodeId)) continue;
|
|
1668
|
+
if (diagContainerId !== void 0 && c.containerId !== diagContainerId) {
|
|
1669
|
+
continue;
|
|
1670
|
+
}
|
|
1671
|
+
const container = boxes.get(c.containerId);
|
|
1672
|
+
if (container === void 0) continue;
|
|
1673
|
+
const content = contentBox(container, c.padding);
|
|
1674
|
+
if (isInside(child, content)) {
|
|
1675
|
+
diagnostics.splice(i, 1);
|
|
1676
|
+
resolved = true;
|
|
1677
|
+
}
|
|
1678
|
+
break;
|
|
1679
|
+
}
|
|
1680
|
+
if (!resolved && diagContainerId !== void 0) {
|
|
1681
|
+
for (const c of constraints) {
|
|
1682
|
+
if (c.kind !== "containment") continue;
|
|
1683
|
+
if (c.containerId !== diagContainerId) continue;
|
|
1684
|
+
if (!c.childIds.includes(nodeId)) continue;
|
|
1685
|
+
const container = boxes.get(c.containerId);
|
|
1686
|
+
if (container === void 0) continue;
|
|
1687
|
+
const content = contentBox(container, c.padding);
|
|
1688
|
+
if (isInside(child, content)) {
|
|
1689
|
+
diagnostics.splice(i, 1);
|
|
1690
|
+
}
|
|
1691
|
+
break;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1577
1697
|
function reportOverlaps(boxes, diagnostics, ignoredPairs = /* @__PURE__ */ new Set()) {
|
|
1578
1698
|
const ids = [...boxes.keys()].sort();
|
|
1579
1699
|
const reported = new Set(
|
|
@@ -1881,6 +2001,12 @@ function applyDistributeContained(input, boxes, locks, diagnostics) {
|
|
|
1881
2001
|
continue;
|
|
1882
2002
|
}
|
|
1883
2003
|
if (locks.has(childId)) {
|
|
2004
|
+
const lock = locks.get(childId);
|
|
2005
|
+
if (lock?.source === "fixed-position") {
|
|
2006
|
+
unlocked.push({ id: childId, box });
|
|
2007
|
+
locks.delete(childId);
|
|
2008
|
+
continue;
|
|
2009
|
+
}
|
|
1884
2010
|
diagnostics.push({
|
|
1885
2011
|
severity: "warning",
|
|
1886
2012
|
code: "constraints.locked-target-not-moved",
|
|
@@ -1939,6 +2065,7 @@ function applyDistributeContained(input, boxes, locks, diagnostics) {
|
|
|
1939
2065
|
});
|
|
1940
2066
|
}
|
|
1941
2067
|
boxes.set(child.id, clamped);
|
|
2068
|
+
locks.delete(child.id);
|
|
1942
2069
|
pos = clamped[axis] + clamped[mainSize] + minGap;
|
|
1943
2070
|
}
|
|
1944
2071
|
diagnostics.push({
|
|
@@ -3388,7 +3515,7 @@ function routeEdge(input) {
|
|
|
3388
3515
|
const rerouted = greedyRerouteAroundObstacles(
|
|
3389
3516
|
bestPoints2,
|
|
3390
3517
|
allObstacles,
|
|
3391
|
-
|
|
3518
|
+
maxAttempts
|
|
3392
3519
|
);
|
|
3393
3520
|
const reroutedAvoidsEndpointInteriors = !routeIntersectsEndpointInteriors(
|
|
3394
3521
|
rerouted,
|
|
@@ -4150,9 +4277,7 @@ function solveDiagram(diagram, options = {}) {
|
|
|
4150
4277
|
options?.overlapSpacing ?? 40,
|
|
4151
4278
|
Math.max(0, options?.minLaneGutter ?? 0)
|
|
4152
4279
|
);
|
|
4153
|
-
|
|
4154
|
-
removeResolvedOverlapDiagnostics(diagnostics, constrained.boxes);
|
|
4155
|
-
}
|
|
4280
|
+
removeResolvedOverlapDiagnostics(diagnostics, constrained.boxes);
|
|
4156
4281
|
diagnostics.push(...swimlaneContracts.diagnostics);
|
|
4157
4282
|
const coordinatedNodes = coordinateNodes(
|
|
4158
4283
|
styledNodes,
|
|
@@ -6095,7 +6220,8 @@ function coordinateEdges(edges, nodes, coordinatedNodes, obstacles, softObstacle
|
|
|
6095
6220
|
...softObstacles,
|
|
6096
6221
|
...routeTextObstacles
|
|
6097
6222
|
],
|
|
6098
|
-
hardObstacles
|
|
6223
|
+
hardObstacles,
|
|
6224
|
+
...options.maxRoutingAttempts === void 0 ? {} : { maxRoutingAttempts: options.maxRoutingAttempts }
|
|
6099
6225
|
});
|
|
6100
6226
|
diagnostics.push(
|
|
6101
6227
|
...route.diagnostics.map((diagnostic) => ({
|
|
@@ -6578,7 +6704,8 @@ function edgeLabelAnchor(edge, layout2, edges, obstacleBoxes, placedLabelBoxes,
|
|
|
6578
6704
|
for (const candidate of edgeLabelAnchorCandidates(
|
|
6579
6705
|
edge.points,
|
|
6580
6706
|
placement,
|
|
6581
|
-
layout2
|
|
6707
|
+
layout2,
|
|
6708
|
+
baseOffset
|
|
6582
6709
|
)) {
|
|
6583
6710
|
const labelBox = {
|
|
6584
6711
|
x: candidate.x - layout2.box.width / 2,
|
|
@@ -6610,8 +6737,8 @@ function edgeLabelAnchor(edge, layout2, edges, obstacleBoxes, placedLabelBoxes,
|
|
|
6610
6737
|
}
|
|
6611
6738
|
return placement;
|
|
6612
6739
|
}
|
|
6613
|
-
function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
6614
|
-
const segment = labelSegmentOnPolyline(points);
|
|
6740
|
+
function edgeLabelAnchorCandidates(points, placement, layout2, baseOffset = 10) {
|
|
6741
|
+
const segment = labelSegmentOnPolyline(points, baseOffset);
|
|
6615
6742
|
if (segment === void 0) {
|
|
6616
6743
|
return [placement];
|
|
6617
6744
|
}
|
|
@@ -6661,7 +6788,7 @@ function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
|
6661
6788
|
}, 0);
|
|
6662
6789
|
if (totalLen > 200) {
|
|
6663
6790
|
for (const ratio of [0.25, 0.75]) {
|
|
6664
|
-
const qp = labelPlacementAtRatio(points, ratio, totalLen);
|
|
6791
|
+
const qp = labelPlacementAtRatio(points, ratio, totalLen, baseOffset);
|
|
6665
6792
|
if (qp !== void 0) {
|
|
6666
6793
|
candidates.push(qp);
|
|
6667
6794
|
const qTargetDist = totalLen * ratio;
|
|
@@ -6747,7 +6874,7 @@ function labelSegmentOnPolyline(points, baseOffset = 10) {
|
|
|
6747
6874
|
if (last === void 0) {
|
|
6748
6875
|
return void 0;
|
|
6749
6876
|
}
|
|
6750
|
-
const offset = labelOffset2(last);
|
|
6877
|
+
const offset = labelOffset2(last, baseOffset);
|
|
6751
6878
|
return {
|
|
6752
6879
|
start: last.start,
|
|
6753
6880
|
end: last.end,
|
|
@@ -6769,7 +6896,7 @@ function nonZeroSegments2(points) {
|
|
|
6769
6896
|
}
|
|
6770
6897
|
return segments;
|
|
6771
6898
|
}
|
|
6772
|
-
function labelPlacementAtRatio(points, ratio, totalLength) {
|
|
6899
|
+
function labelPlacementAtRatio(points, ratio, totalLength, baseOffset = 10) {
|
|
6773
6900
|
if (points.length < 2 || ratio < 0 || ratio > 1) {
|
|
6774
6901
|
return void 0;
|
|
6775
6902
|
}
|
|
@@ -6787,7 +6914,10 @@ function labelPlacementAtRatio(points, ratio, totalLength) {
|
|
|
6787
6914
|
}
|
|
6788
6915
|
if (travelled + segLen >= targetDist) {
|
|
6789
6916
|
const t = (targetDist - travelled) / segLen;
|
|
6790
|
-
const offset = labelOffset2(
|
|
6917
|
+
const offset = labelOffset2(
|
|
6918
|
+
{ start: prev, end: curr, length: segLen },
|
|
6919
|
+
baseOffset
|
|
6920
|
+
);
|
|
6791
6921
|
return {
|
|
6792
6922
|
x: prev.x + (curr.x - prev.x) * t + offset.x,
|
|
6793
6923
|
y: prev.y + (curr.y - prev.y) * t + offset.y
|