@bpmnkit/core 0.0.22 → 0.0.24
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/bpmn/auto-layout.js +190 -21
- package/dist/bpmn/bpmn-builder.d.ts +104 -16
- package/dist/bpmn/bpmn-builder.js +561 -374
- package/dist/bpmn/bpmn-model.d.ts +6 -0
- package/dist/bpmn/bpmn-parser.js +10 -0
- package/dist/bpmn/bpmn-serializer.js +10 -1
- package/dist/bpmn/compact.js +1 -0
- package/dist/bpmn/index.d.ts +15 -1
- package/dist/bpmn/index.js +17 -1
- package/dist/bpmn/optimize/tasks.js +1 -0
- package/dist/bpmn/zeebe-extensions.d.ts +2 -0
- package/dist/bpmn/zeebe-extensions.js +3 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2 -1
- package/dist/layout/astar.d.ts +15 -0
- package/dist/layout/astar.js +191 -0
- package/dist/layout/block-builder.d.ts +37 -0
- package/dist/layout/block-builder.js +154 -0
- package/dist/layout/block-layout.d.ts +9 -0
- package/dist/layout/block-layout.js +163 -0
- package/dist/layout/coordinates.d.ts +23 -0
- package/dist/layout/coordinates.js +612 -88
- package/dist/layout/index.d.ts +5 -0
- package/dist/layout/index.js +4 -0
- package/dist/layout/layout-engine.d.ts +2 -1
- package/dist/layout/layout-engine.js +209 -29
- package/dist/layout/overlap.js +3 -0
- package/dist/layout/routing.d.ts +10 -3
- package/dist/layout/routing.js +254 -71
- package/dist/layout/types.d.ts +6 -0
- package/package.json +4 -3
package/dist/layout/index.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export { layoutProcess, layoutFlowNodes } from "./layout-engine.js";
|
|
2
|
+
export { buildBlockTree } from "./block-builder.js";
|
|
3
|
+
export type { FlowBlock, GatewayBlock, NodeBlock, SequenceBlock } from "./block-builder.js";
|
|
4
|
+
export { applyBlockLayout } from "./block-layout.js";
|
|
5
|
+
export { routeEdgeAstar } from "./astar.js";
|
|
2
6
|
export { benchmarkLayout, compareLayouts, formatBenchmarkResult, generateAutoLayout, parseReferenceLayout, } from "./bench.js";
|
|
3
7
|
export type { BenchmarkResult, BoundingBox, ElementComparison, ElementPosition, FlowOrderViolation, } from "./bench.js";
|
|
8
|
+
export { assignGridRows } from "./coordinates.js";
|
|
4
9
|
export { assertNoOverlap } from "./overlap.js";
|
|
5
10
|
export type { Bounds, LayoutEdge, LayoutNode, LayoutResult, Waypoint } from "./types.js";
|
|
6
11
|
export { ELEMENT_SIZES, GRID_CELL_HEIGHT, GRID_CELL_WIDTH, HORIZONTAL_SPACING, LABEL_CHAR_WIDTH, LABEL_HEIGHT, LABEL_MIN_WIDTH, LABEL_VERTICAL_OFFSET, SUBPROCESS_PADDING, VERTICAL_SPACING, } from "./types.js";
|
package/dist/layout/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export { layoutProcess, layoutFlowNodes } from "./layout-engine.js";
|
|
2
|
+
export { buildBlockTree } from "./block-builder.js";
|
|
3
|
+
export { applyBlockLayout } from "./block-layout.js";
|
|
4
|
+
export { routeEdgeAstar } from "./astar.js";
|
|
2
5
|
export { benchmarkLayout, compareLayouts, formatBenchmarkResult, generateAutoLayout, parseReferenceLayout, } from "./bench.js";
|
|
6
|
+
export { assignGridRows } from "./coordinates.js";
|
|
3
7
|
export { assertNoOverlap } from "./overlap.js";
|
|
4
8
|
export { ELEMENT_SIZES, GRID_CELL_HEIGHT, GRID_CELL_WIDTH, HORIZONTAL_SPACING, LABEL_CHAR_WIDTH, LABEL_HEIGHT, LABEL_MIN_WIDTH, LABEL_VERTICAL_OFFSET, SUBPROCESS_PADDING, VERTICAL_SPACING, } from "./types.js";
|
|
5
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -10,7 +10,8 @@ import type { LayoutResult } from "./types.js";
|
|
|
10
10
|
* 4. Coordinate assignment — Fixed element sizes with spacing
|
|
11
11
|
* 5. Sub-process layout — Recursive nested passes
|
|
12
12
|
* 6. Edge routing — Orthogonal waypoints
|
|
13
|
-
* 7.
|
|
13
|
+
* 7. Boundary event repositioning — place events on host border
|
|
14
|
+
* 8. Overlap assertion — Post-condition validation
|
|
14
15
|
*/
|
|
15
16
|
export declare function layoutProcess(process: BpmnProcess): LayoutResult;
|
|
16
17
|
/**
|
|
@@ -1,10 +1,139 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildBlockTree } from "./block-builder.js";
|
|
2
|
+
import { applyBlockLayout } from "./block-layout.js";
|
|
3
|
+
import { alignBaselinePath, alignBranchBaselines, alignSplitJoinPairs, assignCoordinates, assignGridRows, compactBranches, distributeSplitBranches, ensureEarlyReturnOffBaseline, resolveLayerOverlaps, snapToYRows, } from "./coordinates.js";
|
|
2
4
|
import { minimizeCrossings } from "./crossing.js";
|
|
3
5
|
import { buildGraph, detectBackEdges, reverseBackEdges } from "./graph.js";
|
|
4
6
|
import { assignLayers, groupByLayer } from "./layers.js";
|
|
5
7
|
import { assertNoOverlap } from "./overlap.js";
|
|
6
8
|
import { routeEdges } from "./routing.js";
|
|
7
9
|
import { layoutSubProcesses } from "./subprocess.js";
|
|
10
|
+
const CHAIN_GAP = 30;
|
|
11
|
+
const CHAIN_V_GAP = 20;
|
|
12
|
+
/**
|
|
13
|
+
* Reposition boundary events to the bottom edge of their host task, then walk
|
|
14
|
+
* each boundary event's exclusive downstream chain and place those nodes
|
|
15
|
+
* horizontally to the right of the host task. Re-routes all affected edges.
|
|
16
|
+
*/
|
|
17
|
+
function repositionBoundaryEvents(flowElements, result) {
|
|
18
|
+
const boundaryMap = new Map();
|
|
19
|
+
for (const el of flowElements) {
|
|
20
|
+
if (el.type !== "boundaryEvent")
|
|
21
|
+
continue;
|
|
22
|
+
const list = boundaryMap.get(el.attachedToRef) ?? [];
|
|
23
|
+
list.push(el.id);
|
|
24
|
+
boundaryMap.set(el.attachedToRef, list);
|
|
25
|
+
}
|
|
26
|
+
if (boundaryMap.size === 0)
|
|
27
|
+
return;
|
|
28
|
+
const nodeById = new Map(result.nodes.map((n) => [n.id, n]));
|
|
29
|
+
const succIds = new Map();
|
|
30
|
+
const predIds = new Map();
|
|
31
|
+
for (const edge of result.edges) {
|
|
32
|
+
const se = succIds.get(edge.sourceRef) ?? [];
|
|
33
|
+
se.push(edge.targetRef);
|
|
34
|
+
succIds.set(edge.sourceRef, se);
|
|
35
|
+
const ps = predIds.get(edge.targetRef) ?? new Set();
|
|
36
|
+
ps.add(edge.sourceRef);
|
|
37
|
+
predIds.set(edge.targetRef, ps);
|
|
38
|
+
}
|
|
39
|
+
for (const [hostId, beIds] of boundaryMap) {
|
|
40
|
+
const hostNode = nodeById.get(hostId);
|
|
41
|
+
if (!hostNode)
|
|
42
|
+
continue;
|
|
43
|
+
for (let i = 0; i < beIds.length; i++) {
|
|
44
|
+
const beId = beIds[i];
|
|
45
|
+
if (!beId)
|
|
46
|
+
continue;
|
|
47
|
+
const beNode = nodeById.get(beId);
|
|
48
|
+
if (!beNode)
|
|
49
|
+
continue;
|
|
50
|
+
const bW = beNode.bounds.width;
|
|
51
|
+
const bH = beNode.bounds.height;
|
|
52
|
+
// Place boundary event on the bottom edge of the host task, stacking leftward
|
|
53
|
+
const rightEdge = hostNode.bounds.x + hostNode.bounds.width;
|
|
54
|
+
beNode.bounds.x = Math.round(rightEdge - bW / 2 - i * (bW + 4));
|
|
55
|
+
beNode.bounds.y = Math.round(hostNode.bounds.y + hostNode.bounds.height - bH / 2);
|
|
56
|
+
if (beNode.labelBounds) {
|
|
57
|
+
beNode.labelBounds.x = beNode.bounds.x + Math.round(bW / 2 - beNode.labelBounds.width / 2);
|
|
58
|
+
beNode.labelBounds.y = beNode.bounds.y + bH + 4;
|
|
59
|
+
}
|
|
60
|
+
// Collect nodes exclusively reachable from this boundary event (BFS)
|
|
61
|
+
const chainSet = new Set([beId]);
|
|
62
|
+
const chainOrder = [];
|
|
63
|
+
const queue = [...(succIds.get(beId) ?? [])];
|
|
64
|
+
while (queue.length > 0) {
|
|
65
|
+
const id = queue.shift();
|
|
66
|
+
if (!id || chainSet.has(id))
|
|
67
|
+
continue;
|
|
68
|
+
const preds = predIds.get(id) ?? new Set();
|
|
69
|
+
if ([...preds].every((p) => chainSet.has(p))) {
|
|
70
|
+
chainSet.add(id);
|
|
71
|
+
chainOrder.push(id);
|
|
72
|
+
queue.push(...(succIds.get(id) ?? []));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Each boundary event's chain gets its own vertical lane
|
|
76
|
+
let maxChainH = 0;
|
|
77
|
+
for (const id of chainOrder) {
|
|
78
|
+
const n = nodeById.get(id);
|
|
79
|
+
if (n)
|
|
80
|
+
maxChainH = Math.max(maxChainH, n.bounds.height);
|
|
81
|
+
}
|
|
82
|
+
const laneOffset = i * (maxChainH + CHAIN_V_GAP + 10);
|
|
83
|
+
const chainCenterY = Math.round(beNode.bounds.y + bH + CHAIN_V_GAP + maxChainH / 2 + laneOffset);
|
|
84
|
+
const chainStartX = Math.max(Math.round(beNode.bounds.x + bW / 2) + CHAIN_GAP, hostNode.bounds.x + hostNode.bounds.width + CHAIN_GAP);
|
|
85
|
+
let curX = chainStartX;
|
|
86
|
+
for (const id of chainOrder) {
|
|
87
|
+
const n = nodeById.get(id);
|
|
88
|
+
if (!n)
|
|
89
|
+
continue;
|
|
90
|
+
n.bounds.x = curX;
|
|
91
|
+
n.bounds.y = chainCenterY - Math.round(n.bounds.height / 2);
|
|
92
|
+
if (n.labelBounds) {
|
|
93
|
+
// Center label on node, but clamp so it never extends left of the node —
|
|
94
|
+
// wide event labels would otherwise overlap the preceding chain element.
|
|
95
|
+
const labelX = n.bounds.x + Math.round(n.bounds.width / 2 - n.labelBounds.width / 2);
|
|
96
|
+
n.labelBounds.x = Math.max(labelX, n.bounds.x);
|
|
97
|
+
n.labelBounds.y = n.bounds.y + n.bounds.height + 4;
|
|
98
|
+
}
|
|
99
|
+
// Advance past the node AND its label so the next element doesn't overlap.
|
|
100
|
+
const nodeRight = n.bounds.x + n.bounds.width;
|
|
101
|
+
const labelRight = n.labelBounds ? n.labelBounds.x + n.labelBounds.width : 0;
|
|
102
|
+
curX = Math.max(nodeRight, labelRight) + CHAIN_GAP;
|
|
103
|
+
}
|
|
104
|
+
// Re-route edges touching the boundary event or its chain
|
|
105
|
+
for (const edge of result.edges) {
|
|
106
|
+
if (!chainSet.has(edge.sourceRef))
|
|
107
|
+
continue;
|
|
108
|
+
const src = nodeById.get(edge.sourceRef);
|
|
109
|
+
const tgt = nodeById.get(edge.targetRef);
|
|
110
|
+
if (!src || !tgt)
|
|
111
|
+
continue;
|
|
112
|
+
if (edge.sourceRef === beId) {
|
|
113
|
+
const srcX = Math.round(src.bounds.x + bW / 2);
|
|
114
|
+
const srcY = Math.round(src.bounds.y + bH);
|
|
115
|
+
const tgtX = Math.round(tgt.bounds.x);
|
|
116
|
+
const tgtY = Math.round(tgt.bounds.y + tgt.bounds.height / 2);
|
|
117
|
+
edge.waypoints = [
|
|
118
|
+
{ x: srcX, y: srcY },
|
|
119
|
+
{ x: srcX, y: tgtY },
|
|
120
|
+
{ x: tgtX, y: tgtY },
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const srcX = Math.round(src.bounds.x + src.bounds.width);
|
|
125
|
+
const srcY = Math.round(src.bounds.y + src.bounds.height / 2);
|
|
126
|
+
const tgtX = Math.round(tgt.bounds.x);
|
|
127
|
+
const tgtY = Math.round(tgt.bounds.y + tgt.bounds.height / 2);
|
|
128
|
+
edge.waypoints = [
|
|
129
|
+
{ x: srcX, y: srcY },
|
|
130
|
+
{ x: tgtX, y: tgtY },
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
8
137
|
/**
|
|
9
138
|
* Auto-layout a BPMN process using the Sugiyama/layered algorithm.
|
|
10
139
|
*
|
|
@@ -15,10 +144,12 @@ import { layoutSubProcesses } from "./subprocess.js";
|
|
|
15
144
|
* 4. Coordinate assignment — Fixed element sizes with spacing
|
|
16
145
|
* 5. Sub-process layout — Recursive nested passes
|
|
17
146
|
* 6. Edge routing — Orthogonal waypoints
|
|
18
|
-
* 7.
|
|
147
|
+
* 7. Boundary event repositioning — place events on host border
|
|
148
|
+
* 8. Overlap assertion — Post-condition validation
|
|
19
149
|
*/
|
|
20
150
|
export function layoutProcess(process) {
|
|
21
151
|
const result = layoutFlowNodes(process.flowElements, process.sequenceFlows);
|
|
152
|
+
repositionBoundaryEvents(process.flowElements, result);
|
|
22
153
|
assertNoOverlap(result);
|
|
23
154
|
return result;
|
|
24
155
|
}
|
|
@@ -39,43 +170,46 @@ export function layoutFlowNodes(flowNodes, sequenceFlows) {
|
|
|
39
170
|
const graph = buildGraph(flowNodes, sequenceFlows);
|
|
40
171
|
const backEdges = detectBackEdges(graph, sequenceFlows);
|
|
41
172
|
const dag = backEdges.length > 0 ? reverseBackEdges(graph, backEdges) : graph;
|
|
42
|
-
// Phase 2:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// Phase 4d: Align all baseline-path nodes to the same center-Y
|
|
54
|
-
alignBaselinePath(layoutNodes, dag, backEdges);
|
|
55
|
-
// Phase 4e: Ensure early-return branches are never on the baseline
|
|
56
|
-
ensureEarlyReturnOffBaseline(layoutNodes, dag, backEdges);
|
|
57
|
-
// Phase 4f: Distribute split gateway branches symmetrically
|
|
58
|
-
distributeSplitBranches(layoutNodes, dag, backEdges);
|
|
59
|
-
// Phase 4g: Resolve any layer overlaps from redistribution
|
|
60
|
-
resolveLayerOverlaps(layoutNodes);
|
|
61
|
-
// Phase 4h: Re-align baseline after overlap resolution (overlap resolution may push
|
|
62
|
-
// baseline nodes off-center when they share a layer with branch nodes)
|
|
63
|
-
alignBaselinePath(layoutNodes, dag, backEdges);
|
|
64
|
-
// Phase 4i: Final overlap resolution — baseline re-alignment may pull a node back into
|
|
65
|
-
// an overlap that resolveLayerOverlaps already fixed; one more pass eliminates these.
|
|
66
|
-
resolveLayerOverlaps(layoutNodes);
|
|
173
|
+
// Phase 2: Try block-based layout (primary path for structured processes)
|
|
174
|
+
// Block layout only works well for processes without back-edges (loops).
|
|
175
|
+
let layoutNodes;
|
|
176
|
+
const blockTree = backEdges.length === 0 ? buildBlockTree(dag, nodeIndex) : null;
|
|
177
|
+
const usedBlockLayout = blockTree !== null;
|
|
178
|
+
if (blockTree) {
|
|
179
|
+
layoutNodes = applyBlockLayout(blockTree, nodeIndex);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
layoutNodes = sugiyamaLayout(dag, nodeIndex, backEdges);
|
|
183
|
+
}
|
|
67
184
|
// Phase 5: Sub-process layout — expand containers and lay out children
|
|
68
185
|
const childResults = layoutSubProcesses(layoutNodes, nodeIndex);
|
|
69
|
-
// After subprocess expansion, push nodes that now overlap with expanded containers
|
|
186
|
+
// After subprocess expansion, push nodes that now overlap with expanded containers.
|
|
187
|
+
// For block layout, assign unique layer indices first so resolveLayerOverlaps works
|
|
188
|
+
// correctly (block layout nodes all start at layer=0).
|
|
189
|
+
if (usedBlockLayout && childResults.length > 0) {
|
|
190
|
+
// Assign each block-layout node a unique layer so overlap resolution doesn't
|
|
191
|
+
// collapse them all into the same bucket and push them vertically apart.
|
|
192
|
+
for (let idx = 0; idx < layoutNodes.length; idx++) {
|
|
193
|
+
const n = layoutNodes[idx];
|
|
194
|
+
if (n)
|
|
195
|
+
n.layer = idx;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
70
198
|
resolveSubProcessOverlaps(layoutNodes);
|
|
71
199
|
// Phase 5b: Resolve Y-direction overlaps caused by subprocess expansion.
|
|
72
200
|
// Expanded subprocesses grow in-place and can overlap same-layer siblings.
|
|
73
|
-
|
|
201
|
+
// For block layout without subprocesses, skip this — overlaps are impossible by construction.
|
|
202
|
+
if (!usedBlockLayout || childResults.length > 0) {
|
|
203
|
+
resolveLayerOverlaps(layoutNodes);
|
|
204
|
+
}
|
|
74
205
|
// Phase 5c: Sync child positions to their subprocess containers.
|
|
75
206
|
// resolveLayerOverlaps (including its Y-normalization pass) may have shifted
|
|
76
207
|
// subprocess containers after their children were already translated to
|
|
77
208
|
// absolute coordinates — children must follow.
|
|
78
209
|
syncSubProcessChildren(childResults, layoutNodes);
|
|
210
|
+
// Assign grid-row indices based on final center-Y positions (eliminates pixel-tolerance
|
|
211
|
+
// guessing in port-side decisions).
|
|
212
|
+
assignGridRows(layoutNodes);
|
|
79
213
|
// Phase 6: Edge routing (uses original back-edges for routing, not reversed)
|
|
80
214
|
const nodeMap = new Map();
|
|
81
215
|
for (const node of layoutNodes) {
|
|
@@ -95,6 +229,52 @@ export function layoutFlowNodes(flowNodes, sequenceFlows) {
|
|
|
95
229
|
}
|
|
96
230
|
return { nodes: allNodes, edges: allEdges };
|
|
97
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Run the Sugiyama layered layout pipeline.
|
|
234
|
+
* Used as fallback for unstructured or loop-containing processes.
|
|
235
|
+
*/
|
|
236
|
+
function sugiyamaLayout(dag, nodeIndex, backEdges) {
|
|
237
|
+
// Phase 2: Layer assignment
|
|
238
|
+
const layers = assignLayers(dag);
|
|
239
|
+
// Phase 3: Group by layer and minimize crossings
|
|
240
|
+
const layerGroups = groupByLayer(layers);
|
|
241
|
+
const orderedLayers = minimizeCrossings(layerGroups, dag);
|
|
242
|
+
// Phase 4: Coordinate assignment
|
|
243
|
+
const layoutNodes = assignCoordinates(orderedLayers, nodeIndex);
|
|
244
|
+
// Phase 4b: Align linear sequences to a common y-baseline
|
|
245
|
+
alignBranchBaselines(layoutNodes, dag);
|
|
246
|
+
// Phase 4c: Align split/join gateway pairs to same y-coordinate
|
|
247
|
+
alignSplitJoinPairs(layoutNodes, dag, backEdges);
|
|
248
|
+
// Phase 4d: Align all baseline-path nodes to the same center-Y
|
|
249
|
+
alignBaselinePath(layoutNodes, dag, backEdges);
|
|
250
|
+
// Phase 4e: Ensure early-return branches are never on the baseline
|
|
251
|
+
ensureEarlyReturnOffBaseline(layoutNodes, dag, backEdges);
|
|
252
|
+
// Re-align linear chains that may have been disrupted by position swaps
|
|
253
|
+
alignBranchBaselines(layoutNodes, dag);
|
|
254
|
+
// Phase 4f: Distribute split gateway branches symmetrically
|
|
255
|
+
distributeSplitBranches(layoutNodes, dag, backEdges);
|
|
256
|
+
// Re-align split/join pairs that may have been separated during branch distribution
|
|
257
|
+
alignSplitJoinPairs(layoutNodes, dag, backEdges);
|
|
258
|
+
// Re-align branch spines after distribution moved chains and alignSplitJoinPairs
|
|
259
|
+
// adjusted join gateways (continuation nodes after joins must follow)
|
|
260
|
+
alignBranchBaselines(layoutNodes, dag);
|
|
261
|
+
// Phase 4g: Resolve any layer overlaps from redistribution
|
|
262
|
+
resolveLayerOverlaps(layoutNodes);
|
|
263
|
+
// Phase 4h: Re-align baseline after overlap resolution (overlap resolution may push
|
|
264
|
+
// baseline nodes off-center when they share a layer with branch nodes)
|
|
265
|
+
alignBaselinePath(layoutNodes, dag, backEdges);
|
|
266
|
+
// Phase 4i: Final overlap resolution — baseline re-alignment may pull a node back into
|
|
267
|
+
// an overlap that resolveLayerOverlaps already fixed; one more pass eliminates these.
|
|
268
|
+
resolveLayerOverlaps(layoutNodes);
|
|
269
|
+
// Phase 4j: Branch compaction — pull branch subtrees toward baseline
|
|
270
|
+
compactBranches(layoutNodes, dag, backEdges);
|
|
271
|
+
resolveLayerOverlaps(layoutNodes);
|
|
272
|
+
alignBaselinePath(layoutNodes, dag, backEdges);
|
|
273
|
+
// Phase 4k: Row snapping — merge close Y rows for matrix-like alignment
|
|
274
|
+
snapToYRows(layoutNodes);
|
|
275
|
+
resolveLayerOverlaps(layoutNodes);
|
|
276
|
+
return layoutNodes;
|
|
277
|
+
}
|
|
98
278
|
/**
|
|
99
279
|
* After subprocess expansion, cascade-shift all subsequent layers
|
|
100
280
|
* so that inter-layer spacing is preserved.
|
package/dist/layout/overlap.js
CHANGED
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
export function assertNoOverlap(result) {
|
|
9
9
|
const allBounds = [];
|
|
10
10
|
for (const node of result.nodes) {
|
|
11
|
+
// Boundary events intentionally overlap their host activity — skip them.
|
|
12
|
+
if (node.type === "boundaryEvent")
|
|
13
|
+
continue;
|
|
11
14
|
allBounds.push({ id: node.id, kind: "element", bounds: node.bounds });
|
|
12
15
|
if (node.labelBounds) {
|
|
13
16
|
allBounds.push({ id: `${node.id}-label`, kind: "label", bounds: node.labelBounds });
|
package/dist/layout/routing.d.ts
CHANGED
|
@@ -8,13 +8,15 @@ export type PortSide = "right" | "top" | "bottom";
|
|
|
8
8
|
* Non-gateway targets always receive edges from the left side.
|
|
9
9
|
* Split gateways (starting): incoming always from the left.
|
|
10
10
|
* Join gateways (closing): incoming based on relative position (top/bottom/left).
|
|
11
|
+
*
|
|
12
|
+
* Uses gridRow (integer row index) when available for exact comparison;
|
|
13
|
+
* falls back to pixel-Y with PORT_SAME_Y_TOLERANCE for nodes without gridRow.
|
|
11
14
|
*/
|
|
12
15
|
export declare function resolveTargetPort(source: LayoutNode, target: LayoutNode, joinGateways: ReadonlySet<string>): "left" | "top" | "bottom";
|
|
13
16
|
/**
|
|
14
17
|
* Assign source ports for outgoing edges of a gateway.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - Even count: upper half → top, lower half → bottom, no right port.
|
|
18
|
+
* Uses absolute direction: target above → top, below → bottom, same level → right.
|
|
19
|
+
* Single output always exits from the right port.
|
|
18
20
|
*/
|
|
19
21
|
export declare function assignGatewayPorts(outgoingFlows: BpmnSequenceFlow[], nodeMap: Map<string, LayoutNode>): Map<string, PortSide>;
|
|
20
22
|
/**
|
|
@@ -23,4 +25,9 @@ export declare function assignGatewayPorts(outgoingFlows: BpmnSequenceFlow[], no
|
|
|
23
25
|
* Gateway sources use port-based routing (top/right/bottom).
|
|
24
26
|
*/
|
|
25
27
|
export declare function routeEdges(sequenceFlows: BpmnSequenceFlow[], nodeMap: Map<string, LayoutNode>, backEdges: BackEdge[]): LayoutEdge[];
|
|
28
|
+
/**
|
|
29
|
+
* Post-process routed edges to avoid crossing through intermediate shapes.
|
|
30
|
+
* For each segment that passes through a shape, adds detour waypoints around it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveEdgeCrossings(edges: LayoutEdge[], nodeMap: Map<string, LayoutNode>): void;
|
|
26
33
|
//# sourceMappingURL=routing.d.ts.map
|