@aranzatech/diagrams-bpmn 0.3.5 → 0.3.7
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/{catalog-DNIyjHbl.d.ts → catalog-CYZHikuU.d.ts} +1 -1
- package/dist/{catalog-DG-sz0VM.d.cts → catalog-C_S9hyyn.d.cts} +1 -1
- package/dist/{chunk-JFYWN6QH.js → chunk-EMTO53AN.js} +52 -73
- package/dist/chunk-EMTO53AN.js.map +1 -0
- package/dist/chunk-G22XQD6H.js +64 -0
- package/dist/chunk-G22XQD6H.js.map +1 -0
- package/dist/{chunk-NYIYQUGX.js → chunk-OFOTX3LA.js} +124 -20
- package/dist/chunk-OFOTX3LA.js.map +1 -0
- package/dist/{chunk-YAYZW45I.js → chunk-SRUWPELT.js} +80 -3
- package/dist/chunk-SRUWPELT.js.map +1 -0
- package/dist/edges/index.cjs +73 -35
- package/dist/edges/index.cjs.map +1 -1
- package/dist/edges/index.js +2 -1
- package/dist/elements/index.d.cts +3 -3
- package/dist/elements/index.d.ts +3 -3
- package/dist/extensions/index.d.cts +2 -2
- package/dist/extensions/index.d.ts +2 -2
- package/dist/index.cjs +194 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/layout/index.cjs +1190 -874
- package/dist/layout/index.cjs.map +1 -1
- package/dist/layout/index.d.cts +4 -4
- package/dist/layout/index.d.ts +4 -4
- package/dist/layout/index.js +604 -91
- package/dist/layout/index.js.map +1 -1
- package/dist/modeling/index.cjs +78 -0
- package/dist/modeling/index.cjs.map +1 -1
- package/dist/modeling/index.d.cts +10 -5
- package/dist/modeling/index.d.ts +10 -5
- package/dist/modeling/index.js +1 -1
- package/dist/{types-nvF59RGF.d.cts → types--x9aoecw.d.cts} +5 -0
- package/dist/{types-nvF59RGF.d.ts → types--x9aoecw.d.ts} +5 -0
- package/dist/{types-dQUuSnV5.d.cts → types-CrFDTGo9.d.cts} +1 -1
- package/dist/{types-CuDL2YGL.d.ts → types-DoPv3m7u.d.ts} +2 -2
- package/dist/{types-X5FyP8oS.d.ts → types-DteJykQG.d.ts} +1 -1
- package/dist/{types-CDp9kWQ4.d.cts → types-YZ4sj3Ih.d.cts} +2 -2
- package/dist/validation/index.d.cts +3 -3
- package/dist/validation/index.d.ts +3 -3
- package/dist/xml/index.cjs +162 -18
- package/dist/xml/index.cjs.map +1 -1
- package/dist/xml/index.d.cts +4 -4
- package/dist/xml/index.d.ts +4 -4
- package/dist/xml/index.js +2 -1
- package/package.json +1 -1
- package/dist/chunk-FFWJA5BV.js +0 -163
- package/dist/chunk-FFWJA5BV.js.map +0 -1
- package/dist/chunk-JFYWN6QH.js.map +0 -1
- package/dist/chunk-NYIYQUGX.js.map +0 -1
- package/dist/chunk-YAYZW45I.js.map +0 -1
- package/dist/elk-QT7H4252.js +0 -6
- package/dist/elk-QT7H4252.js.map +0 -1
package/dist/layout/index.js
CHANGED
|
@@ -1,10 +1,166 @@
|
|
|
1
|
-
|
|
2
|
-
import { getBpmnNodeSize } from '../chunk-YAYZW45I.js';
|
|
1
|
+
import { getBpmnNodeSize } from '../chunk-SRUWPELT.js';
|
|
3
2
|
import '../chunk-RLAJNRF2.js';
|
|
4
3
|
import '../chunk-L5Z22RLX.js';
|
|
5
|
-
import { dagreLayout, applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
|
|
4
|
+
import { elkLayout, dagreLayout, applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
|
|
6
5
|
export { applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
|
|
7
6
|
|
|
7
|
+
var BPMN_CONTAINER_TYPES = /* @__PURE__ */ new Set([
|
|
8
|
+
"Pool",
|
|
9
|
+
"Lane",
|
|
10
|
+
"SubProcess",
|
|
11
|
+
"Transaction",
|
|
12
|
+
"EventSubProcess",
|
|
13
|
+
"AdHocSubProcess"
|
|
14
|
+
]);
|
|
15
|
+
var CONTAINER_MIN_SIZE = {
|
|
16
|
+
Pool: { w: 720, h: 200 },
|
|
17
|
+
Lane: { w: 600, h: 160 },
|
|
18
|
+
SubProcess: { w: 240, h: 140 },
|
|
19
|
+
Transaction: { w: 240, h: 140 },
|
|
20
|
+
EventSubProcess: { w: 240, h: 140 },
|
|
21
|
+
AdHocSubProcess: { w: 240, h: 140 }
|
|
22
|
+
};
|
|
23
|
+
var CONTAINER_PADDING = {
|
|
24
|
+
Pool: "[top=30,left=60,bottom=30,right=50]",
|
|
25
|
+
Lane: "[top=40,left=70,bottom=40,right=50]",
|
|
26
|
+
SubProcess: "[top=30,left=40,bottom=30,right=40]",
|
|
27
|
+
Transaction: "[top=30,left=40,bottom=30,right=40]",
|
|
28
|
+
EventSubProcess: "[top=30,left=40,bottom=30,right=40]",
|
|
29
|
+
AdHocSubProcess: "[top=30,left=40,bottom=30,right=40]"
|
|
30
|
+
};
|
|
31
|
+
async function bpmnElkLayout(nodes, edges) {
|
|
32
|
+
const poolsWithLanes = /* @__PURE__ */ new Set();
|
|
33
|
+
for (const node of nodes) {
|
|
34
|
+
if (node.data.elementType === "Lane" && node.parentId) {
|
|
35
|
+
poolsWithLanes.add(node.parentId);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const result = await elkLayout(
|
|
39
|
+
nodes,
|
|
40
|
+
edges,
|
|
41
|
+
{
|
|
42
|
+
direction: "LR",
|
|
43
|
+
getNodeSize: (node) => {
|
|
44
|
+
const bNode = node;
|
|
45
|
+
if (BPMN_CONTAINER_TYPES.has(bNode.data.elementType)) return void 0;
|
|
46
|
+
return getBpmnNodeSize(bNode);
|
|
47
|
+
},
|
|
48
|
+
isContainerNode: (node) => BPMN_CONTAINER_TYPES.has(node.data.elementType),
|
|
49
|
+
getNodeLayoutOptions: (node) => {
|
|
50
|
+
const bNode = node;
|
|
51
|
+
const type = bNode.data.elementType;
|
|
52
|
+
if (!BPMN_CONTAINER_TYPES.has(type)) return void 0;
|
|
53
|
+
const min = CONTAINER_MIN_SIZE[type];
|
|
54
|
+
const isPoolWithLanes = type === "Pool" && poolsWithLanes.has(node.id);
|
|
55
|
+
const dir = isPoolWithLanes ? "DOWN" : "RIGHT";
|
|
56
|
+
return {
|
|
57
|
+
"elk.direction": dir,
|
|
58
|
+
"elk.nodeSize.constraints": "MINIMUM_SIZE",
|
|
59
|
+
// Each container handles its own layout pass so cross-lane edges
|
|
60
|
+
// participate in the internal layout without the global direction
|
|
61
|
+
// forcing Lane containers to align sideways.
|
|
62
|
+
"elk.hierarchyHandling": "INCLUDE_CHILDREN",
|
|
63
|
+
// Lanes within a Pool share a border — zero gap between them.
|
|
64
|
+
// Other containers keep the tighter inner spacing.
|
|
65
|
+
...isPoolWithLanes ? { "elk.spacing.nodeNode": "0", "elk.spacing.componentComponent": "0" } : {
|
|
66
|
+
"elk.layered.spacing.nodeNodeBetweenLayers": "100",
|
|
67
|
+
"elk.layered.spacing.edgeNodeBetweenLayers": "45",
|
|
68
|
+
"elk.spacing.nodeNode": "50"
|
|
69
|
+
},
|
|
70
|
+
...min ? { "elk.nodeSize.minimum": `[w=${min.w},h=${min.h}]` } : {},
|
|
71
|
+
...CONTAINER_PADDING[type] ? { "elk.padding": CONTAINER_PADDING[type] } : {}
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
elk: {
|
|
75
|
+
"elk.algorithm": "layered",
|
|
76
|
+
"elk.direction": "RIGHT",
|
|
77
|
+
// INHERIT: each container handles its own INCLUDE_CHILDREN pass so
|
|
78
|
+
// the global RIGHT direction does not force Lane containers sideways.
|
|
79
|
+
"elk.hierarchyHandling": "INHERIT",
|
|
80
|
+
"elk.edgeRouting": "ORTHOGONAL",
|
|
81
|
+
// Global spacing — generous values for visual breathing room.
|
|
82
|
+
"elk.layered.spacing.nodeNodeBetweenLayers": "120",
|
|
83
|
+
"elk.layered.spacing.edgeNodeBetweenLayers": "50",
|
|
84
|
+
"elk.spacing.nodeNode": "70",
|
|
85
|
+
"elk.spacing.componentComponent": "100"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
const nodeMap = new Map(result.nodes.map((n) => [n.id, n]));
|
|
90
|
+
const edgeMap = new Map(result.edges.map((e) => [e.id, e]));
|
|
91
|
+
const COMPONENT_GAP = 100;
|
|
92
|
+
const rootNodeOrder = nodes.filter((n) => !n.parentId).map((n) => n.id);
|
|
93
|
+
const rootHeights = /* @__PURE__ */ new Map();
|
|
94
|
+
for (const id of rootNodeOrder) {
|
|
95
|
+
const laid = nodeMap.get(id);
|
|
96
|
+
const orig = nodes.find((n) => n.id === id);
|
|
97
|
+
rootHeights.set(id, laid?.height ?? orig?.height ?? 200);
|
|
98
|
+
}
|
|
99
|
+
let stackY = 0;
|
|
100
|
+
const rootY = /* @__PURE__ */ new Map();
|
|
101
|
+
for (const id of rootNodeOrder) {
|
|
102
|
+
rootY.set(id, stackY);
|
|
103
|
+
stackY += (rootHeights.get(id) ?? 200) + COMPONENT_GAP;
|
|
104
|
+
}
|
|
105
|
+
const updatedNodes = nodes.map((node) => {
|
|
106
|
+
const laid = nodeMap.get(node.id);
|
|
107
|
+
if (!laid) return node;
|
|
108
|
+
const pos = node.parentId ? laid.position : { x: laid.position.x, y: rootY.get(node.id) ?? laid.position.y };
|
|
109
|
+
return { ...node, position: pos, width: laid.width, height: laid.height };
|
|
110
|
+
});
|
|
111
|
+
const lanesByPool = /* @__PURE__ */ new Map();
|
|
112
|
+
for (const node of updatedNodes) {
|
|
113
|
+
if (node.data.elementType === "Lane" && node.parentId) {
|
|
114
|
+
const arr = lanesByPool.get(node.parentId) ?? [];
|
|
115
|
+
arr.push(node.id);
|
|
116
|
+
lanesByPool.set(node.parentId, arr);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const nodeIndex = new Map(updatedNodes.map((n, i) => [n.id, i]));
|
|
120
|
+
for (const laneIds of lanesByPool.values()) {
|
|
121
|
+
const widths = laneIds.map((id) => updatedNodes[nodeIndex.get(id)]?.width ?? 0);
|
|
122
|
+
const maxWidth = Math.max(...widths);
|
|
123
|
+
if (maxWidth <= 0) continue;
|
|
124
|
+
for (const id of laneIds) {
|
|
125
|
+
const idx = nodeIndex.get(id);
|
|
126
|
+
if (idx !== void 0) {
|
|
127
|
+
updatedNodes[idx] = { ...updatedNodes[idx], width: maxWidth };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const nodeRootContainer = /* @__PURE__ */ new Map();
|
|
132
|
+
for (const node of updatedNodes) {
|
|
133
|
+
nodeRootContainer.set(node.id, node.parentId ?? null);
|
|
134
|
+
}
|
|
135
|
+
const getRootContainer = (nodeId) => {
|
|
136
|
+
let current = nodeId;
|
|
137
|
+
const visited = /* @__PURE__ */ new Set();
|
|
138
|
+
while (current) {
|
|
139
|
+
if (visited.has(current)) break;
|
|
140
|
+
visited.add(current);
|
|
141
|
+
const parent = nodeRootContainer.get(current);
|
|
142
|
+
if (!parent) return current;
|
|
143
|
+
current = parent;
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
};
|
|
147
|
+
const updatedEdges = edges.map((edge) => {
|
|
148
|
+
const laid = edgeMap.get(edge.id);
|
|
149
|
+
if (!laid) return edge;
|
|
150
|
+
const nextData = { ...edge.data };
|
|
151
|
+
const sourceRoot = getRootContainer(edge.source);
|
|
152
|
+
const targetRoot = getRootContainer(edge.target);
|
|
153
|
+
const isCrossPool = sourceRoot !== targetRoot;
|
|
154
|
+
if (!isCrossPool && laid.points && laid.points.length > 0) {
|
|
155
|
+
nextData.routingPoints = laid.points;
|
|
156
|
+
} else {
|
|
157
|
+
delete nextData.routingPoints;
|
|
158
|
+
}
|
|
159
|
+
return { ...edge, data: nextData };
|
|
160
|
+
});
|
|
161
|
+
return { nodes: updatedNodes, edges: updatedEdges };
|
|
162
|
+
}
|
|
163
|
+
|
|
8
164
|
// src/layout/bpmn-layout-graph.ts
|
|
9
165
|
var LAYOUT_CONTAINER_TYPES = /* @__PURE__ */ new Set([
|
|
10
166
|
"Pool",
|
|
@@ -22,15 +178,21 @@ var LAYOUT_GATEWAY_TYPES = /* @__PURE__ */ new Set([
|
|
|
22
178
|
"ComplexGateway"
|
|
23
179
|
]);
|
|
24
180
|
function detectBackEdges(nodeIds, seqEdges) {
|
|
181
|
+
const sortedIds = [...nodeIds].sort();
|
|
25
182
|
const backEdgeIds = /* @__PURE__ */ new Set();
|
|
26
183
|
const state = /* @__PURE__ */ new Map();
|
|
27
|
-
for (const id of
|
|
184
|
+
for (const id of sortedIds) state.set(id, 0);
|
|
28
185
|
const adj = /* @__PURE__ */ new Map();
|
|
29
|
-
for (const id of
|
|
186
|
+
for (const id of sortedIds) adj.set(id, []);
|
|
30
187
|
for (const e of seqEdges) {
|
|
31
188
|
adj.get(e.source)?.push({ target: e.target, edgeId: e.id });
|
|
32
189
|
}
|
|
33
|
-
for (const
|
|
190
|
+
for (const list of adj.values()) {
|
|
191
|
+
list.sort(
|
|
192
|
+
(a, b) => a.target < b.target ? -1 : a.target > b.target ? 1 : a.edgeId < b.edgeId ? -1 : a.edgeId > b.edgeId ? 1 : 0
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
for (const startId of sortedIds) {
|
|
34
196
|
if (state.get(startId) !== 0) continue;
|
|
35
197
|
const stack = [{ id: startId, idx: 0 }];
|
|
36
198
|
state.set(startId, 1);
|
|
@@ -107,9 +269,7 @@ function detectGatewayPairs(nodes, forwardEdges) {
|
|
|
107
269
|
}
|
|
108
270
|
const order = topologicalSort(nodeIds, forwardEdges);
|
|
109
271
|
const topoPos = new Map(order.map((id, i) => [id, i]));
|
|
110
|
-
const splits = nodes.filter(
|
|
111
|
-
(n) => LAYOUT_GATEWAY_TYPES.has(n.data.elementType) && (succs.get(n.id)?.length ?? 0) > 1
|
|
112
|
-
);
|
|
272
|
+
const splits = nodes.filter((n) => (succs.get(n.id)?.length ?? 0) > 1);
|
|
113
273
|
for (const split of splits) {
|
|
114
274
|
const branches = succs.get(split.id) ?? [];
|
|
115
275
|
if (branches.length < 2) continue;
|
|
@@ -161,12 +321,18 @@ function buildHandleMap(edges) {
|
|
|
161
321
|
}
|
|
162
322
|
return map;
|
|
163
323
|
}
|
|
324
|
+
function branchPullBias(nodeIds, nodeBias) {
|
|
325
|
+
if (!nodeBias) return null;
|
|
326
|
+
let sum = 0;
|
|
327
|
+
for (const id of nodeIds) sum += nodeBias.get(id) ?? 0;
|
|
328
|
+
if (sum === 0) return null;
|
|
329
|
+
return sum > 0 ? 1 : -1;
|
|
330
|
+
}
|
|
164
331
|
function pickMainBranch(branchData) {
|
|
165
332
|
if (branchData.length === 0) return void 0;
|
|
166
333
|
return [...branchData].sort((a, b) => {
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
if (aRight !== bRight) return bRight - aRight;
|
|
334
|
+
const rank = (branch) => branch.bias === 0 ? 2 : branch.bias === null ? 1 : 0;
|
|
335
|
+
if (rank(a) !== rank(b)) return rank(b) - rank(a);
|
|
170
336
|
if (a.nodeIds.length !== b.nodeIds.length) return b.nodeIds.length - a.nodeIds.length;
|
|
171
337
|
return a.start.localeCompare(b.start);
|
|
172
338
|
})[0]?.start;
|
|
@@ -207,7 +373,7 @@ function assignBranchRowsAroundMain(branchData, splitRow) {
|
|
|
207
373
|
}
|
|
208
374
|
return assigned;
|
|
209
375
|
}
|
|
210
|
-
function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
|
|
376
|
+
function assignRows(nodes, forwardEdges, columns, gatewayPairs, nodeBias) {
|
|
211
377
|
const rows = new Map(nodes.map((n) => [n.id, 0]));
|
|
212
378
|
const succs = new Map(nodes.map((n) => [n.id, []]));
|
|
213
379
|
for (const e of forwardEdges) {
|
|
@@ -215,7 +381,7 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
|
|
|
215
381
|
}
|
|
216
382
|
const handleMap = buildHandleMap(forwardEdges);
|
|
217
383
|
const sortedPairs = [...gatewayPairs.entries()].sort(
|
|
218
|
-
(a, b) => (columns.get(
|
|
384
|
+
(a, b) => (columns.get(a[0]) ?? 0) - (columns.get(b[0]) ?? 0)
|
|
219
385
|
);
|
|
220
386
|
for (const [splitId, mergeId] of sortedPairs) {
|
|
221
387
|
const branches = succs.get(splitId) ?? [];
|
|
@@ -235,11 +401,14 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
|
|
|
235
401
|
return result;
|
|
236
402
|
};
|
|
237
403
|
const splitHandles = handleMap.get(splitId);
|
|
238
|
-
const branchData = branches.map((start) =>
|
|
239
|
-
start
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
404
|
+
const branchData = branches.map((start) => {
|
|
405
|
+
const nodeIds = getBranchNodes(start);
|
|
406
|
+
return {
|
|
407
|
+
start,
|
|
408
|
+
nodeIds,
|
|
409
|
+
bias: handleToRowBias(splitHandles?.get(start) ?? null) ?? branchPullBias(nodeIds, nodeBias)
|
|
410
|
+
};
|
|
411
|
+
});
|
|
243
412
|
const assigned = assignBranchRowsAroundMain(branchData, splitRow);
|
|
244
413
|
for (const b of branchData) {
|
|
245
414
|
const row = assigned.get(b.start) ?? splitRow;
|
|
@@ -251,7 +420,7 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
|
|
|
251
420
|
}
|
|
252
421
|
const pairedSplits = new Set(gatewayPairs.keys());
|
|
253
422
|
const unpairedSplits = nodes.filter(
|
|
254
|
-
(n) =>
|
|
423
|
+
(n) => !pairedSplits.has(n.id) && (succs.get(n.id)?.length ?? 0) > 1
|
|
255
424
|
);
|
|
256
425
|
for (const split of unpairedSplits) {
|
|
257
426
|
const branches = succs.get(split.id) ?? [];
|
|
@@ -271,11 +440,14 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
|
|
|
271
440
|
return result;
|
|
272
441
|
};
|
|
273
442
|
const splitHandles2 = handleMap.get(split.id);
|
|
274
|
-
const branchData = branches.map((start) =>
|
|
275
|
-
start
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
443
|
+
const branchData = branches.map((start) => {
|
|
444
|
+
const nodeIds = getAllReachable(start);
|
|
445
|
+
return {
|
|
446
|
+
start,
|
|
447
|
+
nodeIds,
|
|
448
|
+
bias: handleToRowBias(splitHandles2?.get(start) ?? null) ?? branchPullBias(nodeIds, nodeBias)
|
|
449
|
+
};
|
|
450
|
+
});
|
|
279
451
|
const assigned2 = assignBranchRowsAroundMain(branchData, splitRow);
|
|
280
452
|
for (const b of branchData) {
|
|
281
453
|
const row = assigned2.get(b.start) ?? splitRow;
|
|
@@ -328,6 +500,17 @@ var LAYOUT_TASK_TYPES = /* @__PURE__ */ new Set([
|
|
|
328
500
|
]);
|
|
329
501
|
var TASK_LAYOUT_MIN_W = 130;
|
|
330
502
|
var TASK_LAYOUT_MIN_H = 80;
|
|
503
|
+
var SUBPROCESS_LAYOUT_MIN_W = 160;
|
|
504
|
+
var SUBPROCESS_LAYOUT_MIN_H = 80;
|
|
505
|
+
function layoutMinSize(node) {
|
|
506
|
+
if (LAYOUT_TASK_TYPES.has(node.data.elementType)) {
|
|
507
|
+
return { w: TASK_LAYOUT_MIN_W, h: TASK_LAYOUT_MIN_H };
|
|
508
|
+
}
|
|
509
|
+
if (COLLAPSED_SUBPROCESS_TYPES.has(node.data.elementType) && !node.data.isExpanded) {
|
|
510
|
+
return { w: SUBPROCESS_LAYOUT_MIN_W, h: SUBPROCESS_LAYOUT_MIN_H };
|
|
511
|
+
}
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
331
514
|
function nW(node) {
|
|
332
515
|
return node.width ?? node.measured?.width ?? 120;
|
|
333
516
|
}
|
|
@@ -335,18 +518,68 @@ function nH(node) {
|
|
|
335
518
|
return node.height ?? node.measured?.height ?? 60;
|
|
336
519
|
}
|
|
337
520
|
function layoutW(node) {
|
|
338
|
-
|
|
521
|
+
const min = layoutMinSize(node);
|
|
522
|
+
return min ? Math.max(nW(node), min.w) : nW(node);
|
|
339
523
|
}
|
|
340
524
|
function layoutH(node) {
|
|
341
|
-
|
|
525
|
+
const min = layoutMinSize(node);
|
|
526
|
+
return min ? Math.max(nH(node), min.h) : nH(node);
|
|
527
|
+
}
|
|
528
|
+
var LABEL_RESERVE_TYPES = /* @__PURE__ */ new Set([
|
|
529
|
+
...LAYOUT_GATEWAY_TYPES,
|
|
530
|
+
"StartEvent",
|
|
531
|
+
"EndEvent",
|
|
532
|
+
"IntermediateCatchEvent",
|
|
533
|
+
"IntermediateThrowEvent"
|
|
534
|
+
]);
|
|
535
|
+
var LABEL_CHAR_W = 6.5;
|
|
536
|
+
var LABEL_RESERVE_MAX = 150;
|
|
537
|
+
function columnW(node) {
|
|
538
|
+
const base = layoutW(node);
|
|
539
|
+
if (!LABEL_RESERVE_TYPES.has(node.data.elementType)) return base;
|
|
540
|
+
const label = typeof node.data.label === "string" ? node.data.label : "";
|
|
541
|
+
if (!label) return base;
|
|
542
|
+
const reserve = Math.min(Math.ceil(label.length * LABEL_CHAR_W), LABEL_RESERVE_MAX);
|
|
543
|
+
return Math.max(base, reserve);
|
|
342
544
|
}
|
|
343
545
|
function applyLayoutMinSize(node) {
|
|
344
|
-
if (!
|
|
546
|
+
if (!layoutMinSize(node)) return node;
|
|
345
547
|
const w = layoutW(node);
|
|
346
548
|
const h = layoutH(node);
|
|
347
549
|
if (w === nW(node) && h === nH(node)) return node;
|
|
348
550
|
return { ...node, width: w, height: h, measured: { width: w, height: h } };
|
|
349
551
|
}
|
|
552
|
+
function computeRowMetrics(contextNodes, rows, includeRowZero) {
|
|
553
|
+
const vals = contextNodes.map((n) => rows.get(n.id) ?? 0);
|
|
554
|
+
const base = includeRowZero ? [0, ...vals] : vals;
|
|
555
|
+
const minRow = Math.min(...base);
|
|
556
|
+
const maxRow = Math.max(...base);
|
|
557
|
+
const rowH = /* @__PURE__ */ new Map();
|
|
558
|
+
for (let r = minRow; r <= maxRow; r++) rowH.set(r, ROW_HEIGHT);
|
|
559
|
+
for (const node of contextNodes) {
|
|
560
|
+
const r = rows.get(node.id) ?? 0;
|
|
561
|
+
rowH.set(r, Math.max(rowH.get(r) ?? ROW_HEIGHT, layoutH(node)));
|
|
562
|
+
}
|
|
563
|
+
const rowY = /* @__PURE__ */ new Map();
|
|
564
|
+
let y = 0;
|
|
565
|
+
for (let r = minRow; r <= maxRow; r++) {
|
|
566
|
+
rowY.set(r, y);
|
|
567
|
+
y += (rowH.get(r) ?? ROW_HEIGHT) + ROW_GAP;
|
|
568
|
+
}
|
|
569
|
+
return { minRow, maxRow, rowH, rowY, contentH: y - ROW_GAP };
|
|
570
|
+
}
|
|
571
|
+
function reanchorBoundaryEdges(edges, boundaryEvents, contentIds) {
|
|
572
|
+
if (boundaryEvents.length === 0) return edges;
|
|
573
|
+
const hostByBoundaryId = /* @__PURE__ */ new Map();
|
|
574
|
+
for (const be of boundaryEvents) {
|
|
575
|
+
if (be.data.attachedToRef) hostByBoundaryId.set(be.id, be.data.attachedToRef);
|
|
576
|
+
}
|
|
577
|
+
if (hostByBoundaryId.size === 0) return edges;
|
|
578
|
+
return edges.map((edge) => {
|
|
579
|
+
const host = hostByBoundaryId.get(edge.source);
|
|
580
|
+
return host && contentIds.has(host) ? { ...edge, source: host, sourceHandle: "source-bottom" } : edge;
|
|
581
|
+
});
|
|
582
|
+
}
|
|
350
583
|
var BOUNDARY_SPACING = 10;
|
|
351
584
|
function repositionBoundaryEvents(boundaryEvents, positionedContent) {
|
|
352
585
|
if (boundaryEvents.length === 0) return [];
|
|
@@ -403,7 +636,8 @@ function layoutSubProcess(children, edges) {
|
|
|
403
636
|
};
|
|
404
637
|
}
|
|
405
638
|
const contentIds = new Set(mainChildren.map((n) => n.id));
|
|
406
|
-
const
|
|
639
|
+
const graphEdges = reanchorBoundaryEdges(edges, boundaryEvents, contentIds);
|
|
640
|
+
const seqEdges = extractSeqEdges(graphEdges, contentIds);
|
|
407
641
|
const backIds = detectBackEdges([...contentIds], seqEdges);
|
|
408
642
|
const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
|
|
409
643
|
const columns = assignColumns([...contentIds], fwdEdges);
|
|
@@ -414,7 +648,7 @@ function layoutSubProcess(children, edges) {
|
|
|
414
648
|
for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
|
|
415
649
|
for (const node of mainChildren) {
|
|
416
650
|
const c = columns.get(node.id) ?? 0;
|
|
417
|
-
colW.set(c, Math.max(colW.get(c) ?? 0,
|
|
651
|
+
colW.set(c, Math.max(colW.get(c) ?? 0, columnW(node)));
|
|
418
652
|
}
|
|
419
653
|
const colX = /* @__PURE__ */ new Map();
|
|
420
654
|
let cumX = 0;
|
|
@@ -423,20 +657,16 @@ function layoutSubProcess(children, edges) {
|
|
|
423
657
|
cumX += (colW.get(c) ?? 120) + COL_GAP;
|
|
424
658
|
}
|
|
425
659
|
const contentW = cumX - COL_GAP;
|
|
426
|
-
const
|
|
427
|
-
const minRow = Math.min(0, ...rowVals);
|
|
428
|
-
const maxRow = Math.max(0, ...rowVals);
|
|
429
|
-
const rowCount = maxRow - minRow + 1;
|
|
430
|
-
const contentH = rowCount * ROW_HEIGHT + Math.max(0, rowCount - 1) * ROW_GAP;
|
|
660
|
+
const rowMetrics = computeRowMetrics(mainChildren, rows, true);
|
|
431
661
|
const spW = Math.max(280, SP_PAD * 2 + contentW);
|
|
432
|
-
const spH = Math.max(160, SP_PAD * 2 + contentH);
|
|
662
|
+
const spH = Math.max(160, SP_PAD * 2 + rowMetrics.contentH);
|
|
433
663
|
const positionedChildren = mainChildren.map((node) => {
|
|
434
664
|
const c = columns.get(node.id) ?? 0;
|
|
435
665
|
const r = rows.get(node.id) ?? 0;
|
|
436
666
|
const lw = layoutW(node);
|
|
437
667
|
const lh = layoutH(node);
|
|
438
668
|
const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - lw / 2;
|
|
439
|
-
const rowOffset = (r
|
|
669
|
+
const rowOffset = (rowMetrics.rowY.get(r) ?? 0) + (rowMetrics.rowH.get(r) ?? ROW_HEIGHT) / 2 - lh / 2;
|
|
440
670
|
return applyLayoutMinSize({ ...node, position: { x: SP_PAD + colOffset, y: SP_PAD + rowOffset } });
|
|
441
671
|
});
|
|
442
672
|
const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, positionedChildren);
|
|
@@ -479,7 +709,8 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
479
709
|
nodeLaneId.set(node.id, lId);
|
|
480
710
|
}
|
|
481
711
|
const contentIds = new Set(mainContent.map((n) => n.id));
|
|
482
|
-
const
|
|
712
|
+
const graphEdges = reanchorBoundaryEdges(allEdges, boundaryEvents, contentIds);
|
|
713
|
+
const seqEdges = extractSeqEdges(graphEdges, contentIds);
|
|
483
714
|
const backIds = detectBackEdges([...contentIds], seqEdges);
|
|
484
715
|
const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
|
|
485
716
|
const columns = assignColumns([...contentIds], fwdEdges);
|
|
@@ -490,28 +721,67 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
490
721
|
if (!contentByLane.has(lId)) contentByLane.set(lId, []);
|
|
491
722
|
contentByLane.get(lId).push(node);
|
|
492
723
|
}
|
|
724
|
+
const laneStackIndex = /* @__PURE__ */ new Map();
|
|
725
|
+
sortedLanes.forEach((laneNode, index) => laneStackIndex.set(laneNode.id, index));
|
|
726
|
+
laneStackIndex.set("_pool_", sortedLanes.length);
|
|
727
|
+
const crossLanePull = /* @__PURE__ */ new Map();
|
|
728
|
+
for (const e of fwdEdges) {
|
|
729
|
+
const sLane = nodeLaneId.get(e.source) ?? "_pool_";
|
|
730
|
+
const tLane = nodeLaneId.get(e.target) ?? "_pool_";
|
|
731
|
+
if (sLane === tLane) continue;
|
|
732
|
+
const dir = Math.sign((laneStackIndex.get(tLane) ?? 0) - (laneStackIndex.get(sLane) ?? 0));
|
|
733
|
+
crossLanePull.set(e.source, (crossLanePull.get(e.source) ?? 0) + dir);
|
|
734
|
+
crossLanePull.set(e.target, (crossLanePull.get(e.target) ?? 0) - dir);
|
|
735
|
+
}
|
|
493
736
|
for (const [, laneNodes] of contentByLane) {
|
|
494
737
|
const laneNodeIds = new Set(laneNodes.map((n) => n.id));
|
|
495
738
|
const intraEdges = fwdEdges.filter(
|
|
496
739
|
(e) => laneNodeIds.has(e.source) && laneNodeIds.has(e.target)
|
|
497
740
|
);
|
|
498
741
|
const lanePairs = detectGatewayPairs(laneNodes, intraEdges);
|
|
499
|
-
const laneRows = assignRows(laneNodes, intraEdges, columns, lanePairs);
|
|
742
|
+
const laneRows = assignRows(laneNodes, intraEdges, columns, lanePairs, crossLanePull);
|
|
500
743
|
for (const [id, row] of laneRows) rows.set(id, row);
|
|
501
744
|
}
|
|
502
|
-
const
|
|
745
|
+
const seqTouched = /* @__PURE__ */ new Set();
|
|
746
|
+
for (const e of seqEdges) {
|
|
747
|
+
seqTouched.add(e.source);
|
|
748
|
+
seqTouched.add(e.target);
|
|
749
|
+
}
|
|
750
|
+
for (const [, laneNodes] of contentByLane) {
|
|
751
|
+
const eventSPs = laneNodes.filter(
|
|
752
|
+
(n) => n.data.elementType === "EventSubProcess" && !seqTouched.has(n.id)
|
|
753
|
+
);
|
|
754
|
+
if (eventSPs.length === 0) continue;
|
|
755
|
+
const eventSpIds = new Set(eventSPs.map((n) => n.id));
|
|
756
|
+
const otherRows = laneNodes.filter((n) => !eventSpIds.has(n.id)).map((n) => rows.get(n.id) ?? 0);
|
|
757
|
+
const laneMaxRow = otherRows.length > 0 ? Math.max(...otherRows) : -1;
|
|
758
|
+
for (const sp of eventSPs) rows.set(sp.id, laneMaxRow + 1);
|
|
759
|
+
}
|
|
760
|
+
const hasPoolDirectContent = [...nodeLaneId.values()].includes("_pool_");
|
|
761
|
+
const laneIds = hasLanes ? [...sortedLanes.map((l) => l.id), ...hasPoolDirectContent ? ["_pool_"] : []] : ["_pool_"];
|
|
503
762
|
const laneStats = /* @__PURE__ */ new Map();
|
|
504
763
|
for (const laneId of laneIds) {
|
|
505
|
-
const
|
|
506
|
-
if (
|
|
507
|
-
laneStats.set(laneId, {
|
|
764
|
+
const laneNodes = mainContent.filter((n) => nodeLaneId.get(n.id) === laneId);
|
|
765
|
+
if (laneNodes.length === 0) {
|
|
766
|
+
laneStats.set(laneId, {
|
|
767
|
+
minRow: 0,
|
|
768
|
+
maxRow: 0,
|
|
769
|
+
height: LANE_MIN_H,
|
|
770
|
+
contentH: ROW_HEIGHT,
|
|
771
|
+
rowH: /* @__PURE__ */ new Map([[0, ROW_HEIGHT]]),
|
|
772
|
+
rowY: /* @__PURE__ */ new Map([[0, 0]])
|
|
773
|
+
});
|
|
508
774
|
} else {
|
|
509
|
-
const
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
775
|
+
const m = computeRowMetrics(laneNodes, rows, false);
|
|
776
|
+
const height = Math.max(LANE_MIN_H, LANE_V_PAD * 2 + m.contentH);
|
|
777
|
+
laneStats.set(laneId, {
|
|
778
|
+
minRow: m.minRow,
|
|
779
|
+
maxRow: m.maxRow,
|
|
780
|
+
height,
|
|
781
|
+
contentH: m.contentH,
|
|
782
|
+
rowH: m.rowH,
|
|
783
|
+
rowY: m.rowY
|
|
784
|
+
});
|
|
515
785
|
}
|
|
516
786
|
}
|
|
517
787
|
const laneColumnLayouts = /* @__PURE__ */ new Map();
|
|
@@ -524,7 +794,7 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
524
794
|
for (const col of usedCols) colW.set(col, 0);
|
|
525
795
|
for (const node of laneNodes) {
|
|
526
796
|
const col = columns.get(node.id) ?? 0;
|
|
527
|
-
colW.set(col, Math.max(colW.get(col) ?? 0,
|
|
797
|
+
colW.set(col, Math.max(colW.get(col) ?? 0, columnW(node)));
|
|
528
798
|
}
|
|
529
799
|
const colX = /* @__PURE__ */ new Map();
|
|
530
800
|
let laneCumX = 0;
|
|
@@ -571,9 +841,8 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
571
841
|
const lw = layoutW(node);
|
|
572
842
|
const lh = layoutH(node);
|
|
573
843
|
const colOffset = (laneLayout?.colX.get(c) ?? 0) + (laneLayout?.colW.get(c) ?? 120) / 2 - lw / 2;
|
|
574
|
-
const rowOffset = (
|
|
575
|
-
const
|
|
576
|
-
const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - contentH_stat) / 2);
|
|
844
|
+
const rowOffset = (stat.rowY.get(r) ?? 0) + (stat.rowH.get(r) ?? ROW_HEIGHT) / 2 - lh / 2;
|
|
845
|
+
const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - stat.contentH) / 2);
|
|
577
846
|
const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
|
|
578
847
|
const x = isLaneChild ? LANE_LABEL_W + LANE_H_PAD + colOffset : POOL_H_PAD + colOffset;
|
|
579
848
|
const y = isLaneChild ? vertTopOffset + rowOffset : lYOff + vertTopOffset + rowOffset;
|
|
@@ -709,6 +978,17 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
709
978
|
height: poolH
|
|
710
979
|
};
|
|
711
980
|
}
|
|
981
|
+
function layoutVirtualContext(contextNodes, allEdges, offsetY) {
|
|
982
|
+
if (contextNodes.length === 0) return [];
|
|
983
|
+
const virtualPool = {
|
|
984
|
+
id: "__bpmn_virtual_pool__"};
|
|
985
|
+
const result = layoutPool(virtualPool, [], contextNodes, allEdges);
|
|
986
|
+
if (offsetY === 0) return result.nodes;
|
|
987
|
+
return result.nodes.map((n) => ({
|
|
988
|
+
...n,
|
|
989
|
+
position: { x: n.position.x, y: n.position.y + offsetY }
|
|
990
|
+
}));
|
|
991
|
+
}
|
|
712
992
|
function absolutePos(nodeId, byId, cache) {
|
|
713
993
|
const cached = cache.get(nodeId);
|
|
714
994
|
if (cached) return cached;
|
|
@@ -783,15 +1063,113 @@ function routeMidX(sAbs, sW, tAbs, tW) {
|
|
|
783
1063
|
const rightEdge = Math.max(sAbs.x, tAbs.x);
|
|
784
1064
|
return leftEdge < rightEdge ? leftEdge + (rightEdge - leftEdge) * 0.35 : sAbs.x + sW / 2;
|
|
785
1065
|
}
|
|
1066
|
+
var HANDLE_SIDES = ["right", "left", "top", "bottom"];
|
|
1067
|
+
function borderHandle(point, rect, kind) {
|
|
1068
|
+
const dist = {
|
|
1069
|
+
right: Math.abs(point.x - (rect.x + rect.w)),
|
|
1070
|
+
left: Math.abs(point.x - rect.x),
|
|
1071
|
+
top: Math.abs(point.y - rect.y),
|
|
1072
|
+
bottom: Math.abs(point.y - (rect.y + rect.h))
|
|
1073
|
+
};
|
|
1074
|
+
let side = "right";
|
|
1075
|
+
let best = Infinity;
|
|
1076
|
+
for (const s of HANDLE_SIDES) {
|
|
1077
|
+
if (dist[s] < best) {
|
|
1078
|
+
best = dist[s];
|
|
1079
|
+
side = s;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
return `${kind}-${side}`;
|
|
1083
|
+
}
|
|
786
1084
|
var SAME_ROW_THRESHOLD = 15;
|
|
787
1085
|
function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
788
1086
|
const byId = new Map(layoutNodes.map((n) => [n.id, n]));
|
|
789
1087
|
const cache = /* @__PURE__ */ new Map();
|
|
790
1088
|
const abs = (id) => absolutePos(id, byId, cache);
|
|
1089
|
+
const handlesFor = (srcId, tgtId, pts) => {
|
|
1090
|
+
if (pts.length < 2) return {};
|
|
1091
|
+
const s = byId.get(srcId), t = byId.get(tgtId);
|
|
1092
|
+
if (!s || !t) return {};
|
|
1093
|
+
const sa = abs(srcId), ta = abs(tgtId);
|
|
1094
|
+
return {
|
|
1095
|
+
sourceHandle: borderHandle(pts[0], { x: sa.x, y: sa.y, w: nW(s), h: nH(s) }, "source"),
|
|
1096
|
+
targetHandle: borderHandle(pts[pts.length - 1], { x: ta.x, y: ta.y, w: nW(t), h: nH(t) }, "target")
|
|
1097
|
+
};
|
|
1098
|
+
};
|
|
791
1099
|
const sortedLanes = [...laneIds].map((id) => byId.get(id)).filter((n) => !!n).sort((a, b) => abs(a.id).y - abs(b.id).y);
|
|
792
|
-
|
|
1100
|
+
const contentInfos = layoutNodes.filter((n) => !poolIds.has(n.id) && !laneIds.has(n.id)).map((n) => {
|
|
1101
|
+
const p = abs(n.id);
|
|
1102
|
+
return { id: n.id, x: p.x, y: p.y, w: nW(n), h: nH(n), poolId: poolOf(n, poolIds, byId) ?? null };
|
|
1103
|
+
});
|
|
1104
|
+
const findClearX = (desiredX, y0, y1, minX, maxX, excludeA, excludeB, poolId) => {
|
|
1105
|
+
if (minX > maxX) return desiredX;
|
|
1106
|
+
const clampX = (x) => Math.min(maxX, Math.max(minX, x));
|
|
1107
|
+
const blockers = contentInfos.filter(
|
|
1108
|
+
(c) => c.poolId === poolId && c.id !== excludeA && c.id !== excludeB && c.y < y1 && c.y + c.h > y0
|
|
1109
|
+
);
|
|
1110
|
+
const isFree = (x) => blockers.every((c) => x < c.x - 4 || x > c.x + c.w + 4);
|
|
1111
|
+
const clamped = clampX(desiredX);
|
|
1112
|
+
if (isFree(clamped)) return clamped;
|
|
1113
|
+
const candidates = [];
|
|
1114
|
+
for (const c of blockers) candidates.push(c.x - 8, c.x + c.w + 8);
|
|
1115
|
+
const free = candidates.map(clampX).filter(isFree).sort((a, b) => Math.abs(a - desiredX) - Math.abs(b - desiredX));
|
|
1116
|
+
return free.length > 0 ? free[0] : clamped;
|
|
1117
|
+
};
|
|
1118
|
+
const backEdgeOrder = /* @__PURE__ */ new Map();
|
|
1119
|
+
for (const edge of [...edges].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0)) {
|
|
1120
|
+
if (backEdgeIds.has(edge.id)) backEdgeOrder.set(edge.id, backEdgeOrder.size);
|
|
1121
|
+
}
|
|
1122
|
+
const routeMessageFlow = (edge) => {
|
|
1123
|
+
const src = byId.get(edge.source);
|
|
1124
|
+
const tgt = byId.get(edge.target);
|
|
1125
|
+
if (!src || !tgt) return null;
|
|
1126
|
+
const srcPoolId = poolOf(src, poolIds, byId);
|
|
1127
|
+
const tgtPoolId = poolOf(tgt, poolIds, byId);
|
|
1128
|
+
if (!srcPoolId || !tgtPoolId || srcPoolId === tgtPoolId) return null;
|
|
1129
|
+
const srcPoolNode = byId.get(srcPoolId);
|
|
1130
|
+
const tgtPoolNode = byId.get(tgtPoolId);
|
|
1131
|
+
if (!srcPoolNode || !tgtPoolNode) return null;
|
|
1132
|
+
const sAbs = abs(src.id);
|
|
1133
|
+
const tAbs = abs(tgt.id);
|
|
1134
|
+
const sCX = sAbs.x + nW(src) / 2;
|
|
1135
|
+
const tCX = tAbs.x + nW(tgt) / 2;
|
|
1136
|
+
const srcPoolAbs = abs(srcPoolId);
|
|
1137
|
+
const tgtPoolAbs = abs(tgtPoolId);
|
|
1138
|
+
const srcPoolBottom = srcPoolAbs.y + nH(srcPoolNode);
|
|
1139
|
+
const tgtPoolBottom = tgtPoolAbs.y + nH(tgtPoolNode);
|
|
1140
|
+
if (tgtPoolAbs.y >= srcPoolBottom) {
|
|
1141
|
+
const corridorY = (srcPoolBottom + tgtPoolAbs.y) / 2;
|
|
1142
|
+
return [
|
|
1143
|
+
{ x: sCX, y: sAbs.y + nH(src) },
|
|
1144
|
+
{ x: sCX, y: corridorY },
|
|
1145
|
+
{ x: tCX, y: corridorY },
|
|
1146
|
+
{ x: tCX, y: tAbs.y }
|
|
1147
|
+
];
|
|
1148
|
+
}
|
|
1149
|
+
if (srcPoolAbs.y >= tgtPoolBottom) {
|
|
1150
|
+
const corridorY = (tgtPoolBottom + srcPoolAbs.y) / 2;
|
|
1151
|
+
return [
|
|
1152
|
+
{ x: sCX, y: sAbs.y },
|
|
1153
|
+
{ x: sCX, y: corridorY },
|
|
1154
|
+
{ x: tCX, y: corridorY },
|
|
1155
|
+
{ x: tCX, y: tAbs.y + nH(tgt) }
|
|
1156
|
+
];
|
|
1157
|
+
}
|
|
1158
|
+
return null;
|
|
1159
|
+
};
|
|
1160
|
+
const routed = edges.map((edge) => {
|
|
793
1161
|
const edgeType = edge.data?.edgeType ?? edge.type;
|
|
794
1162
|
if (edgeType !== "sequenceFlow") {
|
|
1163
|
+
if (edgeType === "messageFlow") {
|
|
1164
|
+
const pts = routeMessageFlow(edge);
|
|
1165
|
+
if (pts) {
|
|
1166
|
+
return {
|
|
1167
|
+
...edge,
|
|
1168
|
+
...handlesFor(edge.source, edge.target, pts),
|
|
1169
|
+
data: { ...edge.data, routingPoints: pts }
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
795
1173
|
const d = { ...edge.data };
|
|
796
1174
|
delete d.routingPoints;
|
|
797
1175
|
return { ...edge, data: d };
|
|
@@ -816,7 +1194,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
816
1194
|
}
|
|
817
1195
|
let routingPoints;
|
|
818
1196
|
if (backEdgeIds.has(edge.id)) {
|
|
819
|
-
const
|
|
1197
|
+
const spanMinX = Math.min(tAbs.x, sAbs.x) - EDGE_ROUTE_PAD;
|
|
1198
|
+
const spanMaxX = Math.max(tAbs.x + tW, sAbs.x + sW) + EDGE_ROUTE_PAD;
|
|
1199
|
+
let topMost = Math.min(sAbs.y, tAbs.y);
|
|
1200
|
+
for (const cand of contentInfos) {
|
|
1201
|
+
if (cand.poolId !== srcPool) continue;
|
|
1202
|
+
if (cand.x + cand.w < spanMinX || cand.x > spanMaxX) continue;
|
|
1203
|
+
topMost = Math.min(topMost, cand.y);
|
|
1204
|
+
}
|
|
1205
|
+
const stagger = (backEdgeOrder.get(edge.id) ?? 0) * 14;
|
|
1206
|
+
const topY = topMost - BACK_EDGE_CLEARANCE - stagger;
|
|
820
1207
|
routingPoints = [
|
|
821
1208
|
{ x: sAbs.x + sW, y: sCY },
|
|
822
1209
|
{ x: sAbs.x + sW + EDGE_ROUTE_PAD, y: sCY },
|
|
@@ -830,7 +1217,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
830
1217
|
const tgtLane = byId.get(laneOf(tgt, laneIds, byId) ?? "");
|
|
831
1218
|
if (srcLane && tgtLane && laneIds.has(srcLane.id) && laneIds.has(tgtLane.id)) {
|
|
832
1219
|
const goingDown = tAbs.y > sAbs.y;
|
|
833
|
-
const sharedX =
|
|
1220
|
+
const sharedX = findClearX(
|
|
1221
|
+
gapMidX(sAbs, sW, tAbs, tW),
|
|
1222
|
+
Math.min(sCY, tCY),
|
|
1223
|
+
Math.max(sCY, tCY),
|
|
1224
|
+
sAbs.x + sW + 6,
|
|
1225
|
+
tAbs.x - EDGE_ROUTE_PAD - 4,
|
|
1226
|
+
src.id,
|
|
1227
|
+
tgt.id,
|
|
1228
|
+
srcPool
|
|
1229
|
+
);
|
|
834
1230
|
const srcLaneIdx = sortedLanes.findIndex((l) => l.id === srcLane.id);
|
|
835
1231
|
const tgtLaneIdx = sortedLanes.findIndex((l) => l.id === tgtLane.id);
|
|
836
1232
|
const pts = [];
|
|
@@ -865,7 +1261,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
865
1261
|
}
|
|
866
1262
|
routingPoints = pts;
|
|
867
1263
|
} else {
|
|
868
|
-
const sharedX =
|
|
1264
|
+
const sharedX = findClearX(
|
|
1265
|
+
gapMidX(sAbs, sW, tAbs, tW),
|
|
1266
|
+
Math.min(sCY, tCY),
|
|
1267
|
+
Math.max(sCY, tCY),
|
|
1268
|
+
sAbs.x + sW + 6,
|
|
1269
|
+
tAbs.x - 6,
|
|
1270
|
+
src.id,
|
|
1271
|
+
tgt.id,
|
|
1272
|
+
srcPool
|
|
1273
|
+
);
|
|
869
1274
|
routingPoints = [
|
|
870
1275
|
{ x: sAbs.x + sW, y: sCY },
|
|
871
1276
|
{ x: sharedX, y: sCY },
|
|
@@ -876,7 +1281,13 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
876
1281
|
} else if (Math.abs(sCY - tCY) <= SAME_ROW_THRESHOLD) {
|
|
877
1282
|
const d = { ...edge.data };
|
|
878
1283
|
delete d.routingPoints;
|
|
879
|
-
|
|
1284
|
+
const goesRight = tCX >= sCX;
|
|
1285
|
+
return {
|
|
1286
|
+
...edge,
|
|
1287
|
+
sourceHandle: goesRight ? "source-right" : "source-left",
|
|
1288
|
+
targetHandle: goesRight ? "target-left" : "target-right",
|
|
1289
|
+
data: d
|
|
1290
|
+
};
|
|
880
1291
|
} else {
|
|
881
1292
|
const handle = edge.sourceHandle ?? "";
|
|
882
1293
|
const exitsTop = handle.includes("top");
|
|
@@ -895,7 +1306,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
895
1306
|
const midX = routeMidX(sAbs, sW, tAbs, tW);
|
|
896
1307
|
const exitX = sAbs.x + sW;
|
|
897
1308
|
const entryX = tAbs.x;
|
|
898
|
-
const corridorX =
|
|
1309
|
+
const corridorX = findClearX(
|
|
1310
|
+
Math.max(midX, exitX + EDGE_ROUTE_PAD),
|
|
1311
|
+
Math.min(sCY, tCY),
|
|
1312
|
+
Math.max(sCY, tCY),
|
|
1313
|
+
exitX + 6,
|
|
1314
|
+
entryX - 6,
|
|
1315
|
+
src.id,
|
|
1316
|
+
tgt.id,
|
|
1317
|
+
srcPool
|
|
1318
|
+
);
|
|
899
1319
|
routingPoints = [
|
|
900
1320
|
{ x: exitX, y: sCY },
|
|
901
1321
|
{ x: corridorX, y: sCY },
|
|
@@ -904,11 +1324,87 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
904
1324
|
];
|
|
905
1325
|
}
|
|
906
1326
|
}
|
|
907
|
-
return {
|
|
1327
|
+
return {
|
|
1328
|
+
...edge,
|
|
1329
|
+
...handlesFor(edge.source, edge.target, routingPoints),
|
|
1330
|
+
data: { ...edge.data, routingPoints }
|
|
1331
|
+
};
|
|
1332
|
+
});
|
|
1333
|
+
return spreadVerticalChannels(routed);
|
|
1334
|
+
}
|
|
1335
|
+
var CHANNEL_GAP = 10;
|
|
1336
|
+
var CHANNEL_CLUSTER_TOL = 8;
|
|
1337
|
+
function spreadVerticalChannels(edges) {
|
|
1338
|
+
const runs = [];
|
|
1339
|
+
edges.forEach((edge, edgeIdx) => {
|
|
1340
|
+
const pts = edge.data?.routingPoints;
|
|
1341
|
+
if (!pts || pts.length < 4) return;
|
|
1342
|
+
let i = 1;
|
|
1343
|
+
while (i < pts.length) {
|
|
1344
|
+
let j = i;
|
|
1345
|
+
while (j < pts.length && Math.abs(pts[j].x - pts[j - 1].x) <= 0.5) j++;
|
|
1346
|
+
if (j > i) {
|
|
1347
|
+
const fromIdx = i - 1;
|
|
1348
|
+
const toIdx = j - 1;
|
|
1349
|
+
if (fromIdx > 0 && toIdx < pts.length - 1) {
|
|
1350
|
+
const ys = pts.slice(fromIdx, toIdx + 1).map((p) => p.y);
|
|
1351
|
+
const y0 = Math.min(...ys);
|
|
1352
|
+
const y1 = Math.max(...ys);
|
|
1353
|
+
if (y1 - y0 >= 4) {
|
|
1354
|
+
runs.push({ edgeIdx, fromIdx, toIdx, x: pts[fromIdx].x, y0, y1 });
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
i = j + 1;
|
|
1358
|
+
} else {
|
|
1359
|
+
i++;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
if (runs.length < 2) return edges;
|
|
1364
|
+
runs.sort((a, b) => a.x - b.x);
|
|
1365
|
+
const clusters = [];
|
|
1366
|
+
for (const run of runs) {
|
|
1367
|
+
const last = clusters[clusters.length - 1];
|
|
1368
|
+
if (last && run.x - last[0].x <= CHANNEL_CLUSTER_TOL) last.push(run);
|
|
1369
|
+
else clusters.push([run]);
|
|
1370
|
+
}
|
|
1371
|
+
const offsets = /* @__PURE__ */ new Map();
|
|
1372
|
+
for (const cluster of clusters) {
|
|
1373
|
+
if (cluster.length < 2) continue;
|
|
1374
|
+
const colliding = cluster.filter(
|
|
1375
|
+
(run) => cluster.some((other) => other !== run && run.y0 < other.y1 && other.y0 < run.y1)
|
|
1376
|
+
);
|
|
1377
|
+
if (colliding.length < 2) continue;
|
|
1378
|
+
const ordered = [...colliding].sort((a, b) => {
|
|
1379
|
+
const idA = edges[a.edgeIdx].id;
|
|
1380
|
+
const idB = edges[b.edgeIdx].id;
|
|
1381
|
+
return idA < idB ? -1 : idA > idB ? 1 : a.fromIdx - b.fromIdx;
|
|
1382
|
+
});
|
|
1383
|
+
ordered.forEach((run, k) => {
|
|
1384
|
+
const off = Math.round((k - (ordered.length - 1) / 2) * CHANNEL_GAP);
|
|
1385
|
+
if (off !== 0) offsets.set(run, off);
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
if (offsets.size === 0) return edges;
|
|
1389
|
+
const runsByEdge = /* @__PURE__ */ new Map();
|
|
1390
|
+
for (const [run, off] of offsets) {
|
|
1391
|
+
if (!runsByEdge.has(run.edgeIdx)) runsByEdge.set(run.edgeIdx, []);
|
|
1392
|
+
runsByEdge.get(run.edgeIdx).push(run);
|
|
1393
|
+
}
|
|
1394
|
+
return edges.map((edge, edgeIdx) => {
|
|
1395
|
+
const edgeRuns = runsByEdge.get(edgeIdx);
|
|
1396
|
+
if (!edgeRuns) return edge;
|
|
1397
|
+
const pts = (edge.data?.routingPoints).map((p) => ({ ...p }));
|
|
1398
|
+
for (const run of edgeRuns) {
|
|
1399
|
+
const off = offsets.get(run);
|
|
1400
|
+
for (let p = run.fromIdx; p <= run.toIdx; p++) pts[p].x += off;
|
|
1401
|
+
}
|
|
1402
|
+
return { ...edge, data: { ...edge.data, routingPoints: pts } };
|
|
908
1403
|
});
|
|
909
1404
|
}
|
|
910
1405
|
var ARTIFACT_ABOVE_GAP = 16;
|
|
911
1406
|
var ARTIFACT_H_SPACING = 12;
|
|
1407
|
+
var ARTIFACT_EDGE_PAD = 4;
|
|
912
1408
|
function positionArtifacts(artifacts, resultNodes, edges, originalNodes) {
|
|
913
1409
|
if (artifacts.length === 0) return [];
|
|
914
1410
|
const byId = new Map(resultNodes.map((n) => [n.id, n]));
|
|
@@ -949,11 +1445,21 @@ function positionArtifacts(artifacts, resultNodes, edges, originalNodes) {
|
|
|
949
1445
|
let desiredAbsX = connAbsP.x + nW(connNode) / 2 - totalW / 2;
|
|
950
1446
|
for (const artifact of arts) {
|
|
951
1447
|
const parentAbsP = artifact.parentId ? absPos(artifact.parentId) : { x: 0, y: 0 };
|
|
1448
|
+
let relY = desiredAbsY - parentAbsP.y;
|
|
1449
|
+
const parentNode = artifact.parentId ? byId.get(artifact.parentId) : void 0;
|
|
1450
|
+
if (parentNode) {
|
|
1451
|
+
if (relY < ARTIFACT_EDGE_PAD) {
|
|
1452
|
+
const belowAbsY = connAbsP.y + nH(connNode) + ARTIFACT_ABOVE_GAP;
|
|
1453
|
+
relY = belowAbsY - parentAbsP.y;
|
|
1454
|
+
}
|
|
1455
|
+
relY = Math.min(relY, nH(parentNode) - nH(artifact) - ARTIFACT_EDGE_PAD);
|
|
1456
|
+
relY = Math.max(relY, ARTIFACT_EDGE_PAD);
|
|
1457
|
+
}
|
|
952
1458
|
positioned.push({
|
|
953
1459
|
...artifact,
|
|
954
1460
|
position: {
|
|
955
1461
|
x: desiredAbsX - parentAbsP.x,
|
|
956
|
-
y:
|
|
1462
|
+
y: relY
|
|
957
1463
|
}
|
|
958
1464
|
});
|
|
959
1465
|
desiredAbsX += nW(artifact) + ARTIFACT_H_SPACING;
|
|
@@ -1018,9 +1524,17 @@ async function bpmnCustomLayout(nodes, edges) {
|
|
|
1018
1524
|
const mainNodes = nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
|
|
1019
1525
|
const pools = mainNodes.filter((n) => n.data.elementType === "Pool");
|
|
1020
1526
|
const lanes = mainNodes.filter((n) => n.data.elementType === "Lane");
|
|
1021
|
-
const
|
|
1022
|
-
|
|
1023
|
-
)
|
|
1527
|
+
const nodeDepthById = /* @__PURE__ */ new Map();
|
|
1528
|
+
const mainById = new Map(mainNodes.map((n) => [n.id, n]));
|
|
1529
|
+
const depthOf = (node) => {
|
|
1530
|
+
const cached = nodeDepthById.get(node.id);
|
|
1531
|
+
if (cached != null) return cached;
|
|
1532
|
+
const parent = node.parentId ? mainById.get(node.parentId) : void 0;
|
|
1533
|
+
const depth = parent ? depthOf(parent) + 1 : 0;
|
|
1534
|
+
nodeDepthById.set(node.id, depth);
|
|
1535
|
+
return depth;
|
|
1536
|
+
};
|
|
1537
|
+
const expandedSubProcesses = mainNodes.filter((n) => COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType) && n.data.isExpanded).sort((a, b) => depthOf(b) - depthOf(a));
|
|
1024
1538
|
const subProcessLayouts = /* @__PURE__ */ new Map();
|
|
1025
1539
|
const workingMainNodes = [...mainNodes];
|
|
1026
1540
|
for (const sp of expandedSubProcesses) {
|
|
@@ -1038,15 +1552,30 @@ async function bpmnCustomLayout(nodes, edges) {
|
|
|
1038
1552
|
}
|
|
1039
1553
|
}
|
|
1040
1554
|
const content = workingMainNodes.filter((n) => {
|
|
1555
|
+
if (n.data.elementType === "BoundaryEvent") return false;
|
|
1041
1556
|
if (!LAYOUT_CONTAINER_TYPES.has(n.data.elementType)) return true;
|
|
1042
1557
|
if (COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)) return true;
|
|
1043
1558
|
return false;
|
|
1044
1559
|
});
|
|
1045
1560
|
if (pools.length === 0) {
|
|
1046
|
-
const
|
|
1047
|
-
const
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1561
|
+
const isSpChild = (n) => !!n.parentId && subProcessLayouts.has(n.parentId);
|
|
1562
|
+
const freeContent = content.filter((n) => !isSpChild(n));
|
|
1563
|
+
const freeBoundaries = workingMainNodes.filter(
|
|
1564
|
+
(n) => n.data.elementType === "BoundaryEvent" && !isSpChild(n)
|
|
1565
|
+
);
|
|
1566
|
+
const resultNodes2 = layoutVirtualContext([...freeContent, ...freeBoundaries], edges, 0);
|
|
1567
|
+
for (const [, spLayout] of subProcessLayouts) {
|
|
1568
|
+
for (const child of spLayout.children) resultNodes2.push(child);
|
|
1569
|
+
}
|
|
1570
|
+
const contentIds = new Set(freeContent.map((n) => n.id));
|
|
1571
|
+
const seqEdges = extractSeqEdges(edges, contentIds);
|
|
1572
|
+
const backIds = detectBackEdges([...contentIds], seqEdges);
|
|
1573
|
+
const routedEdges2 = routeEdges(edges, resultNodes2, backIds, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set());
|
|
1574
|
+
const posArtifacts = positionArtifacts(artifacts, resultNodes2, edges, nodes);
|
|
1575
|
+
return {
|
|
1576
|
+
nodes: sortNodesParentFirst([...resultNodes2, ...posArtifacts]),
|
|
1577
|
+
edges: routedEdges2
|
|
1578
|
+
};
|
|
1050
1579
|
}
|
|
1051
1580
|
const poolIds = new Set(pools.map((p) => p.id));
|
|
1052
1581
|
const allLaneIds = new Set(lanes.map((l) => l.id));
|
|
@@ -1089,30 +1618,14 @@ async function bpmnCustomLayout(nodes, edges) {
|
|
|
1089
1618
|
const layoutted = new Set(resultNodes.map((n) => n.id));
|
|
1090
1619
|
const freeNodes = workingMainNodes.filter((n) => !layoutted.has(n.id));
|
|
1091
1620
|
if (freeNodes.length > 0) {
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
(e) => freeNodeIds.has(e.source) && freeNodeIds.has(e.target)
|
|
1621
|
+
const freeFlow = freeNodes.filter(
|
|
1622
|
+
(n) => n.data.elementType === "BoundaryEvent" || !LAYOUT_CONTAINER_TYPES.has(n.data.elementType) || COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)
|
|
1095
1623
|
);
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
const offsetY = stackY;
|
|
1100
|
-
for (const node of elkFree.nodes) {
|
|
1101
|
-
resultNodes.push({
|
|
1102
|
-
...node,
|
|
1103
|
-
position: { x: node.position.x, y: node.position.y + offsetY }
|
|
1104
|
-
});
|
|
1105
|
-
}
|
|
1106
|
-
const freeEdgeIds = new Set(freeEdges.map((e) => e.id));
|
|
1107
|
-
const elkEdgeMap = new Map(elkFree.edges.map((e) => [e.id, e]));
|
|
1108
|
-
for (let i = 0; i < edges.length; i++) {
|
|
1109
|
-
if (freeEdgeIds.has(edges[i].id) && elkEdgeMap.has(edges[i].id)) {
|
|
1110
|
-
edges[i] = elkEdgeMap.get(edges[i].id);
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
} catch {
|
|
1114
|
-
for (const node of freeNodes) resultNodes.push(node);
|
|
1624
|
+
const freeRest = freeNodes.filter((n) => !freeFlow.includes(n));
|
|
1625
|
+
for (const node of layoutVirtualContext(freeFlow, edges, stackY)) {
|
|
1626
|
+
resultNodes.push(node);
|
|
1115
1627
|
}
|
|
1628
|
+
for (const node of freeRest) resultNodes.push(node);
|
|
1116
1629
|
}
|
|
1117
1630
|
const routedEdges = routeEdges(edges, resultNodes, allBackEdgeIds, allLaneIds, poolIds);
|
|
1118
1631
|
const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges, nodes);
|
|
@@ -1133,6 +1646,6 @@ function applyBpmnLayoutResult(state, result) {
|
|
|
1133
1646
|
return applyLayoutResultToDiagram(state, result);
|
|
1134
1647
|
}
|
|
1135
1648
|
|
|
1136
|
-
export { applyBpmnLayoutResult, bpmnCustomLayout, bpmnDagreLayout };
|
|
1649
|
+
export { applyBpmnLayoutResult, bpmnCustomLayout, bpmnDagreLayout, bpmnElkLayout };
|
|
1137
1650
|
//# sourceMappingURL=index.js.map
|
|
1138
1651
|
//# sourceMappingURL=index.js.map
|