@statelyai/layout 0.5.0 → 0.5.1
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/elkjs/index.cjs +2 -2
- 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-DonMqGjf.cjs → elkjs-Bh_E59N_.cjs} +2 -2
- package/dist/{elkjs-DBkalvt1.mjs → elkjs-Dk9yOk9U.mjs} +2 -2
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/layered/index.cjs +1 -1
- package/dist/layered/index.mjs +1 -1
- package/dist/{layered-CmL7oynw.mjs → layered-CUwft7on.mjs} +243 -22
- package/dist/{layered-SB2mlAqt.cjs → layered-QzYtokgN.cjs} +243 -22
- package/dist/{layout-engine-CAyJ-I-u.cjs → layout-engine-CQ5FcBPC.cjs} +1 -1
- package/dist/{layout-engine-BXoIpYL4.mjs → layout-engine-DvDkMQM3.mjs} +1 -1
- package/package.json +1 -1
- package/src/layered/index.ts +13 -1
- package/src/layered/loop-envelopes.ts +96 -26
- package/src/layered/self-loop-ports.ts +158 -0
- package/src/layered/strategies.ts +40 -17
package/dist/elkjs/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
-
require('../layered-
|
|
3
|
-
const require_elkjs = require('../elkjs-
|
|
2
|
+
require('../layered-QzYtokgN.cjs');
|
|
3
|
+
const require_elkjs = require('../elkjs-Bh_E59N_.cjs');
|
|
4
4
|
|
|
5
5
|
exports.compileStatechartLayout = require_elkjs.compileStatechartLayout;
|
|
6
6
|
exports.default = require_elkjs.ELK;
|
package/dist/elkjs/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../layered-
|
|
2
|
-
import { a as scoreStatechartLayout, i as layoutStatechart, n as getElkRoutes, r as compileStatechartLayout, t as ELK } from "../elkjs-
|
|
1
|
+
import "../layered-CUwft7on.mjs";
|
|
2
|
+
import { a as scoreStatechartLayout, i as layoutStatechart, n as getElkRoutes, r as compileStatechartLayout, t as ELK } from "../elkjs-Dk9yOk9U.mjs";
|
|
3
3
|
|
|
4
4
|
export { compileStatechartLayout, ELK as default, getElkRoutes, layoutStatechart, scoreStatechartLayout };
|
package/dist/elkjs/main.cjs
CHANGED
package/dist/elkjs/main.mjs
CHANGED
package/dist/elkjs/worker.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
require('../layered-
|
|
2
|
-
const require_elkjs = require('../elkjs-
|
|
1
|
+
require('../layered-QzYtokgN.cjs');
|
|
2
|
+
const require_elkjs = require('../elkjs-Bh_E59N_.cjs');
|
|
3
3
|
|
|
4
4
|
//#region src/elkjs/worker.ts
|
|
5
5
|
/*******************************************************************************
|
package/dist/elkjs/worker.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "../layered-
|
|
2
|
-
import { t as ELK } from "../elkjs-
|
|
1
|
+
import "../layered-CUwft7on.mjs";
|
|
2
|
+
import { t as ELK } from "../elkjs-Dk9yOk9U.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/elkjs/worker.ts
|
|
5
5
|
/*******************************************************************************
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_routing = require('./routing-Phxu1R0x.cjs');
|
|
2
|
-
const require_layered = require('./layered-
|
|
3
|
-
const require_layout_engine = require('./layout-engine-
|
|
2
|
+
const require_layered = require('./layered-QzYtokgN.cjs');
|
|
3
|
+
const require_layout_engine = require('./layout-engine-CQ5FcBPC.cjs');
|
|
4
4
|
let _statelyai_graph = require("@statelyai/graph");
|
|
5
5
|
|
|
6
6
|
//#region src/layered/hierarchy-sweepiness.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { E as pathFromPoints, N as freeze, _ as pathFromSplinePoints } from "./routing-D-LfMXOF.mjs";
|
|
2
|
-
import { $ as attachExternalPortDummy, R as createLayerSweepSession, S as CROSSING_MODEL, Z as minimizeHierarchyCrossings, b as elkjs0111ResultPolicy, c as elkLayeredOptionDefinitions, et as createExternalPortDummy, h as separateOpposingTracks, nt as createOrthogonalHypersegments, t as createLayeredScopePipeline, tt as externalPortDummyOf, v as isPerpendicularPortRestored, y as hierarchicalPortSides } from "./layered-
|
|
3
|
-
import { n as executeElkjs0111Layout } from "./layout-engine-
|
|
2
|
+
import { $ as attachExternalPortDummy, R as createLayerSweepSession, S as CROSSING_MODEL, Z as minimizeHierarchyCrossings, b as elkjs0111ResultPolicy, c as elkLayeredOptionDefinitions, et as createExternalPortDummy, h as separateOpposingTracks, nt as createOrthogonalHypersegments, t as createLayeredScopePipeline, tt as externalPortDummyOf, v as isPerpendicularPortRestored, y as hierarchicalPortSides } from "./layered-CUwft7on.mjs";
|
|
3
|
+
import { n as executeElkjs0111Layout } from "./layout-engine-DvDkMQM3.mjs";
|
|
4
4
|
import { createGraph } from "@statelyai/graph";
|
|
5
5
|
|
|
6
6
|
//#region src/layered/hierarchy-sweepiness.ts
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_routing = require('./routing-Phxu1R0x.cjs');
|
|
2
|
-
const require_layered = require('./layered-
|
|
3
|
-
const require_layout_engine = require('./layout-engine-
|
|
2
|
+
const require_layered = require('./layered-QzYtokgN.cjs');
|
|
3
|
+
const require_layout_engine = require('./layout-engine-CQ5FcBPC.cjs');
|
|
4
4
|
let _statelyai_graph = require("@statelyai/graph");
|
|
5
5
|
|
|
6
6
|
//#region src/layout.ts
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { C as getPathLength, D as roundCorners, E as pathFromPoints, O as segmentCrossesRect, P as routingPolicies, R as LayoutError, S as getPathBounds, T as getTangentAtLength, _ as pathFromSplinePoints, a as fanRouting, b as routeToPolylines, c as orthogonalRouting, d as routingStrategies, f as selfLoopRouting, g as getLayoutRoutes, h as trimBezierPathStart, i as curvedRouting, k as toSvgPath, l as parallelRouting, m as applyRoutePatches, n as bundleRouting, o as octilinearRouting, p as straightRouting, r as busRouting, s as organicRouting, t as bezierRouting, u as polylineRouting, v as routeToGraphPatch, w as getPointAtLength, x as flattenPath, y as routeToPoints, z as UnsupportedLayoutError } from "./routing-D-LfMXOF.mjs";
|
|
2
|
-
import { A as breakCyclesByStronglyConnectedConnectivity, B as minimizeCrossingsInteractively, C as assignLayersByBreadthFirstModelOrder, D as assignLayersInteractively, E as assignLayersByLongestPathToSink, F as breakCyclesWithDepthFirstSearch, G as placeNodesInteractively, H as minimizeCrossingsWithMedian, I as breakCyclesWithModelOrderBreadthFirstSearch, J as routeEdgesWithPolylines, L as breakCyclesWithModelOrderDepthFirstSearch, M as breakCyclesGreedily, N as breakCyclesGreedilyByModelOrder, O as assignLayersWithCoffmanGraham, P as breakCyclesInteractively, Q as assignLayersWithNetworkSimplex, T as assignLayersByLongestPath, U as minimizeCrossingsWithModelOrder, V as minimizeCrossingsWithBarycenter, W as placeNodesInLayers, Y as routeEdgesWithSplines, _ as statechartHints, a as fromElkLayeredOptionId, c as elkLayeredOptionDefinitions, f as assignLayersWithStretchWidth, g as hint, i as layeredAlgorithm, j as breakCyclesByStronglyConnectedNodeType, k as breakCyclesByModelOrder, m as c, o as toElkLayeredOptions, p as assignLayersWithMinWidth, q as routeEdgesOrthogonally, r as getLayeredLayout, s as elkLayeredEnumValues, w as assignLayersByDepthFirstModelOrder } from "./layered-
|
|
3
|
-
import { a as getSporeCompactionLayout, c as sporeOverlapRemovalAlgorithm, d as getRectanglePackingLayout, f as rectanglePackingAlgorithm, g as getFixedLayout, h as fixedAlgorithm, i as getBuiltInLayoutAlgorithm, l as getRandomLayout, m as getBoxLayout, o as getSporeOverlapRemovalLayout, p as boxAlgorithm, r as executeLayoutAlgorithm, s as sporeCompactionAlgorithm, t as builtInLayoutAlgorithms, u as randomAlgorithm } from "./layout-engine-
|
|
2
|
+
import { A as breakCyclesByStronglyConnectedConnectivity, B as minimizeCrossingsInteractively, C as assignLayersByBreadthFirstModelOrder, D as assignLayersInteractively, E as assignLayersByLongestPathToSink, F as breakCyclesWithDepthFirstSearch, G as placeNodesInteractively, H as minimizeCrossingsWithMedian, I as breakCyclesWithModelOrderBreadthFirstSearch, J as routeEdgesWithPolylines, L as breakCyclesWithModelOrderDepthFirstSearch, M as breakCyclesGreedily, N as breakCyclesGreedilyByModelOrder, O as assignLayersWithCoffmanGraham, P as breakCyclesInteractively, Q as assignLayersWithNetworkSimplex, T as assignLayersByLongestPath, U as minimizeCrossingsWithModelOrder, V as minimizeCrossingsWithBarycenter, W as placeNodesInLayers, Y as routeEdgesWithSplines, _ as statechartHints, a as fromElkLayeredOptionId, c as elkLayeredOptionDefinitions, f as assignLayersWithStretchWidth, g as hint, i as layeredAlgorithm, j as breakCyclesByStronglyConnectedNodeType, k as breakCyclesByModelOrder, m as c, o as toElkLayeredOptions, p as assignLayersWithMinWidth, q as routeEdgesOrthogonally, r as getLayeredLayout, s as elkLayeredEnumValues, w as assignLayersByDepthFirstModelOrder } from "./layered-CUwft7on.mjs";
|
|
3
|
+
import { a as getSporeCompactionLayout, c as sporeOverlapRemovalAlgorithm, d as getRectanglePackingLayout, f as rectanglePackingAlgorithm, g as getFixedLayout, h as fixedAlgorithm, i as getBuiltInLayoutAlgorithm, l as getRandomLayout, m as getBoxLayout, o as getSporeOverlapRemovalLayout, p as boxAlgorithm, r as executeLayoutAlgorithm, s as sporeCompactionAlgorithm, t as builtInLayoutAlgorithms, u as randomAlgorithm } from "./layout-engine-DvDkMQM3.mjs";
|
|
4
4
|
import { getGraphIssues } from "@statelyai/graph";
|
|
5
5
|
|
|
6
6
|
//#region src/layout.ts
|
package/dist/layered/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_layered = require('../layered-
|
|
1
|
+
const require_layered = require('../layered-QzYtokgN.cjs');
|
|
2
2
|
|
|
3
3
|
exports.assignLayersByBreadthFirstModelOrder = require_layered.assignLayersByBreadthFirstModelOrder;
|
|
4
4
|
exports.assignLayersByDepthFirstModelOrder = require_layered.assignLayersByDepthFirstModelOrder;
|
package/dist/layered/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as breakCyclesByStronglyConnectedConnectivity, B as minimizeCrossingsInteractively, C as assignLayersByBreadthFirstModelOrder, D as assignLayersInteractively, E as assignLayersByLongestPathToSink, F as breakCyclesWithDepthFirstSearch, G as placeNodesInteractively, H as minimizeCrossingsWithMedian, I as breakCyclesWithModelOrderBreadthFirstSearch, J as routeEdgesWithPolylines, L as breakCyclesWithModelOrderDepthFirstSearch, M as breakCyclesGreedily, N as breakCyclesGreedilyByModelOrder, O as assignLayersWithCoffmanGraham, P as breakCyclesInteractively, Q as assignLayersWithNetworkSimplex, T as assignLayersByLongestPath, U as minimizeCrossingsWithModelOrder, V as minimizeCrossingsWithBarycenter, W as placeNodesInLayers, Y as routeEdgesWithSplines, a as fromElkLayeredOptionId, c as elkLayeredOptionDefinitions, d as placeNodesWithBrandesKoepf, f as assignLayersWithStretchWidth, i as layeredAlgorithm, j as breakCyclesByStronglyConnectedNodeType, k as breakCyclesByModelOrder, l as placeNodesWithNetworkSimplex, n as elkjs0111LayeredAlgorithm, o as toElkLayeredOptions, p as assignLayersWithMinWidth, q as routeEdgesOrthogonally, r as getLayeredLayout, s as elkLayeredEnumValues, t as createLayeredScopePipeline, u as placeNodesWithLinearSegments, w as assignLayersByDepthFirstModelOrder } from "../layered-
|
|
1
|
+
import { A as breakCyclesByStronglyConnectedConnectivity, B as minimizeCrossingsInteractively, C as assignLayersByBreadthFirstModelOrder, D as assignLayersInteractively, E as assignLayersByLongestPathToSink, F as breakCyclesWithDepthFirstSearch, G as placeNodesInteractively, H as minimizeCrossingsWithMedian, I as breakCyclesWithModelOrderBreadthFirstSearch, J as routeEdgesWithPolylines, L as breakCyclesWithModelOrderDepthFirstSearch, M as breakCyclesGreedily, N as breakCyclesGreedilyByModelOrder, O as assignLayersWithCoffmanGraham, P as breakCyclesInteractively, Q as assignLayersWithNetworkSimplex, T as assignLayersByLongestPath, U as minimizeCrossingsWithModelOrder, V as minimizeCrossingsWithBarycenter, W as placeNodesInLayers, Y as routeEdgesWithSplines, a as fromElkLayeredOptionId, c as elkLayeredOptionDefinitions, d as placeNodesWithBrandesKoepf, f as assignLayersWithStretchWidth, i as layeredAlgorithm, j as breakCyclesByStronglyConnectedNodeType, k as breakCyclesByModelOrder, l as placeNodesWithNetworkSimplex, n as elkjs0111LayeredAlgorithm, o as toElkLayeredOptions, p as assignLayersWithMinWidth, q as routeEdgesOrthogonally, r as getLayeredLayout, s as elkLayeredEnumValues, t as createLayeredScopePipeline, u as placeNodesWithLinearSegments, w as assignLayersByDepthFirstModelOrder } from "../layered-CUwft7on.mjs";
|
|
2
2
|
|
|
3
3
|
export { assignLayersByBreadthFirstModelOrder, assignLayersByDepthFirstModelOrder, assignLayersByLongestPath, assignLayersByLongestPathToSink, assignLayersInteractively, assignLayersWithCoffmanGraham, assignLayersWithMinWidth, assignLayersWithNetworkSimplex, assignLayersWithStretchWidth, breakCyclesByModelOrder, breakCyclesByStronglyConnectedConnectivity, breakCyclesByStronglyConnectedNodeType, breakCyclesGreedily, breakCyclesGreedilyByModelOrder, breakCyclesInteractively, breakCyclesWithDepthFirstSearch, breakCyclesWithModelOrderBreadthFirstSearch, breakCyclesWithModelOrderDepthFirstSearch, createLayeredScopePipeline, elkLayeredEnumValues, elkLayeredOptionDefinitions, elkjs0111LayeredAlgorithm, fromElkLayeredOptionId, getLayeredLayout, layeredAlgorithm, minimizeCrossingsInteractively, minimizeCrossingsWithBarycenter, minimizeCrossingsWithMedian, minimizeCrossingsWithModelOrder, placeNodesInLayers, placeNodesInteractively, placeNodesWithBrandesKoepf, placeNodesWithLinearSegments, placeNodesWithNetworkSimplex, routeEdgesOrthogonally, routeEdgesWithPolylines, routeEdgesWithSplines, toElkLayeredOptions };
|
|
@@ -1608,8 +1608,174 @@ function findNode(nodes, id) {
|
|
|
1608
1608
|
return position !== void 0 && nodes[position]?.id === id ? nodes[position] : nodes.find((node) => node.id === id);
|
|
1609
1609
|
}
|
|
1610
1610
|
|
|
1611
|
+
//#endregion
|
|
1612
|
+
//#region src/layered/self-loop-ports.ts
|
|
1613
|
+
const hiddenBySettings = /* @__PURE__ */ new WeakMap();
|
|
1614
|
+
/** Sizes of the ports SelfLoopPreProcessor hid from a loop, if any. */
|
|
1615
|
+
function hiddenLoopPorts(settings, edgeId) {
|
|
1616
|
+
return hiddenBySettings.get(settings)?.get(edgeId);
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* ELK's SelfLoopPreProcessor removes ports that carry only self loops from
|
|
1620
|
+
* nodes whose port order is not fixed, and SelfLoopPortRestorer later puts
|
|
1621
|
+
* them on the loop's side. The layered phases then see implicit loop ports;
|
|
1622
|
+
* {@link restoreSelfLoopPorts} places the hidden ports at the loop ends.
|
|
1623
|
+
*/
|
|
1624
|
+
function hideSelfLoopPorts(graph, options) {
|
|
1625
|
+
const uses = /* @__PURE__ */ new Map();
|
|
1626
|
+
const nonLoop = /* @__PURE__ */ new Set();
|
|
1627
|
+
for (const edge of graph.edges) for (const [node, port] of [[edge.sourceId, edge.sourcePort], [edge.targetId, edge.targetPort]]) {
|
|
1628
|
+
if (port === void 0) continue;
|
|
1629
|
+
const key = `${node}\0${port}`;
|
|
1630
|
+
uses.set(key, (uses.get(key) ?? 0) + 1);
|
|
1631
|
+
if (edge.sourceId !== edge.targetId) nonLoop.add(key);
|
|
1632
|
+
}
|
|
1633
|
+
const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
|
|
1634
|
+
const hidden = /* @__PURE__ */ new Map();
|
|
1635
|
+
const edges = /* @__PURE__ */ new Map();
|
|
1636
|
+
const hiddenPorts = /* @__PURE__ */ new Set();
|
|
1637
|
+
for (const edge of graph.edges) {
|
|
1638
|
+
if (edge.sourceId !== edge.targetId || edge.sourcePort === void 0 || edge.targetPort === void 0 || edge.sourcePort === edge.targetPort) continue;
|
|
1639
|
+
const node = nodeById.get(edge.sourceId);
|
|
1640
|
+
const constraints = node && options.nodeSettings?.(node)?.portConstraints;
|
|
1641
|
+
if (!node || constraints !== void 0 && constraints !== "FREE" && constraints !== "UNDEFINED") continue;
|
|
1642
|
+
const ports = [edge.sourcePort, edge.targetPort].map((name) => node.ports?.find((port) => port.name === name));
|
|
1643
|
+
if (ports.some((port) => !port || uses.get(`${node.id}\0${port.name}`) !== 1 || nonLoop.has(`${node.id}\0${port.name}`))) continue;
|
|
1644
|
+
const size$1 = (port) => ({
|
|
1645
|
+
width: port.width ?? 0,
|
|
1646
|
+
height: port.height ?? 0
|
|
1647
|
+
});
|
|
1648
|
+
hidden.set(edge.id, {
|
|
1649
|
+
source: size$1(ports[0]),
|
|
1650
|
+
target: size$1(ports[1])
|
|
1651
|
+
});
|
|
1652
|
+
edges.set(edge.id, edge);
|
|
1653
|
+
for (const port of ports) hiddenPorts.add(`${node.id}\0${port.name}`);
|
|
1654
|
+
}
|
|
1655
|
+
if (hidden.size === 0) return void 0;
|
|
1656
|
+
const settings = { ...options.settings };
|
|
1657
|
+
hiddenBySettings.set(settings, hidden);
|
|
1658
|
+
return {
|
|
1659
|
+
graph: {
|
|
1660
|
+
...graph,
|
|
1661
|
+
nodes: graph.nodes.map((node) => node.ports?.some((port) => hiddenPorts.has(`${node.id}\0${port.name}`)) ? {
|
|
1662
|
+
...node,
|
|
1663
|
+
ports: node.ports.filter((port) => !hiddenPorts.has(`${node.id}\0${port.name}`))
|
|
1664
|
+
} : node),
|
|
1665
|
+
edges: graph.edges.map((edge) => hidden.has(edge.id) ? {
|
|
1666
|
+
...edge,
|
|
1667
|
+
sourcePort: void 0,
|
|
1668
|
+
targetPort: void 0
|
|
1669
|
+
} : edge)
|
|
1670
|
+
},
|
|
1671
|
+
options: {
|
|
1672
|
+
...options,
|
|
1673
|
+
settings
|
|
1674
|
+
},
|
|
1675
|
+
edges
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
/** Put hidden loop ports back, anchored on the side their loop leaves from. */
|
|
1679
|
+
function restoreSelfLoopPorts(graph, result, edges) {
|
|
1680
|
+
const anchors = /* @__PURE__ */ new Map();
|
|
1681
|
+
for (const edge of result.edges) {
|
|
1682
|
+
const original = edges.get(edge.id);
|
|
1683
|
+
const points = edge.points;
|
|
1684
|
+
if (!original || !points?.length) continue;
|
|
1685
|
+
anchors.set(`${edge.sourceId}\0${original.sourcePort}`, points[0]);
|
|
1686
|
+
anchors.set(`${edge.targetId}\0${original.targetPort}`, points.at(-1));
|
|
1687
|
+
}
|
|
1688
|
+
const originalById = new Map(graph.nodes.map((node) => [node.id, node]));
|
|
1689
|
+
return {
|
|
1690
|
+
...result,
|
|
1691
|
+
nodes: result.nodes.map((node) => {
|
|
1692
|
+
const original = originalById.get(node.id)?.ports;
|
|
1693
|
+
if (!original?.some((port) => anchors.has(`${node.id}\0${port.name}`))) return node;
|
|
1694
|
+
const placed = new Map(node.ports?.map((port) => [port.name, port]));
|
|
1695
|
+
return {
|
|
1696
|
+
...node,
|
|
1697
|
+
ports: original.map((port) => {
|
|
1698
|
+
const anchor = anchors.get(`${node.id}\0${port.name}`);
|
|
1699
|
+
const width = port.width ?? 0, height = port.height ?? 0;
|
|
1700
|
+
if (!anchor) return placed.get(port.name) ?? {
|
|
1701
|
+
...port,
|
|
1702
|
+
width,
|
|
1703
|
+
height,
|
|
1704
|
+
x: 0,
|
|
1705
|
+
y: 0
|
|
1706
|
+
};
|
|
1707
|
+
const x = anchor.x - node.x, y = anchor.y - node.y;
|
|
1708
|
+
return {
|
|
1709
|
+
...port,
|
|
1710
|
+
width,
|
|
1711
|
+
height,
|
|
1712
|
+
x: x <= 0 ? x : x >= node.width ? x - width : x - width / 2,
|
|
1713
|
+
y: x <= 0 || x >= node.width ? y - height / 2 : y <= 0 ? y : y - height
|
|
1714
|
+
};
|
|
1715
|
+
})
|
|
1716
|
+
};
|
|
1717
|
+
}),
|
|
1718
|
+
edges: result.edges.map((edge) => {
|
|
1719
|
+
const original = edges.get(edge.id);
|
|
1720
|
+
return original ? {
|
|
1721
|
+
...edge,
|
|
1722
|
+
sourcePort: original.sourcePort,
|
|
1723
|
+
targetPort: original.targetPort
|
|
1724
|
+
} : edge;
|
|
1725
|
+
})
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1611
1729
|
//#endregion
|
|
1612
1730
|
//#region src/layered/loop-envelopes.ts
|
|
1731
|
+
const crossSide = (side) => side === "NORTH" || side === "SOUTH";
|
|
1732
|
+
/**
|
|
1733
|
+
* Extents of a movable loop's hidden ports in the canonical rightward frame:
|
|
1734
|
+
* along its side, and protruding from it.
|
|
1735
|
+
*/
|
|
1736
|
+
function loopPortExtents(input, edge, side) {
|
|
1737
|
+
const ports = hiddenLoopPorts(input.settings, edge.id);
|
|
1738
|
+
const horizontal$1 = input.direction === "right" || input.direction === "left";
|
|
1739
|
+
const along = crossSide(side) === horizontal$1 ? "width" : "height";
|
|
1740
|
+
const normal = along === "width" ? "height" : "width";
|
|
1741
|
+
return {
|
|
1742
|
+
along: ports ? ports.source[along] + ports.target[along] : 0,
|
|
1743
|
+
normal: ports ? Math.max(ports.source[normal], ports.target[normal]) : 0
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
/** A movable loop's label extent away from its side, in the canonical frame. */
|
|
1747
|
+
function movableLoopLabelExtent(input, edge, side) {
|
|
1748
|
+
const horizontal$1 = input.direction === "right" || input.direction === "left";
|
|
1749
|
+
const size$1 = (crossSide(side) === horizontal$1 ? edge.height : edge.width) ?? 0;
|
|
1750
|
+
return size$1 > 0 ? size$1 + Number(input.settings["spacing.edgeLabel"] ?? 2) : 0;
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* ELK's OrthogonalSelfLoopRouter routing slot of a movable loop, measured
|
|
1754
|
+
* from its node side in the canonical frame: past the protruding ports and
|
|
1755
|
+
* the self-loop spacing, then one edge spacing plus any label per inner slot.
|
|
1756
|
+
*/
|
|
1757
|
+
function movableLoopTrack(input, sideLoops, edge, side, ordering) {
|
|
1758
|
+
const ordered = ordering === "REVERSE_STACKED" ? [...sideLoops].reverse() : sideLoops;
|
|
1759
|
+
const inner = ordering === "SEQUENCED" ? [] : ordered.slice(0, ordered.indexOf(edge));
|
|
1760
|
+
const edgeSpacing = Number(input.settings["spacing.edgeEdge"] ?? 10);
|
|
1761
|
+
return Math.max(0, ...sideLoops.map((loop) => loopPortExtents(input, loop, side).normal)) + Number(input.settings["spacing.nodeSelfLoop"] ?? 10) + inner.reduce((sum, loop) => sum + edgeSpacing + (crossSide(side) ? movableLoopLabelExtent(input, loop, side) : 0), 0);
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* Canonical position of a movable loop port along its side, given its
|
|
1765
|
+
* DISTRIBUTED ratio among the side's implicit ports (ELK's port placement
|
|
1766
|
+
* with equal gaps between hidden ports of their own size).
|
|
1767
|
+
*/
|
|
1768
|
+
function movableLoopPortOffset(input, sideLoops, side, length, ratio) {
|
|
1769
|
+
const count = sideLoops.length * 2;
|
|
1770
|
+
const extents = sideLoops.map((loop) => loopPortExtents(input, loop, side));
|
|
1771
|
+
const total = extents.reduce((sum, extent$2) => sum + extent$2.along, 0);
|
|
1772
|
+
const size$1 = total / count;
|
|
1773
|
+
const index = Math.round(ratio * (count + 1)) - 1;
|
|
1774
|
+
return {
|
|
1775
|
+
along: (length - total) / (count + 1) * (index + 1) + size$1 * index + size$1 / 2,
|
|
1776
|
+
normal: Math.max(0, ...extents.map((extent$2) => extent$2.normal))
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1613
1779
|
/** Unconstrained implicit loop ports are restored on loop faces after the sweep. */
|
|
1614
1780
|
function hasMovableLoopPorts(input, edge) {
|
|
1615
1781
|
if (edge.sourceId !== edge.targetId || edge.sourcePort !== void 0 || edge.targetPort !== void 0) return false;
|
|
@@ -1647,7 +1813,7 @@ function loopEnvelopes(input) {
|
|
|
1647
1813
|
};
|
|
1648
1814
|
const horizontal$1 = input.direction === "right" || input.direction === "left";
|
|
1649
1815
|
const reverse = input.direction === "left" || input.direction === "up";
|
|
1650
|
-
const spacing
|
|
1816
|
+
const spacing = Number(input.settings["spacing.nodeSelfLoop"] ?? 10);
|
|
1651
1817
|
let supported = true;
|
|
1652
1818
|
const tracks = selfLoopTracks(allLoops);
|
|
1653
1819
|
for (const edge of allLoops) {
|
|
@@ -1666,7 +1832,7 @@ function loopEnvelopes(input) {
|
|
|
1666
1832
|
}, input.direction, input), getPortPoint(node, edge.targetPort, rect, {
|
|
1667
1833
|
x: 0,
|
|
1668
1834
|
y: 0
|
|
1669
|
-
}, input.direction, input), sourceSide, targetSide, spacing
|
|
1835
|
+
}, input.direction, input), sourceSide, targetSide, spacing * (tracks.get(edge.id) + 1), input.direction);
|
|
1670
1836
|
if (labeled) {
|
|
1671
1837
|
const labelSpacing = Number(input.settings["spacing.edgeLabel"] ?? 2);
|
|
1672
1838
|
const { width = 0, height = 0 } = edge;
|
|
@@ -1691,11 +1857,10 @@ function loopEnvelopes(input) {
|
|
|
1691
1857
|
}
|
|
1692
1858
|
}
|
|
1693
1859
|
const loops = allLoops.filter((edge) => hasMovableLoopPorts(input, edge));
|
|
1694
|
-
if (loops.length === 0
|
|
1860
|
+
if (loops.length === 0) continue;
|
|
1695
1861
|
const settings = input.nodeSettings?.(node);
|
|
1696
1862
|
const distribution = settings?.["edgeRouting.selfLoopDistribution"] ?? "NORTH";
|
|
1697
1863
|
const ordering = settings?.["edgeRouting.selfLoopOrdering"] ?? "STACKED";
|
|
1698
|
-
const spacing = Number(input.settings["spacing.nodeSelfLoop"] ?? 10);
|
|
1699
1864
|
const envelope = {
|
|
1700
1865
|
before: 0,
|
|
1701
1866
|
after: 0,
|
|
@@ -1708,12 +1873,16 @@ function loopEnvelopes(input) {
|
|
|
1708
1873
|
"flowAfter",
|
|
1709
1874
|
"flowBefore"
|
|
1710
1875
|
] : distribution === "NORTH_SOUTH" ? ["before", "after"] : ["before"];
|
|
1876
|
+
const canonicalSides = {
|
|
1877
|
+
before: "NORTH",
|
|
1878
|
+
after: "SOUTH",
|
|
1879
|
+
flowAfter: "EAST",
|
|
1880
|
+
flowBefore: "WEST"
|
|
1881
|
+
};
|
|
1711
1882
|
for (const side of sides$1) {
|
|
1712
1883
|
const selected = loops.filter((_, index) => sides$1[index % sides$1.length] === side);
|
|
1713
|
-
const
|
|
1714
|
-
|
|
1715
|
-
const labelSpacing = Number(input.settings["spacing.edgeLabel"] ?? 2);
|
|
1716
|
-
envelope[side] = spacing * (ordering === "SEQUENCED" ? Math.min(1, selected.length) : selected.length) + selected.reduce((sum, edge) => sum + ((edge[crossSize$3] ?? 0) > 0 ? (edge[crossSize$3] ?? 0) + labelSpacing : 0), 0);
|
|
1884
|
+
const canonical = canonicalSides[side];
|
|
1885
|
+
envelope[side] = Math.max(0, ...selected.map((edge) => movableLoopTrack(input, selected, edge, canonical, ordering) + movableLoopLabelExtent(input, edge, canonical)));
|
|
1717
1886
|
}
|
|
1718
1887
|
envelopes.set(node.id, envelope);
|
|
1719
1888
|
}
|
|
@@ -2881,7 +3050,7 @@ function compactJoinedGeometryUnchecked(input, placement, routes, orientation) {
|
|
|
2881
3050
|
if (point.x >= rect.x + rect.width - 1e-9) return "EAST";
|
|
2882
3051
|
return point.y <= rect.y ? "NORTH" : "SOUTH";
|
|
2883
3052
|
};
|
|
2884
|
-
const crossSide = (side) => side === "NORTH" || side === "SOUTH";
|
|
3053
|
+
const crossSide$1 = (side) => side === "NORTH" || side === "SOUTH";
|
|
2885
3054
|
const segments = [];
|
|
2886
3055
|
for (const [edgeId, points] of canonicalRoutes) {
|
|
2887
3056
|
const edge = edgeById.get(edgeId);
|
|
@@ -2891,8 +3060,8 @@ function compactJoinedGeometryUnchecked(input, placement, routes, orientation) {
|
|
|
2891
3060
|
const first = points[index];
|
|
2892
3061
|
const second = points[index + 1];
|
|
2893
3062
|
if (Math.abs(first.x - second.x) > 1e-9 || Math.abs(first.y - second.y) < 1e-9) continue;
|
|
2894
|
-
if (index === 0 && !crossSide(endpointSide(edge.sourceId, edge.sourcePort, first))) continue;
|
|
2895
|
-
if (index === points.length - 2 && !crossSide(endpointSide(edge.targetId, edge.targetPort, second))) continue;
|
|
3063
|
+
if (index === 0 && !crossSide$1(endpointSide(edge.sourceId, edge.sourcePort, first))) continue;
|
|
3064
|
+
if (index === points.length - 2 && !crossSide$1(endpointSide(edge.targetId, edge.targetPort, second))) continue;
|
|
2896
3065
|
const owner = index === 0 ? nodes.get(edge.sourceId) : index === points.length - 2 ? nodes.get(edge.targetId) : void 0;
|
|
2897
3066
|
const ownerSide = owner ? endpointSide(index === 0 ? edge.sourceId : edge.targetId, index === 0 ? edge.sourcePort : edge.targetPort, index === 0 ? first : second) : void 0;
|
|
2898
3067
|
const bend = index === 0 ? second : first;
|
|
@@ -3055,7 +3224,7 @@ function compactJoinedGeometryUnchecked(input, placement, routes, orientation) {
|
|
|
3055
3224
|
const points = canonicalRoutes.get(edge.id);
|
|
3056
3225
|
const sourceSide = endpointSide(edge.sourceId, edge.sourcePort, points?.[0]);
|
|
3057
3226
|
const targetSide = endpointSide(edge.targetId, edge.targetPort, points?.at(-1));
|
|
3058
|
-
if (crossSide(sourceSide) && crossSide(targetSide)) continue;
|
|
3227
|
+
if (crossSide$1(sourceSide) && crossSide$1(targetSide)) continue;
|
|
3059
3228
|
const reversed = orientation?.reversedEdgeIds.has(edge.id) ?? source.x > target.x;
|
|
3060
3229
|
const from = reversed ? target : source, to = reversed ? source : target;
|
|
3061
3230
|
constraints.push({
|
|
@@ -3149,8 +3318,8 @@ function compactJoinedGeometryUnchecked(input, placement, routes, orientation) {
|
|
|
3149
3318
|
const start = pointToCanonical(originals[0]);
|
|
3150
3319
|
const next = pointToCanonical(originals[1]);
|
|
3151
3320
|
const previous = pointToCanonical(originals.at(-2));
|
|
3152
|
-
if (!crossSide(endpointSide(edge.sourceId, edge.sourcePort, start)) && Math.abs(start.x - next.x) < 1e-9) points[1].x = points[0].x;
|
|
3153
|
-
if (!crossSide(endpointSide(edge.targetId, edge.targetPort, end)) && Math.abs(end.x - previous.x) < 1e-9) points[points.length - 2].x = points.at(-1).x;
|
|
3321
|
+
if (!crossSide$1(endpointSide(edge.sourceId, edge.sourcePort, start)) && Math.abs(start.x - next.x) < 1e-9) points[1].x = points[0].x;
|
|
3322
|
+
if (!crossSide$1(endpointSide(edge.targetId, edge.targetPort, end)) && Math.abs(end.x - previous.x) < 1e-9) points[points.length - 2].x = points.at(-1).x;
|
|
3154
3323
|
}
|
|
3155
3324
|
}
|
|
3156
3325
|
const extent$2 = Math.max(...items.map((item) => item.x + item.width), ...[...canonicalRoutes.values()].flatMap((points) => points.map((point) => point.x)));
|
|
@@ -6427,13 +6596,13 @@ function routeEdges(style) {
|
|
|
6427
6596
|
"WEST"
|
|
6428
6597
|
][index % 4] : distribution === "NORTH_SOUTH" && index % 2 === 1 ? "SOUTH" : "NORTH";
|
|
6429
6598
|
};
|
|
6430
|
-
const loopDistance = (loops, edge, side, ordering
|
|
6431
|
-
const axis =
|
|
6599
|
+
const loopDistance = (loops, edge, side, ordering) => {
|
|
6600
|
+
const axis = side === "NORTH" || side === "SOUTH" ? "height" : "width";
|
|
6432
6601
|
const ordered = ordering === "REVERSE_STACKED" ? [...loops].reverse() : loops;
|
|
6433
6602
|
const index = ordered.indexOf(edge);
|
|
6434
6603
|
const spacing = Number(input.settings["spacing.nodeSelfLoop"] ?? 10);
|
|
6435
6604
|
const labelSpacing = Number(input.settings["spacing.edgeLabel"] ?? 2);
|
|
6436
|
-
const size$1 = (candidate) =>
|
|
6605
|
+
const size$1 = (candidate) => input.edgeSettings?.(candidate)?.["edgeLabels.inline"] === true ? candidate[axis] ?? 0 : 0;
|
|
6437
6606
|
return spacing * (ordering === "SEQUENCED" ? 1 : index + 1) + ordered.slice(0, index).reduce((extent$2, candidate) => extent$2 + (size$1(candidate) > 0 ? size$1(candidate) + labelSpacing : 0), 0) + (size$1(edge) > 0 && input.edgeSettings?.(edge)?.["edgeLabels.inline"] === true ? size$1(edge) / 2 + labelSpacing : 0);
|
|
6438
6607
|
};
|
|
6439
6608
|
const hasFixedLoopPorts = (node) => {
|
|
@@ -6488,7 +6657,7 @@ function routeEdges(style) {
|
|
|
6488
6657
|
for (const [id, loops] of selfLoopsByNodeId) {
|
|
6489
6658
|
const rect = mutableRects.get(id);
|
|
6490
6659
|
const node = nodeById.get(id);
|
|
6491
|
-
if (!rect || !node) continue;
|
|
6660
|
+
if (!rect || !node || hasPlacementLoopEnvelope(placement, id)) continue;
|
|
6492
6661
|
const settings = input.nodeSettings?.(node);
|
|
6493
6662
|
const distribution = settings?.["edgeRouting.selfLoopDistribution"] ?? "NORTH";
|
|
6494
6663
|
const ordering = settings?.["edgeRouting.selfLoopOrdering"] ?? "STACKED";
|
|
@@ -7603,7 +7772,7 @@ function routeEdges(style) {
|
|
|
7603
7772
|
outsideFeedbackEdgeIds.add(edge.id);
|
|
7604
7773
|
continue;
|
|
7605
7774
|
}
|
|
7606
|
-
const movable = hasMovableLoopPorts(input, edge) && hasPlacementLoopEnvelope(placement, source.id)
|
|
7775
|
+
const movable = hasMovableLoopPorts(input, edge) && hasPlacementLoopEnvelope(placement, source.id);
|
|
7607
7776
|
const loopRect = movable ? {
|
|
7608
7777
|
x: 0,
|
|
7609
7778
|
y: 0,
|
|
@@ -7643,7 +7812,32 @@ function routeEdges(style) {
|
|
|
7643
7812
|
startRatio = (countOnSide + nestingIndex + 1) / denominator;
|
|
7644
7813
|
endRatio = (countOnSide - nestingIndex) / denominator;
|
|
7645
7814
|
}
|
|
7646
|
-
const
|
|
7815
|
+
const sideLoops = loops.filter((candidate, i) => loopSide(distribution, i, candidate) === side);
|
|
7816
|
+
if (movable) {
|
|
7817
|
+
const track$1 = movableLoopTrack(input, sideLoops, edge, side, ordering);
|
|
7818
|
+
const sign = side === "NORTH" ? -1 : 1;
|
|
7819
|
+
const base = side === "NORTH" ? 0 : loopRect.height;
|
|
7820
|
+
const [first, last] = [startRatio, endRatio].map((ratio) => movableLoopPortOffset(input, sideLoops, side, loopRect.width, ratio));
|
|
7821
|
+
return [
|
|
7822
|
+
{
|
|
7823
|
+
x: first.along,
|
|
7824
|
+
y: base + sign * first.normal
|
|
7825
|
+
},
|
|
7826
|
+
{
|
|
7827
|
+
x: first.along,
|
|
7828
|
+
y: base + sign * track$1
|
|
7829
|
+
},
|
|
7830
|
+
{
|
|
7831
|
+
x: last.along,
|
|
7832
|
+
y: base + sign * track$1
|
|
7833
|
+
},
|
|
7834
|
+
{
|
|
7835
|
+
x: last.along,
|
|
7836
|
+
y: base + sign * last.normal
|
|
7837
|
+
}
|
|
7838
|
+
];
|
|
7839
|
+
}
|
|
7840
|
+
const distance = loopDistance(sideLoops, edge, side, ordering);
|
|
7647
7841
|
const y = side === "NORTH" ? loopRect.y - distance : loopRect.y + loopRect.height + distance;
|
|
7648
7842
|
const start$2 = {
|
|
7649
7843
|
x: loopRect.x + loopRect.width * startRatio,
|
|
@@ -7673,7 +7867,32 @@ function routeEdges(style) {
|
|
|
7673
7867
|
const secondRatio = sequenced ? 1 / denominator : 2 / denominator;
|
|
7674
7868
|
const startRatio = side === "EAST" ? firstRatio : secondRatio;
|
|
7675
7869
|
const endRatio = side === "EAST" ? secondRatio : firstRatio;
|
|
7676
|
-
const
|
|
7870
|
+
const sideLoops = loops.filter((candidate, i) => loopSide(distribution, i, candidate) === side);
|
|
7871
|
+
if (movable) {
|
|
7872
|
+
const track$1 = movableLoopTrack(input, sideLoops, edge, side, ordering);
|
|
7873
|
+
const sign = side === "WEST" ? -1 : 1;
|
|
7874
|
+
const base = side === "WEST" ? 0 : loopRect.width;
|
|
7875
|
+
const [first, last] = [startRatio, endRatio].map((ratio) => movableLoopPortOffset(input, sideLoops, side, loopRect.height, ratio));
|
|
7876
|
+
return [
|
|
7877
|
+
{
|
|
7878
|
+
x: base + sign * first.normal,
|
|
7879
|
+
y: first.along
|
|
7880
|
+
},
|
|
7881
|
+
{
|
|
7882
|
+
x: base + sign * track$1,
|
|
7883
|
+
y: first.along
|
|
7884
|
+
},
|
|
7885
|
+
{
|
|
7886
|
+
x: base + sign * track$1,
|
|
7887
|
+
y: last.along
|
|
7888
|
+
},
|
|
7889
|
+
{
|
|
7890
|
+
x: base + sign * last.normal,
|
|
7891
|
+
y: last.along
|
|
7892
|
+
}
|
|
7893
|
+
];
|
|
7894
|
+
}
|
|
7895
|
+
const distance = input.edgeSettings?.(edge)?.["edgeLabels.inline"] === true ? loopDistance(sideLoops, edge, side, ordering) : spacing * (indexOnSide + 1);
|
|
7677
7896
|
const x = side === "EAST" ? loopRect.x + loopRect.width + distance : loopRect.x - distance;
|
|
7678
7897
|
const start$2 = {
|
|
7679
7898
|
x: side === "EAST" ? loopRect.x + loopRect.width : loopRect.x,
|
|
@@ -18936,6 +19155,8 @@ function* createLayeredScopePipeline(graph, options, context, fallbacks = {
|
|
|
18936
19155
|
const separated$1 = runSeparatedComponents(graph, options, context);
|
|
18937
19156
|
if (separated$1) return separated$1;
|
|
18938
19157
|
}
|
|
19158
|
+
const hiddenLoopPorts$1 = hideSelfLoopPorts(graph, options);
|
|
19159
|
+
if (hiddenLoopPorts$1) return restoreSelfLoopPorts(graph, yield* createLayeredScopePipeline(hiddenLoopPorts$1.graph, hiddenLoopPorts$1.options, context, fallbacks), hiddenLoopPorts$1.edges);
|
|
18939
19160
|
const direction = options.direction ?? graph.direction ?? "right";
|
|
18940
19161
|
const padding = typeof options.padding === "number" ? {
|
|
18941
19162
|
top: options.padding,
|
|
@@ -20017,7 +20238,7 @@ function* createLayeredScopePipeline(graph, options, context, fallbacks = {
|
|
|
20017
20238
|
y: (points[1].y + points[2].y - height) / 2
|
|
20018
20239
|
} : void 0;
|
|
20019
20240
|
const movableExteriorLoopLabelPosition = (() => {
|
|
20020
|
-
if (edgeRouting !== "ORTHOGONAL" || labelPlacement !== "CENTER" ||
|
|
20241
|
+
if (edgeRouting !== "ORTHOGONAL" || labelPlacement !== "CENTER" || !hasMovableLoopPorts(input, edge) || !sourceRect || points.length !== 4) return void 0;
|
|
20021
20242
|
const first = points[1], last = points[2];
|
|
20022
20243
|
if (first.y === last.y) {
|
|
20023
20244
|
const low = first.y < sourceRect.y;
|