@crazyhappyone/auto-graph 0.2.9 → 0.2.11
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 +201 -38
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +201 -38
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +201 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +201 -38
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -770,6 +770,12 @@ interface RouteEdgeInput {
|
|
|
770
770
|
hardObstacleIndex?: BoxSpatialIndex;
|
|
771
771
|
/** Maximum greedy rerouting iterations (default 5). */
|
|
772
772
|
maxRoutingAttempts?: number;
|
|
773
|
+
/** Corridor expansion margin in px for corner-graph prefilter (default 32).
|
|
774
|
+
* Larger values include more obstacles in the local routing window. */
|
|
775
|
+
corridorMargin?: number;
|
|
776
|
+
/** Route-length / direct-distance ratio above which a backtracking
|
|
777
|
+
* warning is emitted (default 20). */
|
|
778
|
+
maxBacktrackingRatio?: number;
|
|
773
779
|
}
|
|
774
780
|
interface RouteEdgeResult {
|
|
775
781
|
points: Point[];
|
|
@@ -832,6 +838,15 @@ interface SolveDiagramOptions {
|
|
|
832
838
|
labelPlacement?: "beside" | "on-path";
|
|
833
839
|
/** Pixels to offset edge labels from the edge path when labelPlacement is "beside". */
|
|
834
840
|
labelOffset?: number;
|
|
841
|
+
/** Corridor expansion margin for corner-graph prefilter.
|
|
842
|
+
* - number: fixed px margin
|
|
843
|
+
* - "auto" (default): max(200, contentDiagonal * 0.3)
|
|
844
|
+
* Larger margins include more obstacles in the local routing window,
|
|
845
|
+
* improving path quality on dense diagrams at the cost of more vertices. */
|
|
846
|
+
corridorMargin?: number | "auto";
|
|
847
|
+
/** Route-length / direct-distance ratio above which a backtracking
|
|
848
|
+
* warning is emitted (default 20). */
|
|
849
|
+
maxBacktrackingRatio?: number;
|
|
835
850
|
}
|
|
836
851
|
interface PortShiftingOptions {
|
|
837
852
|
enabled?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -770,6 +770,12 @@ interface RouteEdgeInput {
|
|
|
770
770
|
hardObstacleIndex?: BoxSpatialIndex;
|
|
771
771
|
/** Maximum greedy rerouting iterations (default 5). */
|
|
772
772
|
maxRoutingAttempts?: number;
|
|
773
|
+
/** Corridor expansion margin in px for corner-graph prefilter (default 32).
|
|
774
|
+
* Larger values include more obstacles in the local routing window. */
|
|
775
|
+
corridorMargin?: number;
|
|
776
|
+
/** Route-length / direct-distance ratio above which a backtracking
|
|
777
|
+
* warning is emitted (default 20). */
|
|
778
|
+
maxBacktrackingRatio?: number;
|
|
773
779
|
}
|
|
774
780
|
interface RouteEdgeResult {
|
|
775
781
|
points: Point[];
|
|
@@ -832,6 +838,15 @@ interface SolveDiagramOptions {
|
|
|
832
838
|
labelPlacement?: "beside" | "on-path";
|
|
833
839
|
/** Pixels to offset edge labels from the edge path when labelPlacement is "beside". */
|
|
834
840
|
labelOffset?: number;
|
|
841
|
+
/** Corridor expansion margin for corner-graph prefilter.
|
|
842
|
+
* - number: fixed px margin
|
|
843
|
+
* - "auto" (default): max(200, contentDiagonal * 0.3)
|
|
844
|
+
* Larger margins include more obstacles in the local routing window,
|
|
845
|
+
* improving path quality on dense diagrams at the cost of more vertices. */
|
|
846
|
+
corridorMargin?: number | "auto";
|
|
847
|
+
/** Route-length / direct-distance ratio above which a backtracking
|
|
848
|
+
* warning is emitted (default 20). */
|
|
849
|
+
maxBacktrackingRatio?: number;
|
|
835
850
|
}
|
|
836
851
|
interface PortShiftingOptions {
|
|
837
852
|
enabled?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -5381,7 +5381,7 @@ function segmentCrossesAnyObstacle(a, b, obstacles) {
|
|
|
5381
5381
|
}
|
|
5382
5382
|
|
|
5383
5383
|
// src/routing/routes.ts
|
|
5384
|
-
function checkBacktracking(points, source, target, diagnostics) {
|
|
5384
|
+
function checkBacktracking(points, source, target, diagnostics, maxRatio) {
|
|
5385
5385
|
if (points.length < 2) return;
|
|
5386
5386
|
const direct = Math.hypot(target.x - source.x, target.y - source.y);
|
|
5387
5387
|
if (direct <= 0) return;
|
|
@@ -5391,7 +5391,7 @@ function checkBacktracking(points, source, target, diagnostics) {
|
|
|
5391
5391
|
const b = points[i + 1];
|
|
5392
5392
|
routeLen += Math.hypot(b.x - a.x, b.y - a.y);
|
|
5393
5393
|
}
|
|
5394
|
-
const threshold =
|
|
5394
|
+
const threshold = maxRatio ?? 20;
|
|
5395
5395
|
if (routeLen > direct * threshold) {
|
|
5396
5396
|
diagnostics.push({
|
|
5397
5397
|
severity: "warning",
|
|
@@ -5409,8 +5409,20 @@ function routeEdge(input) {
|
|
|
5409
5409
|
const diagnostics = [];
|
|
5410
5410
|
const softObstacles = input.obstacles ?? [];
|
|
5411
5411
|
const hardObstacles = input.hardObstacles ?? [];
|
|
5412
|
+
let bestRejectedPath;
|
|
5413
|
+
let bestRejectedCrossings = Number.POSITIVE_INFINITY;
|
|
5412
5414
|
const softObstacleIndex = input.obstacleIndex ?? createBoxSpatialIndex(indexedBoxes(softObstacles));
|
|
5413
5415
|
const hardObstacleIndex = input.hardObstacleIndex ?? createBoxSpatialIndex(indexedBoxes(hardObstacles));
|
|
5416
|
+
const recordRejected = (candidate) => {
|
|
5417
|
+
if (routeIntersectsObstacles(candidate, hardObstacles, hardObstacleIndex)) {
|
|
5418
|
+
return;
|
|
5419
|
+
}
|
|
5420
|
+
const crossings = countObstacleCrossings(candidate, softObstacles);
|
|
5421
|
+
if (crossings < bestRejectedCrossings) {
|
|
5422
|
+
bestRejectedCrossings = crossings;
|
|
5423
|
+
bestRejectedPath = candidate;
|
|
5424
|
+
}
|
|
5425
|
+
};
|
|
5414
5426
|
const maxAttempts = input.maxRoutingAttempts ?? 5;
|
|
5415
5427
|
const defaultAnchors = defaultAnchorsForGeometry(
|
|
5416
5428
|
input.source.box,
|
|
@@ -5470,13 +5482,14 @@ function routeEdge(input) {
|
|
|
5470
5482
|
targetAnchor
|
|
5471
5483
|
);
|
|
5472
5484
|
const allObstacles = [...softObstacles, ...hardObstacles];
|
|
5485
|
+
const corridorMargin = input.corridorMargin ?? 32;
|
|
5473
5486
|
const corridorObstacles = filterObstaclesByCorridor(
|
|
5474
5487
|
source,
|
|
5475
5488
|
target,
|
|
5476
5489
|
allObstacles,
|
|
5477
5490
|
[],
|
|
5478
5491
|
// endpointObstacles passed separately via options
|
|
5479
|
-
|
|
5492
|
+
corridorMargin
|
|
5480
5493
|
);
|
|
5481
5494
|
const cornerObstacles = corridorObstacles.length === 0 && allObstacles.length > 0 ? allObstacles : corridorObstacles;
|
|
5482
5495
|
let cornerPath = findCornerGraphPath(
|
|
@@ -5499,7 +5512,7 @@ function routeEdge(input) {
|
|
|
5499
5512
|
source,
|
|
5500
5513
|
target,
|
|
5501
5514
|
allObstacles,
|
|
5502
|
-
{ endpointObstacles, margin: 0 },
|
|
5515
|
+
{ endpointObstacles, margin: 0, corridorMargin },
|
|
5503
5516
|
diagnostics
|
|
5504
5517
|
);
|
|
5505
5518
|
if (path !== null && path.length >= 2) {
|
|
@@ -5516,9 +5529,16 @@ function routeEdge(input) {
|
|
|
5516
5529
|
softObstacles,
|
|
5517
5530
|
softObstacleIndex
|
|
5518
5531
|
) && !routeIntersectsObstacles(finalized, hardObstacles, hardObstacleIndex)) {
|
|
5519
|
-
checkBacktracking(
|
|
5532
|
+
checkBacktracking(
|
|
5533
|
+
finalized,
|
|
5534
|
+
source,
|
|
5535
|
+
target,
|
|
5536
|
+
diagnostics,
|
|
5537
|
+
input.maxBacktrackingRatio
|
|
5538
|
+
);
|
|
5520
5539
|
return { points: finalized, diagnostics };
|
|
5521
5540
|
}
|
|
5541
|
+
recordRejected(finalized);
|
|
5522
5542
|
if (cornerPath !== null) {
|
|
5523
5543
|
const fullCornerPath = cornerObstacles.length < allObstacles.length ? findCornerGraphPath(
|
|
5524
5544
|
source,
|
|
@@ -5545,15 +5565,22 @@ function routeEdge(input) {
|
|
|
5545
5565
|
hardObstacles,
|
|
5546
5566
|
hardObstacleIndex
|
|
5547
5567
|
)) {
|
|
5548
|
-
checkBacktracking(
|
|
5568
|
+
checkBacktracking(
|
|
5569
|
+
fullFinalized,
|
|
5570
|
+
source,
|
|
5571
|
+
target,
|
|
5572
|
+
diagnostics,
|
|
5573
|
+
input.maxBacktrackingRatio
|
|
5574
|
+
);
|
|
5549
5575
|
return { points: fullFinalized, diagnostics };
|
|
5550
5576
|
}
|
|
5577
|
+
recordRejected(fullFinalized);
|
|
5551
5578
|
}
|
|
5552
5579
|
const gridPath = findObstacleFreePath(
|
|
5553
5580
|
source,
|
|
5554
5581
|
target,
|
|
5555
5582
|
allObstacles,
|
|
5556
|
-
{ endpointObstacles, margin: 0 },
|
|
5583
|
+
{ endpointObstacles, margin: 0, corridorMargin },
|
|
5557
5584
|
diagnostics
|
|
5558
5585
|
);
|
|
5559
5586
|
if (gridPath !== null && gridPath.length >= 2) {
|
|
@@ -5574,9 +5601,16 @@ function routeEdge(input) {
|
|
|
5574
5601
|
hardObstacles,
|
|
5575
5602
|
hardObstacleIndex
|
|
5576
5603
|
)) {
|
|
5577
|
-
checkBacktracking(
|
|
5604
|
+
checkBacktracking(
|
|
5605
|
+
gridFinalized,
|
|
5606
|
+
source,
|
|
5607
|
+
target,
|
|
5608
|
+
diagnostics,
|
|
5609
|
+
input.maxBacktrackingRatio
|
|
5610
|
+
);
|
|
5578
5611
|
return { points: gridFinalized, diagnostics };
|
|
5579
5612
|
}
|
|
5613
|
+
recordRejected(gridFinalized);
|
|
5580
5614
|
}
|
|
5581
5615
|
}
|
|
5582
5616
|
}
|
|
@@ -5640,7 +5674,8 @@ function routeEdge(input) {
|
|
|
5640
5674
|
finalizedClean,
|
|
5641
5675
|
candidate.points[0],
|
|
5642
5676
|
candidate.points[candidate.points.length - 1],
|
|
5643
|
-
diagnostics
|
|
5677
|
+
diagnostics,
|
|
5678
|
+
input.maxBacktrackingRatio
|
|
5644
5679
|
);
|
|
5645
5680
|
return { points: finalizedClean, diagnostics };
|
|
5646
5681
|
}
|
|
@@ -5706,13 +5741,41 @@ function routeEdge(input) {
|
|
|
5706
5741
|
code: "routing.obstacle.unavoidable",
|
|
5707
5742
|
message: "No bounded orthogonal route candidate avoided all soft obstacles."
|
|
5708
5743
|
});
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5744
|
+
const finalizedSoftBest = finalizeRoute(
|
|
5745
|
+
bestPoints2,
|
|
5746
|
+
softObstacles,
|
|
5747
|
+
hardObstacles,
|
|
5748
|
+
diagnostics
|
|
5749
|
+
);
|
|
5750
|
+
let softFallback = finalizedSoftBest;
|
|
5751
|
+
if (bestRejectedPath !== void 0) {
|
|
5752
|
+
const finalizedRejected = finalizeRoute(
|
|
5753
|
+
bestRejectedPath,
|
|
5712
5754
|
softObstacles,
|
|
5713
5755
|
hardObstacles,
|
|
5714
5756
|
diagnostics
|
|
5715
|
-
)
|
|
5757
|
+
);
|
|
5758
|
+
const rejectedCrossings = countObstacleCrossings(
|
|
5759
|
+
finalizedRejected,
|
|
5760
|
+
softObstacles
|
|
5761
|
+
);
|
|
5762
|
+
const heuristicCrossings = countObstacleCrossings(
|
|
5763
|
+
finalizedSoftBest,
|
|
5764
|
+
softObstacles
|
|
5765
|
+
);
|
|
5766
|
+
if (rejectedCrossings < heuristicCrossings) {
|
|
5767
|
+
softFallback = finalizedRejected;
|
|
5768
|
+
}
|
|
5769
|
+
}
|
|
5770
|
+
checkBacktracking(
|
|
5771
|
+
softFallback,
|
|
5772
|
+
softFallback[0],
|
|
5773
|
+
softFallback[softFallback.length - 1],
|
|
5774
|
+
diagnostics,
|
|
5775
|
+
input.maxBacktrackingRatio
|
|
5776
|
+
);
|
|
5777
|
+
return {
|
|
5778
|
+
points: softFallback,
|
|
5716
5779
|
diagnostics
|
|
5717
5780
|
};
|
|
5718
5781
|
}
|
|
@@ -5744,6 +5807,22 @@ function routeEdge(input) {
|
|
|
5744
5807
|
maxAttempts
|
|
5745
5808
|
);
|
|
5746
5809
|
}
|
|
5810
|
+
if (bestRejectedPath !== void 0) {
|
|
5811
|
+
diagnostics.push({
|
|
5812
|
+
severity: "warning",
|
|
5813
|
+
code: "routing.obstacle.unavoidable",
|
|
5814
|
+
message: "Using A* route with minor soft-obstacle crossings to avoid hard evidence obstacles."
|
|
5815
|
+
});
|
|
5816
|
+
return {
|
|
5817
|
+
points: finalizeRoute(
|
|
5818
|
+
bestRejectedPath,
|
|
5819
|
+
softObstacles,
|
|
5820
|
+
hardObstacles,
|
|
5821
|
+
diagnostics
|
|
5822
|
+
),
|
|
5823
|
+
diagnostics
|
|
5824
|
+
};
|
|
5825
|
+
}
|
|
5747
5826
|
diagnostics.push({
|
|
5748
5827
|
severity: "error",
|
|
5749
5828
|
code: "routing.evidence.crossing_forbidden",
|
|
@@ -5791,13 +5870,41 @@ function routeEdge(input) {
|
|
|
5791
5870
|
code: "routing.obstacle.unavoidable",
|
|
5792
5871
|
message: "No bounded orthogonal route candidate avoided all obstacles."
|
|
5793
5872
|
});
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5873
|
+
const finalizedBestPoints = finalizeRoute(
|
|
5874
|
+
bestPoints,
|
|
5875
|
+
softObstacles,
|
|
5876
|
+
hardObstacles,
|
|
5877
|
+
diagnostics
|
|
5878
|
+
);
|
|
5879
|
+
let fallbackPoints = finalizedBestPoints;
|
|
5880
|
+
if (bestRejectedPath !== void 0) {
|
|
5881
|
+
const finalizedRejected = finalizeRoute(
|
|
5882
|
+
bestRejectedPath,
|
|
5797
5883
|
softObstacles,
|
|
5798
5884
|
hardObstacles,
|
|
5799
5885
|
diagnostics
|
|
5800
|
-
)
|
|
5886
|
+
);
|
|
5887
|
+
const rejectedCrossings = countObstacleCrossings(
|
|
5888
|
+
finalizedRejected,
|
|
5889
|
+
softObstacles
|
|
5890
|
+
);
|
|
5891
|
+
const heuristicCrossings = countObstacleCrossings(
|
|
5892
|
+
finalizedBestPoints,
|
|
5893
|
+
softObstacles
|
|
5894
|
+
);
|
|
5895
|
+
if (rejectedCrossings < heuristicCrossings) {
|
|
5896
|
+
fallbackPoints = finalizedRejected;
|
|
5897
|
+
}
|
|
5898
|
+
}
|
|
5899
|
+
checkBacktracking(
|
|
5900
|
+
fallbackPoints,
|
|
5901
|
+
fallbackPoints[0],
|
|
5902
|
+
fallbackPoints[fallbackPoints.length - 1],
|
|
5903
|
+
diagnostics,
|
|
5904
|
+
input.maxBacktrackingRatio
|
|
5905
|
+
);
|
|
5906
|
+
return {
|
|
5907
|
+
points: fallbackPoints,
|
|
5801
5908
|
diagnostics
|
|
5802
5909
|
};
|
|
5803
5910
|
}
|
|
@@ -6296,6 +6403,24 @@ function routeIntersectsObstacles(points, obstacles, spatialIndex) {
|
|
|
6296
6403
|
}
|
|
6297
6404
|
return false;
|
|
6298
6405
|
}
|
|
6406
|
+
function countObstacleCrossings(points, obstacles) {
|
|
6407
|
+
let count = 0;
|
|
6408
|
+
for (const obstacle of obstacles) {
|
|
6409
|
+
validateBox(obstacle);
|
|
6410
|
+
for (let pointIndex = 0; pointIndex < points.length - 1; pointIndex += 1) {
|
|
6411
|
+
const a = points[pointIndex];
|
|
6412
|
+
const b = points[pointIndex + 1];
|
|
6413
|
+
if (a === void 0 || b === void 0) {
|
|
6414
|
+
continue;
|
|
6415
|
+
}
|
|
6416
|
+
if (intersectsAabb(segmentBox2(a, b), obstacle)) {
|
|
6417
|
+
count += 1;
|
|
6418
|
+
break;
|
|
6419
|
+
}
|
|
6420
|
+
}
|
|
6421
|
+
}
|
|
6422
|
+
return count;
|
|
6423
|
+
}
|
|
6299
6424
|
function routeIntersectsEndpointInteriors(points, endpointInteriors) {
|
|
6300
6425
|
for (let index = 0; index < points.length - 1; index += 1) {
|
|
6301
6426
|
const a = points[index];
|
|
@@ -6741,7 +6866,8 @@ function solveDiagram(diagram, options = {}) {
|
|
|
6741
6866
|
constrained.boxes,
|
|
6742
6867
|
constrained.locks,
|
|
6743
6868
|
options?.overlapSpacing ?? 40,
|
|
6744
|
-
Math.max(0, options?.minLaneGutter ?? 0)
|
|
6869
|
+
Math.max(0, options?.minLaneGutter ?? 0),
|
|
6870
|
+
options.distributeContainedChildren ?? true
|
|
6745
6871
|
);
|
|
6746
6872
|
removeResolvedOverlapDiagnostics(diagnostics, constrained.boxes);
|
|
6747
6873
|
diagnostics.push(...swimlaneContracts.diagnostics);
|
|
@@ -6908,7 +7034,8 @@ function solveDiagram(diagram, options = {}) {
|
|
|
6908
7034
|
diagram.direction,
|
|
6909
7035
|
options,
|
|
6910
7036
|
diagnostics,
|
|
6911
|
-
coordinatedGroups
|
|
7037
|
+
coordinatedGroups,
|
|
7038
|
+
contentBounds
|
|
6912
7039
|
);
|
|
6913
7040
|
const edgeTextAnnotations = coordinateEdgeTextAnnotations(
|
|
6914
7041
|
coordinatedEdges,
|
|
@@ -7330,7 +7457,7 @@ function reportCjkTypographyDiagnostics(path, typography, previousStyle, diagnos
|
|
|
7330
7457
|
function containsCjk(value) {
|
|
7331
7458
|
return /[\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/u.test(value);
|
|
7332
7459
|
}
|
|
7333
|
-
function applySwimlaneLayoutContracts(swimlanes, constraints, edges, topToBottomFlow, nodeBoxes, locks, overlapSpacing, laneGutter) {
|
|
7460
|
+
function applySwimlaneLayoutContracts(swimlanes, constraints, edges, topToBottomFlow, nodeBoxes, locks, overlapSpacing, laneGutter, distributeContainedChildren) {
|
|
7334
7461
|
const layouts = /* @__PURE__ */ new Map();
|
|
7335
7462
|
const diagnostics = [];
|
|
7336
7463
|
const movedChildIds = /* @__PURE__ */ new Set();
|
|
@@ -7349,7 +7476,9 @@ function applySwimlaneLayoutContracts(swimlanes, constraints, edges, topToBottom
|
|
|
7349
7476
|
locks,
|
|
7350
7477
|
diagnostics,
|
|
7351
7478
|
movedChildIds,
|
|
7352
|
-
laneGutter
|
|
7479
|
+
laneGutter,
|
|
7480
|
+
constraints,
|
|
7481
|
+
distributeContainedChildren
|
|
7353
7482
|
);
|
|
7354
7483
|
if (layout2 !== void 0) {
|
|
7355
7484
|
layouts.set(swimlane.id, layout2);
|
|
@@ -7541,7 +7670,7 @@ function isStackRunaway(boxes, nodes, direction, options) {
|
|
|
7541
7670
|
const maxWidth = Math.max(...nodeBoxes.map((box) => box.width));
|
|
7542
7671
|
return xSpread <= Math.max(maxWidth, options.overlapSpacing ?? 40);
|
|
7543
7672
|
}
|
|
7544
|
-
function applySingleSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes, locks, diagnostics, movedChildIds, laneGutter) {
|
|
7673
|
+
function applySingleSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes, locks, diagnostics, movedChildIds, laneGutter, constraints, distributeContainedChildren) {
|
|
7545
7674
|
const headerHeight = swimlane.headerHeight ?? 28;
|
|
7546
7675
|
const padding = swimlane.padding ?? 16;
|
|
7547
7676
|
const laneBounds = swimlane.lanes.map((lane) => {
|
|
@@ -7566,7 +7695,9 @@ function applySingleSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes
|
|
|
7566
7695
|
locks,
|
|
7567
7696
|
diagnostics,
|
|
7568
7697
|
movedChildIds,
|
|
7569
|
-
laneGutter
|
|
7698
|
+
laneGutter,
|
|
7699
|
+
constraints,
|
|
7700
|
+
distributeContainedChildren
|
|
7570
7701
|
);
|
|
7571
7702
|
}
|
|
7572
7703
|
return applyHorizontalSwimlaneContract(
|
|
@@ -7581,13 +7712,29 @@ function applySingleSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes
|
|
|
7581
7712
|
laneGutter
|
|
7582
7713
|
);
|
|
7583
7714
|
}
|
|
7584
|
-
function applyVerticalSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes, laneBounds, headerHeight, padding, locks, diagnostics, movedChildIds, laneGutter) {
|
|
7715
|
+
function applyVerticalSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes, laneBounds, headerHeight, padding, locks, diagnostics, movedChildIds, laneGutter, constraints, distributeContainedChildren) {
|
|
7585
7716
|
const populatedBounds = laneBounds.filter(
|
|
7586
7717
|
(box) => box !== void 0
|
|
7587
7718
|
);
|
|
7588
7719
|
const top = Math.min(...populatedBounds.map((box) => box.y));
|
|
7589
7720
|
const left = Math.min(...populatedBounds.map((box) => box.x));
|
|
7590
7721
|
const maxChildHeight = Math.max(...populatedBounds.map((box) => box.height));
|
|
7722
|
+
const containedChildIds = /* @__PURE__ */ new Set();
|
|
7723
|
+
if (distributeContainedChildren) {
|
|
7724
|
+
for (const c of constraints) {
|
|
7725
|
+
if (c.kind !== "containment") continue;
|
|
7726
|
+
if (nodeBoxes.get(c.containerId) === void 0) continue;
|
|
7727
|
+
const distributable = c.childIds.filter((childId) => {
|
|
7728
|
+
if (nodeBoxes.get(childId) === void 0) return false;
|
|
7729
|
+
const lock = locks.get(childId);
|
|
7730
|
+
return lock === void 0 || lock.source === "fixed-position";
|
|
7731
|
+
});
|
|
7732
|
+
if (distributable.length < 2) continue;
|
|
7733
|
+
for (const childId of distributable) {
|
|
7734
|
+
containedChildIds.add(childId);
|
|
7735
|
+
}
|
|
7736
|
+
}
|
|
7737
|
+
}
|
|
7591
7738
|
const flowRanks = topToBottomFlow ? rankVerticalSwimlaneChildren(swimlane, edges) : /* @__PURE__ */ new Map();
|
|
7592
7739
|
const maxRank = flowRanks.size === 0 ? 0 : Math.max(...Array.from(flowRanks.values()));
|
|
7593
7740
|
const rankStackGap = Math.max(8, padding / 2);
|
|
@@ -7604,7 +7751,8 @@ function applyVerticalSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBox
|
|
|
7604
7751
|
nodeBoxes,
|
|
7605
7752
|
flowRanks,
|
|
7606
7753
|
locks,
|
|
7607
|
-
rankStackGap
|
|
7754
|
+
rankStackGap,
|
|
7755
|
+
containedChildIds
|
|
7608
7756
|
);
|
|
7609
7757
|
const slotWidth = Math.max(
|
|
7610
7758
|
Math.max(...populatedBounds.map((box) => box.width)),
|
|
@@ -7626,7 +7774,10 @@ function applyVerticalSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBox
|
|
|
7626
7774
|
const distributable = lane.children.filter(
|
|
7627
7775
|
(childId) => !locks.has(childId)
|
|
7628
7776
|
);
|
|
7629
|
-
|
|
7777
|
+
const coveredByContainment = lane.children.some(
|
|
7778
|
+
(childId) => containedChildIds.has(childId)
|
|
7779
|
+
);
|
|
7780
|
+
if (!coveredByContainment && distributable.length >= CROSS_AXIS_SPREAD_THRESHOLD) {
|
|
7630
7781
|
moveRankedVerticalLaneChildren(
|
|
7631
7782
|
lane.children,
|
|
7632
7783
|
nodeBoxes,
|
|
@@ -7654,6 +7805,9 @@ function applyVerticalSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBox
|
|
|
7654
7805
|
);
|
|
7655
7806
|
continue;
|
|
7656
7807
|
}
|
|
7808
|
+
const rankedCoveredByContainment = lane.children.some(
|
|
7809
|
+
(childId) => containedChildIds.has(childId)
|
|
7810
|
+
);
|
|
7657
7811
|
moveRankedVerticalLaneChildren(
|
|
7658
7812
|
lane.children,
|
|
7659
7813
|
nodeBoxes,
|
|
@@ -7664,7 +7818,8 @@ function applyVerticalSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBox
|
|
|
7664
7818
|
rankSpacing,
|
|
7665
7819
|
rankStackGap,
|
|
7666
7820
|
{ x: target.x, y: laneContentTop },
|
|
7667
|
-
slotWidth - padding * 2
|
|
7821
|
+
slotWidth - padding * 2,
|
|
7822
|
+
rankedCoveredByContainment
|
|
7668
7823
|
);
|
|
7669
7824
|
}
|
|
7670
7825
|
return {
|
|
@@ -7780,9 +7935,12 @@ function crossAxisSpreadWidth(items, gap) {
|
|
|
7780
7935
|
0
|
|
7781
7936
|
);
|
|
7782
7937
|
}
|
|
7783
|
-
function maxCrossAxisSpreadWidth(swimlane, nodeBoxes, flowRanks, locks, gap) {
|
|
7938
|
+
function maxCrossAxisSpreadWidth(swimlane, nodeBoxes, flowRanks, locks, gap, containedChildIds) {
|
|
7784
7939
|
let maxWidth = 0;
|
|
7785
7940
|
for (const lane of swimlane.lanes) {
|
|
7941
|
+
if (containedChildIds !== void 0 && lane.children.some((childId) => containedChildIds.has(childId))) {
|
|
7942
|
+
continue;
|
|
7943
|
+
}
|
|
7786
7944
|
for (const stack of rankStacks(
|
|
7787
7945
|
lane.children,
|
|
7788
7946
|
nodeBoxes,
|
|
@@ -7795,7 +7953,7 @@ function maxCrossAxisSpreadWidth(swimlane, nodeBoxes, flowRanks, locks, gap) {
|
|
|
7795
7953
|
}
|
|
7796
7954
|
return maxWidth;
|
|
7797
7955
|
}
|
|
7798
|
-
function moveRankedVerticalLaneChildren(childIds, nodeBoxes, locks, diagnostics, movedChildIds, flowRanks, rankSpacing, rankStackGap, target, contentWidth) {
|
|
7956
|
+
function moveRankedVerticalLaneChildren(childIds, nodeBoxes, locks, diagnostics, movedChildIds, flowRanks, rankSpacing, rankStackGap, target, contentWidth, suppressSpread) {
|
|
7799
7957
|
for (const [rank, stack] of rankStacks(childIds, nodeBoxes, flowRanks)) {
|
|
7800
7958
|
const unlocked = [];
|
|
7801
7959
|
for (const item of stack) {
|
|
@@ -7824,7 +7982,7 @@ function moveRankedVerticalLaneChildren(childIds, nodeBoxes, locks, diagnostics,
|
|
|
7824
7982
|
}
|
|
7825
7983
|
nodeBoxes.set(childId, next);
|
|
7826
7984
|
} else {
|
|
7827
|
-
const shouldSpread = unlocked.length >= CROSS_AXIS_SPREAD_THRESHOLD;
|
|
7985
|
+
const shouldSpread = !suppressSpread && unlocked.length >= CROSS_AXIS_SPREAD_THRESHOLD;
|
|
7828
7986
|
if (!shouldSpread) {
|
|
7829
7987
|
let yOffset = 0;
|
|
7830
7988
|
for (const { childId, box } of unlocked) {
|
|
@@ -8953,14 +9111,21 @@ function evidenceOverlapDiagnostic(block, conflict) {
|
|
|
8953
9111
|
}
|
|
8954
9112
|
};
|
|
8955
9113
|
}
|
|
8956
|
-
function coordinateEdges(edges, nodes, coordinatedNodes, obstacles, softObstacles, textObstacles, hardObstacles, direction, options, diagnostics, groups) {
|
|
9114
|
+
function coordinateEdges(edges, nodes, coordinatedNodes, obstacles, softObstacles, textObstacles, hardObstacles, direction, options, diagnostics, groups, contentBounds) {
|
|
8957
9115
|
const coordinated = [];
|
|
8958
9116
|
const coordinatedNodeById = new Map(
|
|
8959
9117
|
coordinatedNodes.map((node) => [node.id, node])
|
|
8960
9118
|
);
|
|
9119
|
+
const corridorMarginOption = options.corridorMargin ?? "auto";
|
|
9120
|
+
const corridorMargin = typeof corridorMarginOption === "number" ? corridorMarginOption : Math.max(
|
|
9121
|
+
200,
|
|
9122
|
+
Math.hypot(contentBounds.width, contentBounds.height) * 0.3
|
|
9123
|
+
);
|
|
9124
|
+
const routingGutter = options.routingGutter ?? 160;
|
|
9125
|
+
const queryGutter = (options.routeKind ?? "orthogonal") === "obstacle-avoiding" ? Math.max(routingGutter, corridorMargin) : routingGutter;
|
|
8961
9126
|
const nodeObstacleIndex = createBoxSpatialIndex(
|
|
8962
9127
|
obstacles.map((box, index) => ({ id: `node-obstacle:${index}`, box })),
|
|
8963
|
-
|
|
9128
|
+
queryGutter
|
|
8964
9129
|
);
|
|
8965
9130
|
for (const edge of edges) {
|
|
8966
9131
|
const source = nodes.get(edge.source.nodeId);
|
|
@@ -8982,11 +9147,7 @@ function coordinateEdges(edges, nodes, coordinatedNodes, obstacles, softObstacle
|
|
|
8982
9147
|
const sourcePort = coordinatedNodeById.get(edge.source.nodeId)?.ports?.find((port) => port.id === edge.source.portId);
|
|
8983
9148
|
const targetPort = coordinatedNodeById.get(edge.target.nodeId)?.ports?.find((port) => port.id === edge.target.portId);
|
|
8984
9149
|
const routeTextObstacles = textObstacles.filter((annotation) => !isEdgeConnectedTextAnnotation(edge, annotation)).map((annotation) => annotation.box);
|
|
8985
|
-
const corridor = edgeCorridorBox(
|
|
8986
|
-
source.box,
|
|
8987
|
-
target.box,
|
|
8988
|
-
options.routingGutter ?? 160
|
|
8989
|
-
);
|
|
9150
|
+
const corridor = edgeCorridorBox(source.box, target.box, queryGutter);
|
|
8990
9151
|
const routeNodeObstacles = queryBoxSpatialIndex(nodeObstacleIndex, corridor).map((entry) => entry.box).filter(
|
|
8991
9152
|
(obstacle) => !sameBox(obstacle, source.obstacleBox) && !sameBox(obstacle, target.obstacleBox)
|
|
8992
9153
|
);
|
|
@@ -9004,7 +9165,9 @@ function coordinateEdges(edges, nodes, coordinatedNodes, obstacles, softObstacle
|
|
|
9004
9165
|
...routeTextObstacles
|
|
9005
9166
|
],
|
|
9006
9167
|
hardObstacles,
|
|
9007
|
-
|
|
9168
|
+
corridorMargin,
|
|
9169
|
+
...options.maxRoutingAttempts === void 0 ? {} : { maxRoutingAttempts: options.maxRoutingAttempts },
|
|
9170
|
+
...options.maxBacktrackingRatio === void 0 ? {} : { maxBacktrackingRatio: options.maxBacktrackingRatio }
|
|
9008
9171
|
});
|
|
9009
9172
|
diagnostics.push(
|
|
9010
9173
|
...route.diagnostics.map((diagnostic) => ({
|