@statelyai/layout 0.4.2 → 0.5.0
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/README.md +40 -3
- package/dist/elkjs/index.cjs +2 -2
- package/dist/elkjs/index.d.cts +1 -1
- package/dist/elkjs/index.d.mts +1 -1
- package/dist/elkjs/index.mjs +2 -2
- package/dist/elkjs/main.cjs +1 -1
- package/dist/elkjs/main.mjs +1 -1
- package/dist/elkjs/worker.cjs +2 -2
- package/dist/elkjs/worker.mjs +2 -2
- package/dist/{elkjs-CSi7oB5J.mjs → elkjs-DBkalvt1.mjs} +25 -3
- package/dist/{elkjs-CnBvdyBu.cjs → elkjs-DonMqGjf.cjs} +25 -3
- package/dist/{index-B6cWNrMw.d.cts → index-0YVSvMvA.d.mts} +13 -3
- package/dist/{index-CJQLUKD9.d.mts → index-C0J4ttZe.d.cts} +13 -3
- package/dist/{index-DT6lPMfS.d.cts → index-Xc4R6y3z.d.cts} +9 -2
- package/dist/{index-F1U-fCTu.d.mts → index-lSp0oCJC.d.mts} +9 -2
- package/dist/index.cjs +7 -4
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +4 -4
- package/dist/layered/index.cjs +1 -1
- package/dist/layered/index.d.cts +2 -2
- package/dist/layered/index.d.mts +2 -2
- package/dist/layered/index.mjs +1 -1
- package/dist/{layered-BsAdm_u8.mjs → layered-CmL7oynw.mjs} +245 -69
- package/dist/{layered-BJu8A21s.cjs → layered-SB2mlAqt.cjs} +245 -69
- package/dist/{layout-engine-DnlmGxHL.mjs → layout-engine-BXoIpYL4.mjs} +1 -1
- package/dist/{layout-engine-BFP1TZbF.cjs → layout-engine-CAyJ-I-u.cjs} +1 -1
- package/dist/routing/index.cjs +5 -2
- package/dist/routing/index.d.cts +3 -3
- package/dist/routing/index.d.mts +3 -3
- package/dist/routing/index.mjs +2 -2
- package/dist/routing-D-LfMXOF.mjs +5189 -0
- package/dist/routing-Phxu1R0x.cjs +5423 -0
- package/dist/{types-CT2akdK0.d.mts → types-D8pYSn8I.d.cts} +112 -2
- package/dist/{types-uxPlGRof.d.cts → types-MAUtJfKQ.d.mts} +112 -2
- package/package.json +4 -1
- package/src/authoring/partial.ts +1 -7
- package/src/authoring/routing.ts +64 -19
- package/src/elkjs/index.ts +26 -0
- package/src/layered/feedback-chains.ts +22 -4
- package/src/layered/index.ts +173 -41
- package/src/layered/north-south-ports.ts +17 -4
- package/src/layered/strategies.ts +143 -15
- package/src/routing/algorithms.ts +1436 -148
- package/src/routing/bezier-fit.ts +605 -0
- package/src/routing/bezier-visibility.ts +107 -0
- package/src/routing/bezier.ts +596 -0
- package/src/routing/engine.ts +65 -13
- package/src/routing/index.ts +14 -0
- package/src/routing/model.ts +185 -1
- package/src/routing/path.ts +1 -1
- package/src/routing/policy-geometry.ts +536 -0
- package/src/routing/search.ts +10 -2
- package/src/routing/types.ts +77 -1
- package/dist/routing-CR8flv8b.mjs +0 -2780
- package/dist/routing-QIdGGFBe.cjs +0 -2996
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_routing = require('./routing-
|
|
1
|
+
const require_routing = require('./routing-Phxu1R0x.cjs');
|
|
2
2
|
let _statelyai_graph_layout = require("@statelyai/graph/layout");
|
|
3
3
|
let _statelyai_graph = require("@statelyai/graph");
|
|
4
4
|
|
|
@@ -3719,6 +3719,19 @@ function assertNorthSouthPortSides(graph) {
|
|
|
3719
3719
|
//#region src/layered/strategies.ts
|
|
3720
3720
|
const modelSweepInputs = /* @__PURE__ */ new WeakSet();
|
|
3721
3721
|
const nodeRelativePortRanksByInput = /* @__PURE__ */ new WeakMap();
|
|
3722
|
+
const labelPortSideFeedbackByInput = /* @__PURE__ */ new WeakMap();
|
|
3723
|
+
/**
|
|
3724
|
+
* @internal Collect the feedback segments routed to a center-label dummy's port
|
|
3725
|
+
* sides. Exempt segments keep the plain feedback detour instead.
|
|
3726
|
+
*/
|
|
3727
|
+
function trackLabelPortSideFeedback(input, exempt) {
|
|
3728
|
+
const routed = /* @__PURE__ */ new Set();
|
|
3729
|
+
labelPortSideFeedbackByInput.set(input, {
|
|
3730
|
+
exempt,
|
|
3731
|
+
routed
|
|
3732
|
+
});
|
|
3733
|
+
return routed;
|
|
3734
|
+
}
|
|
3722
3735
|
function getOrientedEndpoints(edge, orientation) {
|
|
3723
3736
|
return orientation.reversedEdgeIds.has(edge.id) ? [edge.targetId, edge.sourceId] : [edge.sourceId, edge.targetId];
|
|
3724
3737
|
}
|
|
@@ -4923,7 +4936,7 @@ const assignLayersWithCoffmanGraham = (input, orientation) => {
|
|
|
4923
4936
|
seedOrder: [...layerMembers].reverse().flat()
|
|
4924
4937
|
};
|
|
4925
4938
|
};
|
|
4926
|
-
function sortLayerByAdjacentPosition(layer, ranksByNodeId, statistic, random, preOrdered = true, sourceUnknownPlacement = true, perturbSummedWeight = true, units, sameLayerNeighbors = /* @__PURE__ */ new Map(), orderedVisits, forcedCompare) {
|
|
4939
|
+
function sortLayerByAdjacentPosition(layer, ranksByNodeId, statistic, random, preOrdered = true, sourceUnknownPlacement = true, perturbSummedWeight = true, units, sameLayerNeighbors = /* @__PURE__ */ new Map(), orderedVisits, forcedCompare, forcedTies) {
|
|
4927
4940
|
const originalIndex = new Map(layer.map((nodeId, index) => [nodeId, index]));
|
|
4928
4941
|
const adjacentPosition = /* @__PURE__ */ new Map();
|
|
4929
4942
|
if (units && statistic === "mean") for (const [id, score] of associatedBarycenters(layer, ranksByNodeId, sameLayerNeighbors, units.associates, random, orderedVisits)) adjacentPosition.set(id, score);
|
|
@@ -4959,6 +4972,7 @@ function sortLayerByAdjacentPosition(layer, ranksByNodeId, statistic, random, pr
|
|
|
4959
4972
|
}
|
|
4960
4973
|
else for (const nodeId of layer) if (adjacentPosition.get(nodeId) === void 0) adjacentPosition.set(nodeId, originalIndex.get(nodeId) ?? 0);
|
|
4961
4974
|
const compare = (a, b) => {
|
|
4975
|
+
if (forcedTies?.has(a) || forcedTies?.has(b)) return 0;
|
|
4962
4976
|
return forcedCompare?.(a, b) || (adjacentPosition.get(a) ?? 0) - (adjacentPosition.get(b) ?? 0) || (originalIndex.get(a) ?? 0) - (originalIndex.get(b) ?? 0);
|
|
4963
4977
|
};
|
|
4964
4978
|
if (forcedCompare) insertionSort(layer, transitiveComparator((id) => id, compare));
|
|
@@ -5110,6 +5124,10 @@ function createLayerSweepSession(input, orientation, assignment, statistic = "me
|
|
|
5110
5124
|
let initialOrderAttempt = usesInitialModelOrder;
|
|
5111
5125
|
const sourceUnknownPlacement = true;
|
|
5112
5126
|
const forcedCompare = usesInitialModelOrder && input.settings["crossingMinimization.forceNodeModelOrder"] === true ? normalModelComparator(input) : void 0;
|
|
5127
|
+
const forcedTies = forcedCompare ? new Set(input.graph.nodes.filter((node) => {
|
|
5128
|
+
const constraint = input.nodeSettings?.(node)?.["layering.layerConstraint"];
|
|
5129
|
+
return constraint === "FIRST_SEPARATE" || constraint === "LAST_SEPARATE";
|
|
5130
|
+
}).map((node) => node.id)) : void 0;
|
|
5113
5131
|
const medianWeights = /* @__PURE__ */ new Map();
|
|
5114
5132
|
const listedEdgeIds = /* @__PURE__ */ new Map();
|
|
5115
5133
|
const listedEdgeId = (edgeId) => {
|
|
@@ -5251,7 +5269,7 @@ function createLayerSweepSession(input, orientation, assignment, statistic = "me
|
|
|
5251
5269
|
const shuffleFirstLayer = (forward) => {
|
|
5252
5270
|
const firstLayerIndex = forward ? 0 : Math.max(0, working.length - 1);
|
|
5253
5271
|
const firstLayerWeights = new Map((working[firstLayerIndex] ?? []).map((id) => [id, random.nextDouble()]));
|
|
5254
|
-
const compare = (left, right) => forcedCompare?.(left, right) || (firstLayerWeights.get(left) ?? 0) - (firstLayerWeights.get(right) ?? 0);
|
|
5272
|
+
const compare = (left, right) => forcedTies?.has(left) || forcedTies?.has(right) ? 0 : forcedCompare?.(left, right) || (firstLayerWeights.get(left) ?? 0) - (firstLayerWeights.get(right) ?? 0);
|
|
5255
5273
|
const first = working[firstLayerIndex];
|
|
5256
5274
|
if (first) if (forcedCompare) insertionSort(first, transitiveComparator((id) => id, compare));
|
|
5257
5275
|
else first.sort(compare);
|
|
@@ -5347,7 +5365,7 @@ function createLayerSweepSession(input, orientation, assignment, statistic = "me
|
|
|
5347
5365
|
if (statistic === "median") sortWithMedianWeights(current, previous);
|
|
5348
5366
|
else {
|
|
5349
5367
|
const adjacent = adjacentRanks(previous, current, true);
|
|
5350
|
-
sortLayerByAdjacentPosition(current, adjacent.ranks, statistic, random, !firstSweep || initialOrderAttempt || canonicalNodes.get(current[0] ?? "")?.type === "EXTERNAL_PORT", sourceUnknownPlacement, true, units, sameLayerNeighbors(isForward), adjacent.visits, forcedCompare);
|
|
5368
|
+
sortLayerByAdjacentPosition(current, adjacent.ranks, statistic, random, !firstSweep || initialOrderAttempt || canonicalNodes.get(current[0] ?? "")?.type === "EXTERNAL_PORT", sourceUnknownPlacement, true, units, sameLayerNeighbors(isForward), adjacent.visits, forcedCompare, forcedTies);
|
|
5351
5369
|
}
|
|
5352
5370
|
groupMixedPortDirections(current, previous, working[layer + 1]);
|
|
5353
5371
|
if (exactPortSweep) distributePorts(layer, true);
|
|
@@ -5361,7 +5379,7 @@ function createLayerSweepSession(input, orientation, assignment, statistic = "me
|
|
|
5361
5379
|
if (statistic === "median") sortWithMedianWeights(current, next);
|
|
5362
5380
|
else {
|
|
5363
5381
|
const adjacent = adjacentRanks(next, current, false);
|
|
5364
|
-
sortLayerByAdjacentPosition(current, adjacent.ranks, statistic, random, !firstSweep || initialOrderAttempt || canonicalNodes.get(current[0] ?? "")?.type === "EXTERNAL_PORT", sourceUnknownPlacement, true, units, sameLayerNeighbors(isForward), adjacent.visits, forcedCompare);
|
|
5382
|
+
sortLayerByAdjacentPosition(current, adjacent.ranks, statistic, random, !firstSweep || initialOrderAttempt || canonicalNodes.get(current[0] ?? "")?.type === "EXTERNAL_PORT", sourceUnknownPlacement, true, units, sameLayerNeighbors(isForward), adjacent.visits, forcedCompare, forcedTies);
|
|
5365
5383
|
}
|
|
5366
5384
|
groupMixedPortDirections(current, next, working[layer - 1]);
|
|
5367
5385
|
if (exactPortSweep) distributePorts(layer, false);
|
|
@@ -7381,6 +7399,17 @@ function routeEdges(style) {
|
|
|
7381
7399
|
};
|
|
7382
7400
|
const start$1 = fixedSideFeedback ? getPortPoint(source, edge.sourcePort, sourceRect, sourceFallback$1, input.direction, input) : sourceFallback$1;
|
|
7383
7401
|
const end$1 = fixedSideFeedback ? getPortPoint(target, edge.targetPort, targetRect, targetFallback$1, input.direction, input) : targetFallback$1;
|
|
7402
|
+
const [forwardSide, backwardSide] = {
|
|
7403
|
+
right: ["EAST", "WEST"],
|
|
7404
|
+
left: ["WEST", "EAST"],
|
|
7405
|
+
down: ["SOUTH", "NORTH"],
|
|
7406
|
+
up: ["NORTH", "SOUTH"]
|
|
7407
|
+
}[input.direction];
|
|
7408
|
+
const labelPortSides = labelPortSideFeedbackByInput.get(input);
|
|
7409
|
+
const faces = (node, side, away) => !fixedSideFeedback && !labelPortSides?.exempt.has(edge.id) && node.id.startsWith("__layout_dummy:label:") && side === away;
|
|
7410
|
+
const sourceFace = faces(source, feedbackSourcePortSide, backwardSide) ? -1 : 1;
|
|
7411
|
+
const targetFace = faces(target, feedbackTargetPortSide, forwardSide) ? -1 : 1;
|
|
7412
|
+
if (sourceFace < 0 || targetFace < 0) labelPortSides?.routed.add(edge.id);
|
|
7384
7413
|
if (horizontal$1) {
|
|
7385
7414
|
const sign = fixedSideFeedback ? Math.sign(sourceRect.x - targetRect.x) || 1 : reverse ? -1 : 1;
|
|
7386
7415
|
const outerCross = Math.max(...[...placement.rectByNodeId.values()].map((rect) => rect.y + rect.height)) + crossSpacing + (fixedSideFeedback ? .5 : 0);
|
|
@@ -7388,11 +7417,11 @@ function routeEdges(style) {
|
|
|
7388
7417
|
pointsByEdgeId.set(edge.id, [
|
|
7389
7418
|
start$1,
|
|
7390
7419
|
{
|
|
7391
|
-
x: start$1.x + sign * flowSpacing,
|
|
7420
|
+
x: start$1.x + sourceFace * sign * flowSpacing,
|
|
7392
7421
|
y: start$1.y
|
|
7393
7422
|
},
|
|
7394
7423
|
{
|
|
7395
|
-
x: start$1.x + sign * flowSpacing,
|
|
7424
|
+
x: start$1.x + sourceFace * sign * flowSpacing,
|
|
7396
7425
|
y: outerCross
|
|
7397
7426
|
},
|
|
7398
7427
|
...preserveCenters ? [{
|
|
@@ -7403,11 +7432,11 @@ function routeEdges(style) {
|
|
|
7403
7432
|
y: outerCross
|
|
7404
7433
|
}] : [],
|
|
7405
7434
|
{
|
|
7406
|
-
x: end$1.x - sign * flowSpacing,
|
|
7435
|
+
x: end$1.x - targetFace * sign * flowSpacing,
|
|
7407
7436
|
y: outerCross
|
|
7408
7437
|
},
|
|
7409
7438
|
{
|
|
7410
|
-
x: end$1.x - sign * flowSpacing,
|
|
7439
|
+
x: end$1.x - targetFace * sign * flowSpacing,
|
|
7411
7440
|
y: end$1.y
|
|
7412
7441
|
},
|
|
7413
7442
|
end$1
|
|
@@ -7420,11 +7449,11 @@ function routeEdges(style) {
|
|
|
7420
7449
|
start$1,
|
|
7421
7450
|
{
|
|
7422
7451
|
x: start$1.x,
|
|
7423
|
-
y: start$1.y + sign * flowSpacing
|
|
7452
|
+
y: start$1.y + sourceFace * sign * flowSpacing
|
|
7424
7453
|
},
|
|
7425
7454
|
{
|
|
7426
7455
|
x: outerCross,
|
|
7427
|
-
y: start$1.y + sign * flowSpacing
|
|
7456
|
+
y: start$1.y + sourceFace * sign * flowSpacing
|
|
7428
7457
|
},
|
|
7429
7458
|
...preserveCenters ? [{
|
|
7430
7459
|
x: outerCross,
|
|
@@ -7435,11 +7464,11 @@ function routeEdges(style) {
|
|
|
7435
7464
|
}] : [],
|
|
7436
7465
|
{
|
|
7437
7466
|
x: outerCross,
|
|
7438
|
-
y: end$1.y - sign * flowSpacing
|
|
7467
|
+
y: end$1.y - targetFace * sign * flowSpacing
|
|
7439
7468
|
},
|
|
7440
7469
|
{
|
|
7441
7470
|
x: end$1.x,
|
|
7442
|
-
y: end$1.y - sign * flowSpacing
|
|
7471
|
+
y: end$1.y - targetFace * sign * flowSpacing
|
|
7443
7472
|
},
|
|
7444
7473
|
end$1
|
|
7445
7474
|
]);
|
|
@@ -7924,6 +7953,55 @@ function routeEdges(style) {
|
|
|
7924
7953
|
const routeEdgesOrthogonally = routeEdges("ORTHOGONAL");
|
|
7925
7954
|
const routeEdgesWithPolylines = routeEdges("POLYLINE");
|
|
7926
7955
|
const routeEdgesWithSplines = routeEdges("SPLINES");
|
|
7956
|
+
const sweptPortRanks = /* @__PURE__ */ new WeakMap();
|
|
7957
|
+
/**
|
|
7958
|
+
* Order movable ports along each physical side as crossing minimization left
|
|
7959
|
+
* them, as ELK places ports from its swept port lists. The lists are
|
|
7960
|
+
* clockwise per canonical side.
|
|
7961
|
+
*/
|
|
7962
|
+
function recordSweptPortOrder(graph, direction, order) {
|
|
7963
|
+
const connected = new Set(graph.edges.flatMap((edge) => [JSON.stringify([edge.sourceId, edge.sourcePort]), JSON.stringify([edge.targetId, edge.targetPort])]));
|
|
7964
|
+
const vertical$1 = direction === "down" || direction === "up";
|
|
7965
|
+
const reverse = direction === "up" || direction === "left";
|
|
7966
|
+
const canonical = direction === "right" ? {
|
|
7967
|
+
NORTH: "NORTH",
|
|
7968
|
+
EAST: "EAST",
|
|
7969
|
+
SOUTH: "SOUTH",
|
|
7970
|
+
WEST: "WEST"
|
|
7971
|
+
} : direction === "left" ? {
|
|
7972
|
+
NORTH: "NORTH",
|
|
7973
|
+
EAST: "WEST",
|
|
7974
|
+
SOUTH: "SOUTH",
|
|
7975
|
+
WEST: "EAST"
|
|
7976
|
+
} : direction === "down" ? {
|
|
7977
|
+
NORTH: "WEST",
|
|
7978
|
+
EAST: "SOUTH",
|
|
7979
|
+
SOUTH: "EAST",
|
|
7980
|
+
WEST: "NORTH"
|
|
7981
|
+
} : {
|
|
7982
|
+
NORTH: "EAST",
|
|
7983
|
+
EAST: "SOUTH",
|
|
7984
|
+
SOUTH: "WEST",
|
|
7985
|
+
WEST: "NORTH"
|
|
7986
|
+
};
|
|
7987
|
+
for (const node of graph.nodes) {
|
|
7988
|
+
if (!node.ports) continue;
|
|
7989
|
+
const swept = order.physicalPortOrderByNodeId?.get(node.id);
|
|
7990
|
+
if (!swept) {
|
|
7991
|
+
sweptPortRanks.delete(node.ports);
|
|
7992
|
+
continue;
|
|
7993
|
+
}
|
|
7994
|
+
const index = new Map(swept.flatMap((id, i) => connected.has(id) ? [[id, i]] : []));
|
|
7995
|
+
const rankByPort = new Map(node.ports.map((port) => [port, index.get(JSON.stringify([node.id, port.name]))]));
|
|
7996
|
+
sweptPortRanks.set(node.ports, (port, side) => {
|
|
7997
|
+
const rank = rankByPort.get(port);
|
|
7998
|
+
if (rank === void 0) return void 0;
|
|
7999
|
+
const alongFlow = (side === "NORTH" || side === "SOUTH") !== vertical$1;
|
|
8000
|
+
const c$1 = canonical[side];
|
|
8001
|
+
return (alongFlow ? (c$1 === "NORTH" ? 1 : -1) * (reverse ? -1 : 1) : c$1 === "EAST" ? 1 : -1) * rank;
|
|
8002
|
+
});
|
|
8003
|
+
}
|
|
8004
|
+
}
|
|
7927
8005
|
function placePorts(ports, rect, direction, portSettings, nodeSettings, portDirection) {
|
|
7928
8006
|
if (!ports) return void 0;
|
|
7929
8007
|
const horizontal$1 = direction === "left" || direction === "right";
|
|
@@ -7950,9 +8028,12 @@ function placePorts(ports, rect, direction, portSettings, nodeSettings, portDire
|
|
|
7950
8028
|
group.push(port);
|
|
7951
8029
|
grouped.set(side, group);
|
|
7952
8030
|
}
|
|
8031
|
+
const swept = constraints === "FIXED_ORDER" || constraints === "FIXED_POS" || constraints === "FIXED_RATIO" ? void 0 : sweptPortRanks.get(ports);
|
|
7953
8032
|
for (const group of grouped.values()) {
|
|
7954
|
-
group.sort((left, right) => Number(portSettings?.(left)?.["port.index"] ?? ports.indexOf(left)) - Number(portSettings?.(right)?.["port.index"] ?? ports.indexOf(right)));
|
|
7955
8033
|
const side = sideByPort.get(group[0]);
|
|
8034
|
+
const ranks = swept && group.map((port) => swept(port, side));
|
|
8035
|
+
const ranked = ranks?.every((rank) => rank !== void 0) && group.every((port) => portSettings?.(port)?.["port.index"] === void 0) ? new Map(group.map((port, i) => [port, ranks[i]])) : void 0;
|
|
8036
|
+
group.sort((left, right) => ranked ? ranked.get(left) - ranked.get(right) : Number(portSettings?.(left)?.["port.index"] ?? ports.indexOf(left)) - Number(portSettings?.(right)?.["port.index"] ?? ports.indexOf(right)));
|
|
7956
8037
|
if (constraints === "FIXED_ORDER" && (side === "SOUTH" || side === "WEST")) group.reverse();
|
|
7957
8038
|
}
|
|
7958
8039
|
return ports.map((port) => {
|
|
@@ -12767,13 +12848,7 @@ function runPartialLayout(input, options, context, arrange, phase = "selection")
|
|
|
12767
12848
|
if (routeAllowed) {
|
|
12768
12849
|
if (options.settings?.edgeRouting === "SPLINES" || options.strategies?.routeEdges) throw new require_routing.UnsupportedLayoutError("Partial layout supports its built-in orthogonal router only");
|
|
12769
12850
|
const ancestorIds = new Set([...ancestors(source.id), ...ancestors(target.id)]);
|
|
12770
|
-
const nodeObstacles = graph.nodes.filter((n) => !ancestorIds.has(n.id))
|
|
12771
|
-
...n,
|
|
12772
|
-
x: n.x - 1,
|
|
12773
|
-
y: n.y - 1,
|
|
12774
|
-
width: n.width + 2,
|
|
12775
|
-
height: n.height + 2
|
|
12776
|
-
});
|
|
12851
|
+
const nodeObstacles = graph.nodes.filter((n) => !ancestorIds.has(n.id));
|
|
12777
12852
|
const labelObstacles = [...edgeById.values()].filter((e) => e.id !== edge.id && e.width > 0 && e.height > 0);
|
|
12778
12853
|
const required = waypoints.filter((c$1) => (c$1.strength ?? "required") === "required");
|
|
12779
12854
|
const accepted = new Set(required.map((c$1) => c$1.id));
|
|
@@ -13803,7 +13878,7 @@ function switchCenterLabelDummies(expansion, labels, order) {
|
|
|
13803
13878
|
//#endregion
|
|
13804
13879
|
//#region src/layered/north-south-ports.ts
|
|
13805
13880
|
/** Detach fixed cross-axis ports into same-layer units before crossing minimization. */
|
|
13806
|
-
function insertNorthSouthPortDummies(expansion) {
|
|
13881
|
+
function insertNorthSouthPortDummies(expansion, sortedPorts) {
|
|
13807
13882
|
const { input, orientation } = expansion;
|
|
13808
13883
|
const vertical$1 = input.direction === "down" || input.direction === "up";
|
|
13809
13884
|
const forward = input.direction === "right" ? "EAST" : input.direction === "left" ? "WEST" : input.direction === "down" ? "SOUTH" : "NORTH";
|
|
@@ -13914,13 +13989,16 @@ function insertNorthSouthPortDummies(expansion) {
|
|
|
13914
13989
|
for (const node of nodes) if (origins.has(node.id)) node.ports?.sort((a, b) => Number(a.name === "output") - Number(b.name === "output"));
|
|
13915
13990
|
const roleOrder = (origin) => origin.input && origin.output ? 2 : origin.input ? 0 : 1;
|
|
13916
13991
|
const negativeFlow = input.direction === "left" || input.direction === "up";
|
|
13992
|
+
const modelOrder = (input.settings["considerModelOrder.strategy"] ?? "NONE") !== "NONE";
|
|
13917
13993
|
const orderedOrigins = input.graph.nodes.flatMap((node) => {
|
|
13918
13994
|
const entries = [...origins].filter(([, origin]) => origin.node.id === node.id);
|
|
13919
13995
|
const constraints = input.nodeSettings?.(node)?.portConstraints;
|
|
13996
|
+
const sorted = sortedPorts?.get(node.id);
|
|
13920
13997
|
const coordinate = (origin) => {
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13998
|
+
const flip = modelOrder && origin.output && !origin.input ? -1 : 1;
|
|
13999
|
+
if (constraints === "FIXED_POS" || constraints === "FIXED_RATIO") return (vertical$1 ? origin.port.y ?? 0 : origin.port.x ?? 0) * (negativeFlow ? -1 : 1) * flip;
|
|
14000
|
+
const index = sorted ? sorted.indexOf(JSON.stringify([node.id, origin.port.name])) : node.ports?.indexOf(origin.port) ?? 0;
|
|
14001
|
+
return (origin.beforeOwner ? index : -index) * flip;
|
|
13924
14002
|
};
|
|
13925
14003
|
return entries.sort(([, a], [, b]) => Number(!a.beforeOwner) - Number(!b.beforeOwner) || roleOrder(a) - roleOrder(b) || coordinate(a) - coordinate(b));
|
|
13926
14004
|
});
|
|
@@ -16235,9 +16313,10 @@ function opposed(a, b) {
|
|
|
16235
16313
|
* A reversed feedback edge split by label or inverted-port dummies is routed
|
|
16236
16314
|
* one segment at a time, so each segment detours to the outer feedback track
|
|
16237
16315
|
* and back to the next dummy. Rejoin the chain as one track: the label's own
|
|
16238
|
-
* track, or the outer track with the label moved onto it, whichever is clear
|
|
16316
|
+
* track, or the outer track with the label moved onto it, whichever is clear;
|
|
16317
|
+
* failing both, a fresh track past everything else with the label on it.
|
|
16239
16318
|
*/
|
|
16240
|
-
function straightenFeedbackChains(chains, pointsByEdgeId, rectByNodeId, horizontal$1) {
|
|
16319
|
+
function straightenFeedbackChains(chains, pointsByEdgeId, rectByNodeId, horizontal$1, spacing) {
|
|
16241
16320
|
const cross = (p) => horizontal$1 ? p.y : p.x;
|
|
16242
16321
|
const flow = (p) => horizontal$1 ? p.x : p.y;
|
|
16243
16322
|
const at = (f, c$1) => horizontal$1 ? {
|
|
@@ -16256,7 +16335,12 @@ function straightenFeedbackChains(chains, pointsByEdgeId, rectByNodeId, horizont
|
|
|
16256
16335
|
const tail = points.at(-2), end = points.at(-1);
|
|
16257
16336
|
const outer = Math.max(...points.map(cross));
|
|
16258
16337
|
const labelRect = label && rectByNodeId.get(label.id);
|
|
16259
|
-
|
|
16338
|
+
const tracks = label ? [label.cross, outer] : [outer];
|
|
16339
|
+
if (labelRect) {
|
|
16340
|
+
const farthest = Math.max(...[...pointsByEdgeId.values()].flatMap((other) => other.map(cross)), ...[...rectByNodeId.values()].map((rect) => horizontal$1 ? rect.y + rect.height : rect.x + rect.width));
|
|
16341
|
+
tracks.push(farthest + spacing + label.cross - (horizontal$1 ? labelRect.y : labelRect.x));
|
|
16342
|
+
}
|
|
16343
|
+
for (const track of tracks) {
|
|
16260
16344
|
const route = [
|
|
16261
16345
|
start,
|
|
16262
16346
|
lead,
|
|
@@ -16285,7 +16369,7 @@ function straightenFeedbackChains(chains, pointsByEdgeId, rectByNodeId, horizont
|
|
|
16285
16369
|
}
|
|
16286
16370
|
if (simple.at(-1) !== end) continue;
|
|
16287
16371
|
if (simple.length >= points.length) break;
|
|
16288
|
-
if ([...pointsByEdgeId].some(([id, other]) => id !== edgeId && opposed(simple, other))) continue;
|
|
16372
|
+
if ([...pointsByEdgeId].some(([id, other]) => id !== edgeId && opposed(simple, other) && !opposed(points, other))) continue;
|
|
16289
16373
|
pointsByEdgeId.set(edgeId, simple);
|
|
16290
16374
|
if (moved) rectByNodeId.set(label.id, moved);
|
|
16291
16375
|
break;
|
|
@@ -18654,53 +18738,100 @@ function runSeparatedComponents(graph, options, context) {
|
|
|
18654
18738
|
bottom: options.padding?.bottom ?? 12,
|
|
18655
18739
|
left: options.padding?.left ?? 12
|
|
18656
18740
|
};
|
|
18741
|
+
const direction = options.direction ?? graph.direction ?? "right";
|
|
18742
|
+
const drawnRects = (result) => {
|
|
18743
|
+
const rects = [];
|
|
18744
|
+
for (const node of result.nodes) {
|
|
18745
|
+
const x$1 = node.x ?? 0, y$1 = node.y ?? 0;
|
|
18746
|
+
rects.push({
|
|
18747
|
+
x: x$1,
|
|
18748
|
+
y: y$1,
|
|
18749
|
+
width: node.width ?? 0,
|
|
18750
|
+
height: node.height ?? 0
|
|
18751
|
+
});
|
|
18752
|
+
for (const port of node.ports ?? []) rects.push({
|
|
18753
|
+
x: x$1 + (port.x ?? 0),
|
|
18754
|
+
y: y$1 + (port.y ?? 0),
|
|
18755
|
+
width: port.width ?? 0,
|
|
18756
|
+
height: port.height ?? 0
|
|
18757
|
+
});
|
|
18758
|
+
}
|
|
18759
|
+
for (const edge of result.edges) {
|
|
18760
|
+
const points = edge.points ?? [];
|
|
18761
|
+
for (let index = 1; index < points.length; index++) {
|
|
18762
|
+
const from = points[index - 1], to = points[index];
|
|
18763
|
+
const x$1 = Math.min(from.x, to.x), y$1 = Math.min(from.y, to.y);
|
|
18764
|
+
rects.push({
|
|
18765
|
+
x: x$1,
|
|
18766
|
+
y: y$1,
|
|
18767
|
+
width: Math.max(from.x, to.x) - x$1,
|
|
18768
|
+
height: Math.max(from.y, to.y) - y$1
|
|
18769
|
+
});
|
|
18770
|
+
}
|
|
18771
|
+
if ((edge.width ?? 0) > 0 || (edge.height ?? 0) > 0) rects.push({
|
|
18772
|
+
x: edge.x ?? 0,
|
|
18773
|
+
y: edge.y ?? 0,
|
|
18774
|
+
width: edge.width ?? 0,
|
|
18775
|
+
height: edge.height ?? 0
|
|
18776
|
+
});
|
|
18777
|
+
}
|
|
18778
|
+
return rects;
|
|
18779
|
+
};
|
|
18780
|
+
const rows = [];
|
|
18657
18781
|
let x = 0;
|
|
18782
|
+
for (const component of components) {
|
|
18783
|
+
if (x > 0 && x + component.bounds.width > maxRowWidth) x = 0;
|
|
18784
|
+
if (x === 0) rows.push([]);
|
|
18785
|
+
rows.at(-1).push({
|
|
18786
|
+
component,
|
|
18787
|
+
x
|
|
18788
|
+
});
|
|
18789
|
+
x += component.bounds.width + componentSpacing;
|
|
18790
|
+
}
|
|
18658
18791
|
let y = 0;
|
|
18659
|
-
let rowHeight = 0;
|
|
18660
18792
|
const compactConnectedComponents = options.settings?.["compaction.connectedComponents"] === true;
|
|
18661
18793
|
const placedShapes = [];
|
|
18662
18794
|
const nodeResults = /* @__PURE__ */ new Map();
|
|
18663
18795
|
const edgeResults = /* @__PURE__ */ new Map();
|
|
18664
18796
|
const placements = [];
|
|
18665
|
-
for (const
|
|
18666
|
-
|
|
18667
|
-
|
|
18668
|
-
|
|
18669
|
-
|
|
18670
|
-
|
|
18671
|
-
|
|
18672
|
-
|
|
18673
|
-
|
|
18674
|
-
|
|
18675
|
-
|
|
18676
|
-
|
|
18677
|
-
|
|
18678
|
-
|
|
18679
|
-
|
|
18680
|
-
|
|
18797
|
+
for (const row of rows) {
|
|
18798
|
+
const rowWidth = Math.max(...row.map((entry) => entry.x + entry.component.bounds.width));
|
|
18799
|
+
let rowHeight = 0;
|
|
18800
|
+
for (const { component, x: packedX } of row) {
|
|
18801
|
+
const { bounds } = component;
|
|
18802
|
+
const left = direction === "left" ? rowWidth - packedX - bounds.width : packedX;
|
|
18803
|
+
const shapes = drawnRects(component.result).map((rect) => ({
|
|
18804
|
+
left: left + rect.x - bounds.left,
|
|
18805
|
+
top: direction === "up" ? bounds.top + bounds.height - rect.y - rect.height : rect.y - bounds.top,
|
|
18806
|
+
width: rect.width,
|
|
18807
|
+
height: rect.height
|
|
18808
|
+
}));
|
|
18809
|
+
let compactedY = y;
|
|
18810
|
+
if (compactConnectedComponents && y > 0) {
|
|
18811
|
+
let requiredY = 0;
|
|
18812
|
+
for (const shape of shapes) for (const placed of placedShapes) {
|
|
18813
|
+
if (shape.left + shape.width <= placed.left || shape.left >= placed.right) continue;
|
|
18814
|
+
requiredY = Math.max(requiredY, placed.bottom + componentSpacing - shape.top);
|
|
18681
18815
|
}
|
|
18816
|
+
compactedY = Math.min(y, requiredY);
|
|
18682
18817
|
}
|
|
18683
|
-
|
|
18818
|
+
for (const shape of shapes) placedShapes.push({
|
|
18819
|
+
left: shape.left,
|
|
18820
|
+
right: shape.left + shape.width,
|
|
18821
|
+
top: compactedY + shape.top,
|
|
18822
|
+
bottom: compactedY + shape.top + shape.height
|
|
18823
|
+
});
|
|
18824
|
+
placements.push({
|
|
18825
|
+
component,
|
|
18826
|
+
x: left,
|
|
18827
|
+
y: compactedY
|
|
18828
|
+
});
|
|
18829
|
+
rowHeight = Math.max(rowHeight, bounds.height);
|
|
18684
18830
|
}
|
|
18685
|
-
|
|
18686
|
-
left: x + (node.x ?? 0) - component.bounds.left,
|
|
18687
|
-
right: x + (node.x ?? 0) - component.bounds.left + (node.width ?? 0),
|
|
18688
|
-
top: compactedY + (node.y ?? 0) - component.bounds.top,
|
|
18689
|
-
bottom: compactedY + (node.y ?? 0) - component.bounds.top + (node.height ?? 0)
|
|
18690
|
-
});
|
|
18691
|
-
placements.push({
|
|
18692
|
-
component,
|
|
18693
|
-
x,
|
|
18694
|
-
y: compactedY
|
|
18695
|
-
});
|
|
18696
|
-
x += component.bounds.width + componentSpacing;
|
|
18697
|
-
rowHeight = Math.max(rowHeight, component.bounds.height);
|
|
18831
|
+
y += rowHeight + componentSpacing;
|
|
18698
18832
|
}
|
|
18699
|
-
const direction = options.direction ?? graph.direction ?? "right";
|
|
18700
|
-
const packedWidth = Math.max(0, ...placements.map((p) => p.x + p.component.bounds.width));
|
|
18701
18833
|
const packedHeight = Math.max(0, ...placements.map((p) => p.y + p.component.bounds.height));
|
|
18702
|
-
for (const { component, x:
|
|
18703
|
-
const left = direction === "left" ? packedWidth - packedX - component.bounds.width : packedX;
|
|
18834
|
+
for (const { component, x: left, y: packedY } of placements) {
|
|
18704
18835
|
const top = direction === "up" ? packedHeight - packedY - component.bounds.height : packedY;
|
|
18705
18836
|
const dx = padding.left + left - component.bounds.left;
|
|
18706
18837
|
const dy = padding.top + top - component.bounds.top;
|
|
@@ -18751,7 +18882,11 @@ function runLayeredPipeline(graph, options, context) {
|
|
|
18751
18882
|
* coordinator can prepare every scope, share sweep state, then resume each
|
|
18752
18883
|
* scope with its final order. The ordinary entry point drains this same pipeline.
|
|
18753
18884
|
*/
|
|
18754
|
-
function* createLayeredScopePipeline(graph, options, context
|
|
18885
|
+
function* createLayeredScopePipeline(graph, options, context, fallbacks = {
|
|
18886
|
+
antiparallelPairs: /* @__PURE__ */ new Set(),
|
|
18887
|
+
feedbackSegments: /* @__PURE__ */ new Set()
|
|
18888
|
+
}) {
|
|
18889
|
+
const scopeOptions = options;
|
|
18755
18890
|
if ((options.settings?.["spacing.edgeEdge"] ?? 10) < 2) options = {
|
|
18756
18891
|
...options,
|
|
18757
18892
|
settings: {
|
|
@@ -18989,7 +19124,7 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
18989
19124
|
}
|
|
18990
19125
|
};
|
|
18991
19126
|
}
|
|
18992
|
-
const northSouth = insertNorthSouthPortDummies(expanded);
|
|
19127
|
+
const northSouth = insertNorthSouthPortDummies(expanded, preparedPorts);
|
|
18993
19128
|
expanded = northSouth.expansion;
|
|
18994
19129
|
if (prepareModelOrder) markInitialModelOrderPrepared(expanded.input, preparedPorts);
|
|
18995
19130
|
const associates = /* @__PURE__ */ new Map(), unitMembers = /* @__PURE__ */ new Map();
|
|
@@ -19051,6 +19186,8 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19051
19186
|
minimize: minimizeScope,
|
|
19052
19187
|
finishOrder: finishCrossingOrder
|
|
19053
19188
|
};
|
|
19189
|
+
const crossingOrder = order;
|
|
19190
|
+
recordSweptPortOrder(graph, direction, order);
|
|
19054
19191
|
traceLayeredPhase(() => ({
|
|
19055
19192
|
kind: "crossing-order",
|
|
19056
19193
|
scope: graph.id,
|
|
@@ -19295,6 +19432,7 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19295
19432
|
const edgeRouting = options.settings?.edgeRouting ?? "ORTHOGONAL";
|
|
19296
19433
|
const edgeRouter = options.strategies?.routeEdges ?? (edgeRouting === "POLYLINE" ? routeEdgesWithPolylines : edgeRouting === "SPLINES" ? routeEdgesWithSplines : routeEdgesOrthogonally);
|
|
19297
19434
|
if (options.strategies?.routeEdges) measure("post-compaction", () => applyPostCompaction(expanded.input, placement));
|
|
19435
|
+
const labelPortSideSegments = trackLabelPortSideFeedback(expanded.input, fallbacks.feedbackSegments);
|
|
19298
19436
|
let expandedRoutes = measure("edge-routing", () => edgeRouter(expanded.input, expanded.orientation, placement));
|
|
19299
19437
|
const restoredJunctionCounts = /* @__PURE__ */ new Map();
|
|
19300
19438
|
expandedRoutes = restoreNorthSouthPortRoutes({
|
|
@@ -19342,6 +19480,7 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19342
19480
|
const outerAntiparallelLabelIds = /* @__PURE__ */ new Set();
|
|
19343
19481
|
const parallelLabelPositions = /* @__PURE__ */ new Map();
|
|
19344
19482
|
const postCompactionNodeCrossDeltas = /* @__PURE__ */ new Map();
|
|
19483
|
+
const flowOrderedPairs = /* @__PURE__ */ new Map();
|
|
19345
19484
|
const horizontalAntiparallelFlow = direction === "left" || direction === "right";
|
|
19346
19485
|
if (options.strategies?.routeEdges === void 0 && options.settings?.["cycleBreaking.strategy"] === "MODEL_ORDER" && options.settings?.["layering.strategy"] === "INTERACTIVE" && options.settings?.["crossingMinimization.forceNodeModelOrder"] === true && options.settings?.["nodePlacement.strategy"] === "BRANDES_KOEPF" && options.settings?.["nodePlacement.favorStraightEdges"] === true && options.settings?.["compaction.postCompaction.strategy"] === "LEFT" && options.settings?.["compaction.postCompaction.constraints"] === "SCANLINE") {
|
|
19347
19486
|
const neighbors = new Map(graph.nodes.map((node) => [node.id, /* @__PURE__ */ new Set()]));
|
|
@@ -19411,6 +19550,7 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19411
19550
|
const horizontal$1 = horizontalAntiparallelFlow;
|
|
19412
19551
|
const nodesById = new Map(graph.nodes.map((node) => [node.id, node]));
|
|
19413
19552
|
const pairEdges = /* @__PURE__ */ new Map();
|
|
19553
|
+
const flowOrder = direction === "left" || direction === "up";
|
|
19414
19554
|
for (const edge of graph.edges) {
|
|
19415
19555
|
if (edge.sourceId === edge.targetId || (edge.width ?? 0) <= 0 || (edge.height ?? 0) <= 0) continue;
|
|
19416
19556
|
const key = [edge.sourceId, edge.targetId].sort().join("\0");
|
|
@@ -19418,7 +19558,7 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19418
19558
|
pair.push(edge);
|
|
19419
19559
|
pairEdges.set(key, pair);
|
|
19420
19560
|
}
|
|
19421
|
-
for (const pair of pairEdges
|
|
19561
|
+
for (const [pairKey, pair] of pairEdges) {
|
|
19422
19562
|
if (pair.length !== 2 || pair[0].sourceId !== pair[1].targetId || pair[0].targetId !== pair[1].sourceId || pair.some((edge) => {
|
|
19423
19563
|
const settings = options.edgeSettings?.(edge);
|
|
19424
19564
|
return (settings?.["edgeLabels.placement"] ?? "CENTER") !== "CENTER" || settings?.["edgeLabels.inline"] !== true;
|
|
@@ -19436,11 +19576,13 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19436
19576
|
};
|
|
19437
19577
|
const hasFlexiblePairPorts = hasFlexiblePorts(firstNode) && hasFlexiblePorts(secondNode);
|
|
19438
19578
|
if (isolatedAntiparallelPair && !hasFlexiblePairPorts) continue;
|
|
19439
|
-
const
|
|
19579
|
+
const pairFlowOrder = flowOrder && !fallbacks.antiparallelPairs.has(pairKey);
|
|
19580
|
+
const firstBeforeSecond = (horizontal$1 ? firstRect.x + firstRect.width / 2 < secondRect.x + secondRect.width / 2 : firstRect.y + firstRect.height / 2 < secondRect.y + secondRect.height / 2) !== pairFlowOrder;
|
|
19440
19581
|
const beforeRect = firstBeforeSecond ? firstRect : secondRect;
|
|
19441
19582
|
const afterRect = firstBeforeSecond ? secondRect : firstRect;
|
|
19442
19583
|
const forward = pair.find((edge) => firstBeforeSecond ? edge.sourceId === pair[0].sourceId : edge.sourceId === pair[0].targetId);
|
|
19443
19584
|
if (!forward?.sourcePort || !forward.targetPort) continue;
|
|
19585
|
+
if (pairFlowOrder) flowOrderedPairs.set(pairKey, [firstNode.id, secondNode.id]);
|
|
19444
19586
|
let cross = Math.min(horizontal$1 ? firstRect.y : firstRect.x, horizontal$1 ? secondRect.y : secondRect.x);
|
|
19445
19587
|
const edgeSpacing = Number(options.settings?.["spacing.edgeEdge"] ?? 10);
|
|
19446
19588
|
for (const edge of pair) {
|
|
@@ -19549,7 +19691,7 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19549
19691
|
cross: horizontal$1 ? anchor.y : anchor.x
|
|
19550
19692
|
}
|
|
19551
19693
|
}];
|
|
19552
|
-
}), routes.pointsByEdgeId, placement.rectByNodeId, horizontal$1);
|
|
19694
|
+
}), routes.pointsByEdgeId, placement.rectByNodeId, horizontal$1, Number(options.settings?.["spacing.edgeEdge"] ?? 10));
|
|
19553
19695
|
}
|
|
19554
19696
|
if (options.settings?.["layering.nodePromotion.strategy"] === "MODEL_ORDER_LEFT_TO_RIGHT") {
|
|
19555
19697
|
const horizontal$1 = direction === "right" || direction === "left";
|
|
@@ -19651,8 +19793,11 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19651
19793
|
}
|
|
19652
19794
|
}
|
|
19653
19795
|
if ((options.settings?.["layerUnzipping.strategy"] ?? "NONE") === "ALTERNATING" && !unzippingFanIn && edgeRouting === "ORTHOGONAL") routes = { pointsByEdgeId: adjustUnzippedSinkRoutes(graph, routes.pointsByEdgeId, direction, Number(options.settings?.["spacing.edgeNodeBetweenLayers"] ?? 10), Number(options.settings?.["spacing.edgeEdgeBetweenLayers"] ?? 10)) };
|
|
19796
|
+
const connectsOnlyTo = (nodeId, otherId) => graph.edges.every((edge) => edge.sourceId === edge.targetId || edge.sourceId !== nodeId && edge.targetId !== nodeId || edge.sourceId === otherId || edge.targetId === otherId);
|
|
19654
19797
|
for (const pair of labeledEdgesByPair.values()) {
|
|
19655
19798
|
if (pair.length < 2) continue;
|
|
19799
|
+
const { sourceId, targetId } = pair[0];
|
|
19800
|
+
if (!connectsOnlyTo(sourceId, targetId) || !connectsOnlyTo(targetId, sourceId)) continue;
|
|
19656
19801
|
const sourceRect = mutableRects.get(pair[0].sourceId);
|
|
19657
19802
|
const targetRect = mutableRects.get(pair[0].targetId);
|
|
19658
19803
|
if (!sourceRect || !targetRect) continue;
|
|
@@ -19950,6 +20095,28 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19950
20095
|
};
|
|
19951
20096
|
}
|
|
19952
20097
|
});
|
|
20098
|
+
if (edgeRouting === "ORTHOGONAL") {
|
|
20099
|
+
const diagonalEdges = edges.filter((edge) => countDiagonals(edge.points) > 0);
|
|
20100
|
+
const antiparallelPairs = [...flowOrderedPairs].flatMap(([key, nodeIds]) => diagonalEdges.some((edge) => nodeIds.includes(edge.sourceId) || nodeIds.includes(edge.targetId)) ? [key] : []);
|
|
20101
|
+
const feedbackSegments = diagonalEdges.flatMap((edge) => {
|
|
20102
|
+
const segments = expanded.segmentIdsByEdgeId.get(edge.id) ?? [edge.id];
|
|
20103
|
+
return segments.some((id) => labelPortSideSegments.has(id)) ? segments : [];
|
|
20104
|
+
});
|
|
20105
|
+
if (antiparallelPairs.length > 0 || feedbackSegments.length > 0) {
|
|
20106
|
+
const retry = createLayeredScopePipeline(graph, scopeOptions, context && {
|
|
20107
|
+
...context,
|
|
20108
|
+
diagnostics: []
|
|
20109
|
+
}, {
|
|
20110
|
+
antiparallelPairs: new Set([...fallbacks.antiparallelPairs, ...antiparallelPairs]),
|
|
20111
|
+
feedbackSegments: new Set([...fallbacks.feedbackSegments, ...feedbackSegments])
|
|
20112
|
+
});
|
|
20113
|
+
const prepared = retry.next();
|
|
20114
|
+
const resumed = prepared.done ? prepared : retry.next(crossingOrder);
|
|
20115
|
+
if (!resumed.done) throw new Error("Layered scope yielded more than one crossing phase");
|
|
20116
|
+
const diagonals = (routed) => routed.reduce((sum, edge) => sum + countDiagonals(edge.points), 0);
|
|
20117
|
+
if (diagonals(resumed.value.edges) < diagonals(edges)) return resumed.value;
|
|
20118
|
+
}
|
|
20119
|
+
}
|
|
19953
20120
|
return setElkjs0111ResultPolicy({
|
|
19954
20121
|
...graph,
|
|
19955
20122
|
direction,
|
|
@@ -19963,6 +20130,15 @@ function* createLayeredScopePipeline(graph, options, context) {
|
|
|
19963
20130
|
junctionPointsByEdgeId: routes.junctionPointsByEdgeId
|
|
19964
20131
|
});
|
|
19965
20132
|
}
|
|
20133
|
+
function countDiagonals(points) {
|
|
20134
|
+
let count = 0;
|
|
20135
|
+
for (let index = 1; index < (points?.length ?? 0); index++) {
|
|
20136
|
+
const a = points[index - 1];
|
|
20137
|
+
const b = points[index];
|
|
20138
|
+
if (Math.abs(a.x - b.x) > 1e-6 && Math.abs(a.y - b.y) > 1e-6) count++;
|
|
20139
|
+
}
|
|
20140
|
+
return count;
|
|
20141
|
+
}
|
|
19966
20142
|
/**
|
|
19967
20143
|
* Deterministic native layered layout for an `@statelyai/graph` graph.
|
|
19968
20144
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { K as placePorts, X as JavaRandom, i as layeredAlgorithm, n as elkjs0111LayeredAlgorithm, x as setElkjs0111ResultPolicy, z as getPolylineMidpoint } from "./layered-
|
|
1
|
+
import { K as placePorts, X as JavaRandom, i as layeredAlgorithm, n as elkjs0111LayeredAlgorithm, x as setElkjs0111ResultPolicy, z as getPolylineMidpoint } from "./layered-CmL7oynw.mjs";
|
|
2
2
|
import { getNodeSize } from "@statelyai/graph/layout";
|
|
3
3
|
|
|
4
4
|
//#region src/fixed.ts
|
package/dist/routing/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_routing = require('../routing-
|
|
1
|
+
const require_routing = require('../routing-Phxu1R0x.cjs');
|
|
2
2
|
|
|
3
3
|
exports.applyRoutePatches = require_routing.applyRoutePatches;
|
|
4
4
|
exports.bezierRouting = require_routing.bezierRouting;
|
|
@@ -23,7 +23,10 @@ exports.roundCorners = require_routing.roundCorners;
|
|
|
23
23
|
exports.routeToGraphPatch = require_routing.routeToGraphPatch;
|
|
24
24
|
exports.routeToPoints = require_routing.routeToPoints;
|
|
25
25
|
exports.routeToPolylines = require_routing.routeToPolylines;
|
|
26
|
+
exports.routingPolicies = require_routing.routingPolicies;
|
|
26
27
|
exports.routingStrategies = require_routing.routingStrategies;
|
|
28
|
+
exports.segmentCrossesRect = require_routing.segmentCrossesRect;
|
|
27
29
|
exports.selfLoopRouting = require_routing.selfLoopRouting;
|
|
28
30
|
exports.straightRouting = require_routing.straightRouting;
|
|
29
|
-
exports.toSvgPath = require_routing.toSvgPath;
|
|
31
|
+
exports.toSvgPath = require_routing.toSvgPath;
|
|
32
|
+
exports.trimBezierPathStart = require_routing.trimBezierPathStart;
|
package/dist/routing/index.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as
|
|
3
|
-
export { EdgeRoutingSettings, FlattenPathOptions, NativeRoutingStrategy, Route, RouteAttachment, RouteBounds, RouteEndpoint, RoutePatch, RoutePath, RoutePoint, RouteSection, RouteSegment, RouteSide, RouteStyle, RoutingDiagnostic, RoutingDiagnosticCode, RoutingGraph, RoutingMetrics, RoutingSettings, RoutingSnapshot, RoutingStrategy, RoutingUpdate, applyRoutePatches, bezierRouting, bundleRouting, busRouting, curvedRouting, fanRouting, flattenPath, getLayoutRoutes, getPathBounds, getPathLength, getPointAtLength, getTangentAtLength, octilinearRouting, organicRouting, orthogonalRouting, parallelRouting, pathFromPoints, pathFromSplinePoints, polylineRouting, roundCorners, routeToGraphPatch, routeToPoints, routeToPolylines, routingStrategies, selfLoopRouting, straightRouting, toSvgPath };
|
|
1
|
+
import { A as BezierGuide, C as RoutingPolicy, D as RoutingTangent, E as RoutingStrategy, O as RoutingUpdate, S as RoutingMetrics, T as RoutingSnapshot, _ as RoutingCurve, a as Route, b as RoutingGraph, c as RouteEndpoint, d as RoutePath, f as RoutePoint, g as RouteStyle, h as RouteSide, i as NativeRoutingStrategy, j as trimBezierPathStart, k as BezierEndpoint, l as RouteLabelPlacement, m as RouteSegment, n as BezierRoutingOptions, o as RouteAttachment, p as RouteSection, r as EdgeRoutingSettings, s as RouteBounds, t as BezierEdgeSettings, u as RoutePatch, v as RoutingDiagnostic, w as RoutingSettings, x as RoutingLabel, y as RoutingDiagnosticCode } from "../types-D8pYSn8I.cjs";
|
|
2
|
+
import { A as applyRoutePatches, C as getPathLength, D as roundCorners, E as pathFromPoints, O as segmentCrossesRect, S as getPathBounds, T as getTangentAtLength, _ as routeToGraphPatch, a as fanRouting, b as FlattenPathOptions, c as orthogonalRouting, d as routingStrategies, f as selfLoopRouting, g as pathFromSplinePoints, h as getLayoutRoutes, i as curvedRouting, k as toSvgPath, l as parallelRouting, m as routingPolicies, n as bundleRouting, o as octilinearRouting, p as straightRouting, r as busRouting, s as organicRouting, t as bezierRouting, u as polylineRouting, v as routeToPoints, w as getPointAtLength, x as flattenPath, y as routeToPolylines } from "../index-C0J4ttZe.cjs";
|
|
3
|
+
export { BezierEdgeSettings, BezierEndpoint, BezierGuide, BezierRoutingOptions, EdgeRoutingSettings, FlattenPathOptions, NativeRoutingStrategy, Route, RouteAttachment, RouteBounds, RouteEndpoint, RouteLabelPlacement, RoutePatch, RoutePath, RoutePoint, RouteSection, RouteSegment, RouteSide, RouteStyle, RoutingCurve, RoutingDiagnostic, RoutingDiagnosticCode, RoutingGraph, RoutingLabel, RoutingMetrics, RoutingPolicy, RoutingSettings, RoutingSnapshot, RoutingStrategy, RoutingTangent, RoutingUpdate, applyRoutePatches, bezierRouting, bundleRouting, busRouting, curvedRouting, fanRouting, flattenPath, getLayoutRoutes, getPathBounds, getPathLength, getPointAtLength, getTangentAtLength, octilinearRouting, organicRouting, orthogonalRouting, parallelRouting, pathFromPoints, pathFromSplinePoints, polylineRouting, roundCorners, routeToGraphPatch, routeToPoints, routeToPolylines, routingPolicies, routingStrategies, segmentCrossesRect, selfLoopRouting, straightRouting, toSvgPath, trimBezierPathStart };
|
package/dist/routing/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as
|
|
3
|
-
export { EdgeRoutingSettings, FlattenPathOptions, NativeRoutingStrategy, Route, RouteAttachment, RouteBounds, RouteEndpoint, RoutePatch, RoutePath, RoutePoint, RouteSection, RouteSegment, RouteSide, RouteStyle, RoutingDiagnostic, RoutingDiagnosticCode, RoutingGraph, RoutingMetrics, RoutingSettings, RoutingSnapshot, RoutingStrategy, RoutingUpdate, applyRoutePatches, bezierRouting, bundleRouting, busRouting, curvedRouting, fanRouting, flattenPath, getLayoutRoutes, getPathBounds, getPathLength, getPointAtLength, getTangentAtLength, octilinearRouting, organicRouting, orthogonalRouting, parallelRouting, pathFromPoints, pathFromSplinePoints, polylineRouting, roundCorners, routeToGraphPatch, routeToPoints, routeToPolylines, routingStrategies, selfLoopRouting, straightRouting, toSvgPath };
|
|
1
|
+
import { A as BezierGuide, C as RoutingPolicy, D as RoutingTangent, E as RoutingStrategy, O as RoutingUpdate, S as RoutingMetrics, T as RoutingSnapshot, _ as RoutingCurve, a as Route, b as RoutingGraph, c as RouteEndpoint, d as RoutePath, f as RoutePoint, g as RouteStyle, h as RouteSide, i as NativeRoutingStrategy, j as trimBezierPathStart, k as BezierEndpoint, l as RouteLabelPlacement, m as RouteSegment, n as BezierRoutingOptions, o as RouteAttachment, p as RouteSection, r as EdgeRoutingSettings, s as RouteBounds, t as BezierEdgeSettings, u as RoutePatch, v as RoutingDiagnostic, w as RoutingSettings, x as RoutingLabel, y as RoutingDiagnosticCode } from "../types-MAUtJfKQ.mjs";
|
|
2
|
+
import { A as applyRoutePatches, C as getPathLength, D as roundCorners, E as pathFromPoints, O as segmentCrossesRect, S as getPathBounds, T as getTangentAtLength, _ as routeToGraphPatch, a as fanRouting, b as FlattenPathOptions, c as orthogonalRouting, d as routingStrategies, f as selfLoopRouting, g as pathFromSplinePoints, h as getLayoutRoutes, i as curvedRouting, k as toSvgPath, l as parallelRouting, m as routingPolicies, n as bundleRouting, o as octilinearRouting, p as straightRouting, r as busRouting, s as organicRouting, t as bezierRouting, u as polylineRouting, v as routeToPoints, w as getPointAtLength, x as flattenPath, y as routeToPolylines } from "../index-0YVSvMvA.mjs";
|
|
3
|
+
export { BezierEdgeSettings, BezierEndpoint, BezierGuide, BezierRoutingOptions, EdgeRoutingSettings, FlattenPathOptions, NativeRoutingStrategy, Route, RouteAttachment, RouteBounds, RouteEndpoint, RouteLabelPlacement, RoutePatch, RoutePath, RoutePoint, RouteSection, RouteSegment, RouteSide, RouteStyle, RoutingCurve, RoutingDiagnostic, RoutingDiagnosticCode, RoutingGraph, RoutingLabel, RoutingMetrics, RoutingPolicy, RoutingSettings, RoutingSnapshot, RoutingStrategy, RoutingTangent, RoutingUpdate, applyRoutePatches, bezierRouting, bundleRouting, busRouting, curvedRouting, fanRouting, flattenPath, getLayoutRoutes, getPathBounds, getPathLength, getPointAtLength, getTangentAtLength, octilinearRouting, organicRouting, orthogonalRouting, parallelRouting, pathFromPoints, pathFromSplinePoints, polylineRouting, roundCorners, routeToGraphPatch, routeToPoints, routeToPolylines, routingPolicies, routingStrategies, segmentCrossesRect, selfLoopRouting, straightRouting, toSvgPath, trimBezierPathStart };
|