@aranzatech/diagrams-bpmn 0.3.0 → 0.3.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/layout/index.cjs +355 -89
- package/dist/layout/index.cjs.map +1 -1
- package/dist/layout/index.js +355 -89
- package/dist/layout/index.js.map +1 -1
- package/package.json +1 -1
package/dist/layout/index.js
CHANGED
|
@@ -249,63 +249,197 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
|
|
|
249
249
|
|
|
250
250
|
// src/layout/bpmn-custom-layout.ts
|
|
251
251
|
var LANE_LABEL_W = 28;
|
|
252
|
-
var LANE_H_PAD =
|
|
253
|
-
var COL_GAP =
|
|
254
|
-
var ROW_HEIGHT =
|
|
255
|
-
var ROW_GAP =
|
|
256
|
-
var LANE_V_PAD =
|
|
257
|
-
var POOL_H_PAD =
|
|
258
|
-
var POOL_V_GAP =
|
|
259
|
-
var LANE_MIN_H =
|
|
260
|
-
var POOL_MIN_W =
|
|
261
|
-
var POOL_INNER_PAD =
|
|
252
|
+
var LANE_H_PAD = 40;
|
|
253
|
+
var COL_GAP = 100;
|
|
254
|
+
var ROW_HEIGHT = 100;
|
|
255
|
+
var ROW_GAP = 80;
|
|
256
|
+
var LANE_V_PAD = 60;
|
|
257
|
+
var POOL_H_PAD = 80;
|
|
258
|
+
var POOL_V_GAP = 60;
|
|
259
|
+
var LANE_MIN_H = 200;
|
|
260
|
+
var POOL_MIN_W = 840;
|
|
261
|
+
var POOL_INNER_PAD = 10;
|
|
262
|
+
var BACK_EDGE_CLEARANCE = 70;
|
|
263
|
+
var LAYOUT_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
|
|
264
|
+
"DataObject",
|
|
265
|
+
"DataObjectReference",
|
|
266
|
+
"DataInput",
|
|
267
|
+
"DataOutput",
|
|
268
|
+
"DataStore",
|
|
269
|
+
"DataStoreReference",
|
|
270
|
+
"Annotation",
|
|
271
|
+
"Group"
|
|
272
|
+
]);
|
|
273
|
+
var COLLAPSED_SUBPROCESS_TYPES = /* @__PURE__ */ new Set([
|
|
274
|
+
"SubProcess",
|
|
275
|
+
"Transaction",
|
|
276
|
+
"EventSubProcess",
|
|
277
|
+
"AdHocSubProcess"
|
|
278
|
+
]);
|
|
262
279
|
function nW(node) {
|
|
263
280
|
return node.width ?? node.measured?.width ?? 120;
|
|
264
281
|
}
|
|
265
282
|
function nH(node) {
|
|
266
283
|
return node.height ?? node.measured?.height ?? 60;
|
|
267
284
|
}
|
|
285
|
+
var BOUNDARY_SPACING = 10;
|
|
286
|
+
function repositionBoundaryEvents(boundaryEvents, positionedContent) {
|
|
287
|
+
if (boundaryEvents.length === 0) return [];
|
|
288
|
+
const hostById = new Map(positionedContent.map((n) => [n.id, n]));
|
|
289
|
+
const byHost = /* @__PURE__ */ new Map();
|
|
290
|
+
for (const be of boundaryEvents) {
|
|
291
|
+
const hostId = be.data.attachedToRef;
|
|
292
|
+
if (!hostId) continue;
|
|
293
|
+
if (!byHost.has(hostId)) byHost.set(hostId, []);
|
|
294
|
+
byHost.get(hostId).push(be);
|
|
295
|
+
}
|
|
296
|
+
const result = [];
|
|
297
|
+
for (const be of boundaryEvents) {
|
|
298
|
+
const hostId = be.data.attachedToRef;
|
|
299
|
+
if (!hostId) {
|
|
300
|
+
result.push(be);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const host = hostById.get(hostId);
|
|
304
|
+
if (!host) {
|
|
305
|
+
result.push(be);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const hostGroup = byHost.get(hostId);
|
|
309
|
+
const siblingIdx = hostGroup.findIndex((n) => n.id === be.id);
|
|
310
|
+
const hostW = nW(host);
|
|
311
|
+
const hostH = nH(host);
|
|
312
|
+
const beH = nH(be);
|
|
313
|
+
const totalGroupW = hostGroup.reduce((s, b) => s + nW(b), 0) + (hostGroup.length - 1) * BOUNDARY_SPACING;
|
|
314
|
+
const groupStartX = host.position.x + hostW / 2 - totalGroupW / 2;
|
|
315
|
+
const offsetX = hostGroup.slice(0, siblingIdx).reduce((s, b) => s + nW(b) + BOUNDARY_SPACING, 0);
|
|
316
|
+
result.push({
|
|
317
|
+
...be,
|
|
318
|
+
position: {
|
|
319
|
+
x: groupStartX + offsetX,
|
|
320
|
+
y: host.position.y + hostH - beH / 2
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
var SP_PAD = 48;
|
|
327
|
+
function layoutSubProcess(children, edges) {
|
|
328
|
+
if (children.length === 0) {
|
|
329
|
+
return { children: [], width: 280, height: 160 };
|
|
330
|
+
}
|
|
331
|
+
const boundaryEvents = children.filter((n) => n.data.elementType === "BoundaryEvent");
|
|
332
|
+
const mainChildren = children.filter((n) => n.data.elementType !== "BoundaryEvent");
|
|
333
|
+
if (mainChildren.length === 0) {
|
|
334
|
+
return {
|
|
335
|
+
children: repositionBoundaryEvents(boundaryEvents, []),
|
|
336
|
+
width: 280,
|
|
337
|
+
height: 160
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
const contentIds = new Set(mainChildren.map((n) => n.id));
|
|
341
|
+
const seqEdges = extractSeqEdges(edges, contentIds);
|
|
342
|
+
const backIds = detectBackEdges([...contentIds], seqEdges);
|
|
343
|
+
const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
|
|
344
|
+
const columns = assignColumns([...contentIds], fwdEdges);
|
|
345
|
+
const pairs = detectGatewayPairs(mainChildren, fwdEdges);
|
|
346
|
+
const rows = assignRows(mainChildren, fwdEdges, columns, pairs);
|
|
347
|
+
const maxCol = Math.max(0, ...[...columns.values()]);
|
|
348
|
+
const colW = /* @__PURE__ */ new Map();
|
|
349
|
+
for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
|
|
350
|
+
for (const node of mainChildren) {
|
|
351
|
+
const c = columns.get(node.id) ?? 0;
|
|
352
|
+
colW.set(c, Math.max(colW.get(c) ?? 0, nW(node)));
|
|
353
|
+
}
|
|
354
|
+
const colX = /* @__PURE__ */ new Map();
|
|
355
|
+
let cumX = 0;
|
|
356
|
+
for (let c = 0; c <= maxCol; c++) {
|
|
357
|
+
colX.set(c, cumX);
|
|
358
|
+
cumX += (colW.get(c) ?? 120) + COL_GAP;
|
|
359
|
+
}
|
|
360
|
+
const contentW = cumX - COL_GAP;
|
|
361
|
+
const rowVals = [...rows.values()];
|
|
362
|
+
const minRow = Math.min(0, ...rowVals);
|
|
363
|
+
const maxRow = Math.max(0, ...rowVals);
|
|
364
|
+
const rowCount = maxRow - minRow + 1;
|
|
365
|
+
const contentH = rowCount * ROW_HEIGHT + Math.max(0, rowCount - 1) * ROW_GAP;
|
|
366
|
+
const spW = Math.max(280, SP_PAD * 2 + contentW);
|
|
367
|
+
const spH = Math.max(160, SP_PAD * 2 + contentH);
|
|
368
|
+
const positionedChildren = mainChildren.map((node) => {
|
|
369
|
+
const c = columns.get(node.id) ?? 0;
|
|
370
|
+
const r = rows.get(node.id) ?? 0;
|
|
371
|
+
const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - nW(node) / 2;
|
|
372
|
+
const rowOffset = (r - minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - nH(node) / 2;
|
|
373
|
+
return {
|
|
374
|
+
...node,
|
|
375
|
+
position: { x: SP_PAD + colOffset, y: SP_PAD + rowOffset }
|
|
376
|
+
};
|
|
377
|
+
});
|
|
378
|
+
const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, positionedChildren);
|
|
379
|
+
return {
|
|
380
|
+
children: [...positionedChildren, ...positionedBoundaries],
|
|
381
|
+
width: spW,
|
|
382
|
+
height: spH
|
|
383
|
+
};
|
|
384
|
+
}
|
|
268
385
|
function layoutPool(pool, lanes, content, allEdges) {
|
|
269
|
-
|
|
386
|
+
const boundaryEvents = content.filter((n) => n.data.elementType === "BoundaryEvent");
|
|
387
|
+
const mainContent = content.filter((n) => n.data.elementType !== "BoundaryEvent");
|
|
388
|
+
if (mainContent.length === 0) {
|
|
389
|
+
const positionedBoundaries2 = repositionBoundaryEvents(boundaryEvents, []);
|
|
270
390
|
if (lanes.length === 0) {
|
|
271
|
-
return { nodes:
|
|
391
|
+
return { nodes: positionedBoundaries2, width: 300, height: 140 };
|
|
272
392
|
}
|
|
273
393
|
const laneH = LANE_MIN_H;
|
|
274
394
|
const h = POOL_INNER_PAD * 2 + lanes.length * laneH + Math.max(0, lanes.length - 1) * POOL_INNER_PAD;
|
|
275
|
-
const w = POOL_MIN_W;
|
|
276
395
|
return {
|
|
277
|
-
nodes:
|
|
278
|
-
...
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
396
|
+
nodes: [
|
|
397
|
+
...positionedBoundaries2,
|
|
398
|
+
...lanes.map((lane, i) => ({
|
|
399
|
+
...lane,
|
|
400
|
+
position: { x: POOL_INNER_PAD, y: POOL_INNER_PAD + i * (laneH + POOL_INNER_PAD) },
|
|
401
|
+
width: POOL_MIN_W - POOL_INNER_PAD * 2,
|
|
402
|
+
height: laneH
|
|
403
|
+
}))
|
|
404
|
+
],
|
|
405
|
+
width: POOL_MIN_W,
|
|
284
406
|
height: h
|
|
285
407
|
};
|
|
286
408
|
}
|
|
287
|
-
const contentIds = new Set(content.map((n) => n.id));
|
|
288
|
-
const seqEdges = extractSeqEdges(allEdges, contentIds);
|
|
289
|
-
const backIds = detectBackEdges([...contentIds], seqEdges);
|
|
290
|
-
const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
|
|
291
|
-
const columns = assignColumns([...contentIds], fwdEdges);
|
|
292
|
-
const pairs = detectGatewayPairs(content, fwdEdges);
|
|
293
|
-
const rows = assignRows(content, fwdEdges, columns, pairs);
|
|
294
409
|
const lanePositionsDistinct = lanes.some((l) => Math.abs(l.position.y) > 10);
|
|
295
410
|
const sortedLanes = lanePositionsDistinct ? [...lanes].sort((a, b) => a.position.y - b.position.y) : [...lanes];
|
|
296
411
|
const hasLanes = sortedLanes.length > 0;
|
|
412
|
+
const laneIdSet = new Set(sortedLanes.map((l) => l.id));
|
|
297
413
|
const nodeLaneId = /* @__PURE__ */ new Map();
|
|
298
|
-
for (const node of
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
414
|
+
for (const node of mainContent) {
|
|
415
|
+
const lId = hasLanes && node.parentId && laneIdSet.has(node.parentId) ? node.parentId : "_pool_";
|
|
416
|
+
nodeLaneId.set(node.id, lId);
|
|
417
|
+
}
|
|
418
|
+
const contentIds = new Set(mainContent.map((n) => n.id));
|
|
419
|
+
const seqEdges = extractSeqEdges(allEdges, contentIds);
|
|
420
|
+
const backIds = detectBackEdges([...contentIds], seqEdges);
|
|
421
|
+
const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
|
|
422
|
+
const columns = assignColumns([...contentIds], fwdEdges);
|
|
423
|
+
const rows = /* @__PURE__ */ new Map();
|
|
424
|
+
const contentByLane = /* @__PURE__ */ new Map();
|
|
425
|
+
for (const node of mainContent) {
|
|
426
|
+
const lId = nodeLaneId.get(node.id) ?? "_pool_";
|
|
427
|
+
if (!contentByLane.has(lId)) contentByLane.set(lId, []);
|
|
428
|
+
contentByLane.get(lId).push(node);
|
|
429
|
+
}
|
|
430
|
+
for (const [, laneNodes] of contentByLane) {
|
|
431
|
+
const laneNodeIds = new Set(laneNodes.map((n) => n.id));
|
|
432
|
+
const intraEdges = fwdEdges.filter(
|
|
433
|
+
(e) => laneNodeIds.has(e.source) && laneNodeIds.has(e.target)
|
|
434
|
+
);
|
|
435
|
+
const lanePairs = detectGatewayPairs(laneNodes, intraEdges);
|
|
436
|
+
const laneRows = assignRows(laneNodes, intraEdges, columns, lanePairs);
|
|
437
|
+
for (const [id, row] of laneRows) rows.set(id, row);
|
|
304
438
|
}
|
|
305
439
|
const laneIds = hasLanes ? sortedLanes.map((l) => l.id) : ["_pool_"];
|
|
306
440
|
const laneStats = /* @__PURE__ */ new Map();
|
|
307
441
|
for (const laneId of laneIds) {
|
|
308
|
-
const laneRows =
|
|
442
|
+
const laneRows = mainContent.filter((n) => nodeLaneId.get(n.id) === laneId).map((n) => rows.get(n.id) ?? 0);
|
|
309
443
|
if (laneRows.length === 0) {
|
|
310
444
|
laneStats.set(laneId, { minRow: 0, maxRow: 0, rowCount: 1, height: LANE_MIN_H });
|
|
311
445
|
} else {
|
|
@@ -320,7 +454,7 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
320
454
|
const maxCol = Math.max(0, ...[...columns.values()]);
|
|
321
455
|
const colW = /* @__PURE__ */ new Map();
|
|
322
456
|
for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
|
|
323
|
-
for (const node of
|
|
457
|
+
for (const node of mainContent) {
|
|
324
458
|
const c = columns.get(node.id) ?? 0;
|
|
325
459
|
colW.set(c, Math.max(colW.get(c) ?? 0, nW(node)));
|
|
326
460
|
}
|
|
@@ -343,7 +477,7 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
343
477
|
if (i < laneIds.length - 1) cumY += POOL_INNER_PAD;
|
|
344
478
|
}
|
|
345
479
|
const poolH = cumY + POOL_INNER_PAD;
|
|
346
|
-
const positionedContent =
|
|
480
|
+
const positionedContent = mainContent.map((node) => {
|
|
347
481
|
const c = columns.get(node.id) ?? 0;
|
|
348
482
|
const r = rows.get(node.id) ?? 0;
|
|
349
483
|
const laneId = nodeLaneId.get(node.id) ?? "_pool_";
|
|
@@ -351,14 +485,14 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
351
485
|
const lYOff = laneY.get(laneId) ?? 0;
|
|
352
486
|
const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - nW(node) / 2;
|
|
353
487
|
const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - nH(node) / 2;
|
|
354
|
-
const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
|
|
355
488
|
const contentH_stat = stat.rowCount * ROW_HEIGHT + Math.max(0, stat.rowCount - 1) * ROW_GAP;
|
|
356
489
|
const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - contentH_stat) / 2);
|
|
490
|
+
const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
|
|
357
491
|
const x = isLaneChild ? LANE_LABEL_W + LANE_H_PAD + colOffset : POOL_H_PAD + colOffset;
|
|
358
492
|
const y = isLaneChild ? vertTopOffset + rowOffset : lYOff + vertTopOffset + rowOffset;
|
|
359
493
|
return { ...node, position: { x, y } };
|
|
360
494
|
});
|
|
361
|
-
const NODE_MIN_GAP =
|
|
495
|
+
const NODE_MIN_GAP = 24;
|
|
362
496
|
const resolvedContent = [...positionedContent];
|
|
363
497
|
for (const laneId of laneIds) {
|
|
364
498
|
const laneNodeIndices = resolvedContent.map((n, i) => ({ n, i })).filter(({ n }) => (nodeLaneId.get(n.id) ?? "_pool_") === laneId).sort((a, b) => a.n.position.x - b.n.position.x);
|
|
@@ -375,30 +509,24 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
375
509
|
if (prevRight + NODE_MIN_GAP > curr.position.x) {
|
|
376
510
|
resolvedContent[laneNodeIndices[k].i] = {
|
|
377
511
|
...curr,
|
|
378
|
-
position: {
|
|
379
|
-
x: prevRight + NODE_MIN_GAP,
|
|
380
|
-
y: curr.position.y
|
|
381
|
-
}
|
|
512
|
+
position: { x: prevRight + NODE_MIN_GAP, y: curr.position.y }
|
|
382
513
|
};
|
|
383
514
|
}
|
|
384
515
|
}
|
|
385
516
|
}
|
|
517
|
+
const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, resolvedContent);
|
|
386
518
|
const positionedLanes = hasLanes ? sortedLanes.map((lane) => ({
|
|
387
519
|
...lane,
|
|
388
|
-
// x: after pool label strip + left inner padding
|
|
389
|
-
// y: laneY already includes top POOL_INNER_PAD offset
|
|
390
520
|
position: { x: POOL_INNER_PAD, y: laneY.get(lane.id) ?? POOL_INNER_PAD },
|
|
391
521
|
width: laneW,
|
|
392
522
|
height: laneStats.get(lane.id)?.height ?? LANE_MIN_H
|
|
393
523
|
})) : [];
|
|
394
524
|
return {
|
|
395
|
-
nodes: [...resolvedContent, ...positionedLanes],
|
|
525
|
+
nodes: [...resolvedContent, ...positionedBoundaries, ...positionedLanes],
|
|
396
526
|
width: poolW,
|
|
397
527
|
height: poolH
|
|
398
528
|
};
|
|
399
529
|
}
|
|
400
|
-
var BACK_EDGE_CLEARANCE = 50;
|
|
401
|
-
var SAME_ROW_THRESHOLD = 15;
|
|
402
530
|
function absolutePos(nodeId, byId, cache) {
|
|
403
531
|
const cached = cache.get(nodeId);
|
|
404
532
|
if (cached) return cached;
|
|
@@ -417,10 +545,17 @@ function absolutePos(nodeId, byId, cache) {
|
|
|
417
545
|
function laneOf(node, laneIds) {
|
|
418
546
|
return node.parentId && laneIds.has(node.parentId) ? node.parentId : void 0;
|
|
419
547
|
}
|
|
548
|
+
function gapMidX(sAbs, sW, tAbs, tW) {
|
|
549
|
+
const leftRightEdge = Math.min(sAbs.x + sW, tAbs.x + tW);
|
|
550
|
+
const rightLeftEdge = Math.max(sAbs.x, tAbs.x);
|
|
551
|
+
return leftRightEdge < rightLeftEdge ? (leftRightEdge + rightLeftEdge) / 2 : sAbs.x + sW / 2;
|
|
552
|
+
}
|
|
553
|
+
var SAME_ROW_THRESHOLD = 15;
|
|
420
554
|
function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
421
555
|
const byId = new Map(layoutNodes.map((n) => [n.id, n]));
|
|
422
556
|
const cache = /* @__PURE__ */ new Map();
|
|
423
557
|
const abs = (id) => absolutePos(id, byId, cache);
|
|
558
|
+
const sortedLanes = [...laneIds].map((id) => byId.get(id)).filter((n) => !!n).sort((a, b) => abs(a.id).y - abs(b.id).y);
|
|
424
559
|
return edges.map((edge) => {
|
|
425
560
|
const edgeType = edge.data?.edgeType ?? edge.type;
|
|
426
561
|
if (edgeType !== "sequenceFlow") {
|
|
@@ -435,11 +570,22 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
435
570
|
const tAbs = abs(tgt.id);
|
|
436
571
|
const sW = nW(src), sH = nH(src);
|
|
437
572
|
const tW = nW(tgt), tH = nH(tgt);
|
|
438
|
-
const sCX = sAbs.x + sW / 2
|
|
439
|
-
const tCX = tAbs.x + tW / 2
|
|
440
|
-
const
|
|
441
|
-
const
|
|
442
|
-
|
|
573
|
+
const sCX = sAbs.x + sW / 2;
|
|
574
|
+
const tCX = tAbs.x + tW / 2;
|
|
575
|
+
const sCY = sAbs.y + sH / 2;
|
|
576
|
+
const tCY = tAbs.y + tH / 2;
|
|
577
|
+
const getPool = (nodeId) => {
|
|
578
|
+
const node = byId.get(nodeId);
|
|
579
|
+
if (!node) return null;
|
|
580
|
+
if (poolIds.has(nodeId)) return nodeId;
|
|
581
|
+
if (node.parentId && poolIds.has(node.parentId)) return node.parentId;
|
|
582
|
+
if (node.parentId) {
|
|
583
|
+
const gp = byId.get(node.parentId)?.parentId ?? null;
|
|
584
|
+
if (gp && poolIds.has(gp)) return gp;
|
|
585
|
+
}
|
|
586
|
+
return node.parentId ?? null;
|
|
587
|
+
};
|
|
588
|
+
if (getPool(edge.source) !== getPool(edge.target)) {
|
|
443
589
|
const d = { ...edge.data };
|
|
444
590
|
delete d.routingPoints;
|
|
445
591
|
return { ...edge, data: d };
|
|
@@ -449,33 +595,49 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
449
595
|
const topY = Math.min(sAbs.y, tAbs.y) - BACK_EDGE_CLEARANCE;
|
|
450
596
|
routingPoints = [
|
|
451
597
|
{ x: sCX, y: sAbs.y },
|
|
452
|
-
// [0] discarded
|
|
453
598
|
{ x: sCX, y: topY },
|
|
454
|
-
// [1] go up
|
|
455
599
|
{ x: tCX, y: topY },
|
|
456
|
-
|
|
457
|
-
{ x: tCX, y: tAbs.y }
|
|
458
|
-
// [3] discarded
|
|
600
|
+
{ x: tCX, y: tAbs.y + tH }
|
|
459
601
|
];
|
|
460
602
|
} else if (laneOf(src, laneIds) !== laneOf(tgt, laneIds)) {
|
|
461
|
-
const goingDown = tAbs.y > sAbs.y;
|
|
462
|
-
const sharedX = Math.abs(sCX - tCX) < 10 ? sCX : (sCX + tCX) / 2;
|
|
463
603
|
const srcLane = byId.get(src.parentId ?? "");
|
|
464
604
|
const tgtLane = byId.get(tgt.parentId ?? "");
|
|
465
605
|
if (srcLane && tgtLane && laneIds.has(srcLane.id) && laneIds.has(tgtLane.id)) {
|
|
466
|
-
const
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
{ x: sharedX, y:
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
606
|
+
const goingDown = tAbs.y > sAbs.y;
|
|
607
|
+
const sharedX = gapMidX(sAbs, sW, tAbs, tW);
|
|
608
|
+
const srcLaneIdx = sortedLanes.findIndex((l) => l.id === srcLane.id);
|
|
609
|
+
const tgtLaneIdx = sortedLanes.findIndex((l) => l.id === tgtLane.id);
|
|
610
|
+
const pts = [];
|
|
611
|
+
if (goingDown) {
|
|
612
|
+
pts.push({ x: sCX, y: sAbs.y + sH });
|
|
613
|
+
pts.push({ x: sharedX, y: sAbs.y + sH });
|
|
614
|
+
const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
|
|
615
|
+
const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
|
|
616
|
+
for (let i = fromIdx; i < toIdx; i++) {
|
|
617
|
+
const lane = sortedLanes[i];
|
|
618
|
+
const laneBot = abs(lane.id).y + (lane.height ?? LANE_MIN_H);
|
|
619
|
+
pts.push({ x: sharedX, y: laneBot });
|
|
620
|
+
}
|
|
621
|
+
const lastY = pts[pts.length - 1].y;
|
|
622
|
+
pts.push({ x: tCX, y: lastY });
|
|
623
|
+
pts.push({ x: tCX, y: tAbs.y + tH });
|
|
624
|
+
} else {
|
|
625
|
+
pts.push({ x: sCX, y: sAbs.y });
|
|
626
|
+
pts.push({ x: sharedX, y: sAbs.y });
|
|
627
|
+
const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
|
|
628
|
+
const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
|
|
629
|
+
for (let i = toIdx; i > fromIdx; i--) {
|
|
630
|
+
const lane = sortedLanes[i];
|
|
631
|
+
const laneTop = abs(lane.id).y;
|
|
632
|
+
pts.push({ x: sharedX, y: laneTop });
|
|
633
|
+
}
|
|
634
|
+
const lastY = pts[pts.length - 1].y;
|
|
635
|
+
pts.push({ x: tCX, y: lastY });
|
|
636
|
+
pts.push({ x: tCX, y: tAbs.y });
|
|
637
|
+
}
|
|
638
|
+
routingPoints = pts;
|
|
478
639
|
} else {
|
|
640
|
+
const sharedX = gapMidX(sAbs, sW, tAbs, tW);
|
|
479
641
|
routingPoints = [
|
|
480
642
|
{ x: sCX, y: sCY },
|
|
481
643
|
{ x: sharedX, y: sCY },
|
|
@@ -494,39 +656,108 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
494
656
|
if (exitsTop || exitsBottom) {
|
|
495
657
|
routingPoints = [
|
|
496
658
|
{ x: sCX, y: exitsTop ? sAbs.y : sAbs.y + sH },
|
|
497
|
-
// [0] discarded
|
|
498
659
|
{ x: sCX, y: tCY },
|
|
499
|
-
// [1] vertical to target row
|
|
500
660
|
{ x: tCX, y: tCY },
|
|
501
|
-
// [2] horizontal to target
|
|
502
661
|
{ x: tCX, y: exitsTop ? tAbs.y + tH : tAbs.y }
|
|
503
|
-
// [3] discarded
|
|
504
662
|
];
|
|
505
663
|
} else {
|
|
506
|
-
const
|
|
507
|
-
const midX = goingRight ? sAbs.x + sW + COL_GAP / 2 : sAbs.x - COL_GAP / 2;
|
|
664
|
+
const midX = gapMidX(sAbs, sW, tAbs, tW);
|
|
508
665
|
routingPoints = [
|
|
509
666
|
{ x: sAbs.x + sW, y: sCY },
|
|
510
|
-
// [0] discarded
|
|
511
667
|
{ x: midX, y: sCY },
|
|
512
|
-
// [1] horizontal exit
|
|
513
668
|
{ x: midX, y: tCY },
|
|
514
|
-
// [2] vertical to target row
|
|
515
669
|
{ x: tAbs.x, y: tCY }
|
|
516
|
-
// [3] discarded
|
|
517
670
|
];
|
|
518
671
|
}
|
|
519
672
|
}
|
|
520
673
|
return { ...edge, data: { ...edge.data, routingPoints } };
|
|
521
674
|
});
|
|
522
675
|
}
|
|
676
|
+
var ARTIFACT_ABOVE_GAP = 16;
|
|
677
|
+
var ARTIFACT_H_SPACING = 12;
|
|
678
|
+
function positionArtifacts(artifacts, resultNodes, edges) {
|
|
679
|
+
if (artifacts.length === 0) return [];
|
|
680
|
+
const byId = new Map(resultNodes.map((n) => [n.id, n]));
|
|
681
|
+
const cache = /* @__PURE__ */ new Map();
|
|
682
|
+
const absPos = (id) => absolutePos(id, byId, cache);
|
|
683
|
+
const artifactsByNode = /* @__PURE__ */ new Map();
|
|
684
|
+
const ungrouped = [];
|
|
685
|
+
for (const artifact of artifacts) {
|
|
686
|
+
if (artifact.data.elementType === "Group") {
|
|
687
|
+
ungrouped.push(artifact);
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
const connEdge = edges.find((e) => {
|
|
691
|
+
const t = e.data?.edgeType ?? e.type;
|
|
692
|
+
return (t === "association" || t === "dataAssociation") && (e.source === artifact.id || e.target === artifact.id);
|
|
693
|
+
});
|
|
694
|
+
if (!connEdge) {
|
|
695
|
+
ungrouped.push(artifact);
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
const connId = connEdge.source === artifact.id ? connEdge.target : connEdge.source;
|
|
699
|
+
if (!byId.has(connId)) {
|
|
700
|
+
ungrouped.push(artifact);
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
if (!artifactsByNode.has(connId)) artifactsByNode.set(connId, []);
|
|
704
|
+
artifactsByNode.get(connId).push(artifact);
|
|
705
|
+
}
|
|
706
|
+
const positioned = [...ungrouped];
|
|
707
|
+
for (const [connId, arts] of artifactsByNode) {
|
|
708
|
+
const connNode = byId.get(connId);
|
|
709
|
+
const connAbsP = absPos(connId);
|
|
710
|
+
const totalW = arts.reduce((s, a) => s + nW(a), 0) + (arts.length - 1) * ARTIFACT_H_SPACING;
|
|
711
|
+
const desiredAbsY = connAbsP.y - ARTIFACT_ABOVE_GAP - Math.max(...arts.map(nH));
|
|
712
|
+
let desiredAbsX = connAbsP.x + nW(connNode) / 2 - totalW / 2;
|
|
713
|
+
for (const artifact of arts) {
|
|
714
|
+
const parentAbsP = artifact.parentId ? absPos(artifact.parentId) : { x: 0, y: 0 };
|
|
715
|
+
positioned.push({
|
|
716
|
+
...artifact,
|
|
717
|
+
position: {
|
|
718
|
+
x: desiredAbsX - parentAbsP.x,
|
|
719
|
+
y: desiredAbsY - parentAbsP.y
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
desiredAbsX += nW(artifact) + ARTIFACT_H_SPACING;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
return positioned;
|
|
726
|
+
}
|
|
523
727
|
async function bpmnCustomLayout(nodes, edges) {
|
|
524
|
-
const
|
|
525
|
-
const
|
|
526
|
-
const
|
|
728
|
+
const artifacts = nodes.filter((n) => LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
|
|
729
|
+
const mainNodes = nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
|
|
730
|
+
const pools = mainNodes.filter((n) => n.data.elementType === "Pool");
|
|
731
|
+
const lanes = mainNodes.filter((n) => n.data.elementType === "Lane");
|
|
732
|
+
const expandedSubProcesses = mainNodes.filter(
|
|
733
|
+
(n) => COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType) && n.data.isExpanded
|
|
734
|
+
);
|
|
735
|
+
const subProcessLayouts = /* @__PURE__ */ new Map();
|
|
736
|
+
const workingMainNodes = [...mainNodes];
|
|
737
|
+
for (const sp of expandedSubProcesses) {
|
|
738
|
+
const spChildren = workingMainNodes.filter((n) => n.parentId === sp.id);
|
|
739
|
+
const result = layoutSubProcess(spChildren, edges);
|
|
740
|
+
subProcessLayouts.set(sp.id, result);
|
|
741
|
+
const spIdx = workingMainNodes.findIndex((n) => n.id === sp.id);
|
|
742
|
+
if (spIdx >= 0) {
|
|
743
|
+
workingMainNodes[spIdx] = {
|
|
744
|
+
...workingMainNodes[spIdx],
|
|
745
|
+
width: result.width,
|
|
746
|
+
height: result.height,
|
|
747
|
+
measured: { width: result.width, height: result.height }
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
const content = workingMainNodes.filter((n) => {
|
|
752
|
+
if (!LAYOUT_CONTAINER_TYPES.has(n.data.elementType)) return true;
|
|
753
|
+
if (COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)) return true;
|
|
754
|
+
return false;
|
|
755
|
+
});
|
|
527
756
|
if (pools.length === 0) {
|
|
528
757
|
const { bpmnElkLayout: bpmnElkLayout2 } = await import('../elk-QT7H4252.js');
|
|
529
|
-
|
|
758
|
+
const elkResult = await bpmnElkLayout2(nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType)), edges);
|
|
759
|
+
const posArtifacts = positionArtifacts(artifacts, elkResult.nodes, edges);
|
|
760
|
+
return { nodes: [...elkResult.nodes, ...posArtifacts], edges: elkResult.edges };
|
|
530
761
|
}
|
|
531
762
|
const poolIds = new Set(pools.map((p) => p.id));
|
|
532
763
|
const allLaneIds = new Set(lanes.map((l) => l.id));
|
|
@@ -546,7 +777,10 @@ async function bpmnCustomLayout(nodes, edges) {
|
|
|
546
777
|
const poolContent = content.filter(
|
|
547
778
|
(n) => n.parentId === pool.id || n.parentId != null && laneIds.has(n.parentId)
|
|
548
779
|
);
|
|
549
|
-
const
|
|
780
|
+
const poolBoundaries = workingMainNodes.filter(
|
|
781
|
+
(n) => n.data.elementType === "BoundaryEvent" && (n.parentId === pool.id || n.parentId != null && laneIds.has(n.parentId))
|
|
782
|
+
);
|
|
783
|
+
const result = layoutPool(pool, poolLanes, [...poolContent, ...poolBoundaries], edges);
|
|
550
784
|
resultNodes.push({
|
|
551
785
|
...pool,
|
|
552
786
|
position: { x: 0, y: stackY },
|
|
@@ -558,12 +792,44 @@ async function bpmnCustomLayout(nodes, edges) {
|
|
|
558
792
|
}
|
|
559
793
|
stackY += result.height + POOL_V_GAP;
|
|
560
794
|
}
|
|
795
|
+
for (const [, spLayout] of subProcessLayouts) {
|
|
796
|
+
for (const child of spLayout.children) {
|
|
797
|
+
resultNodes.push(child);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
561
800
|
const layoutted = new Set(resultNodes.map((n) => n.id));
|
|
562
|
-
|
|
563
|
-
|
|
801
|
+
const freeNodes = workingMainNodes.filter((n) => !layoutted.has(n.id));
|
|
802
|
+
if (freeNodes.length > 0) {
|
|
803
|
+
const freeEdges = edges.filter(
|
|
804
|
+
(e) => freeNodes.some((n) => n.id === e.source || n.id === e.target)
|
|
805
|
+
);
|
|
806
|
+
try {
|
|
807
|
+
const { bpmnElkLayout: bpmnElkLayout2 } = await import('../elk-QT7H4252.js');
|
|
808
|
+
const elkFree = await bpmnElkLayout2(freeNodes, freeEdges);
|
|
809
|
+
const offsetY = stackY;
|
|
810
|
+
for (const node of elkFree.nodes) {
|
|
811
|
+
resultNodes.push({
|
|
812
|
+
...node,
|
|
813
|
+
position: { x: node.position.x, y: node.position.y + offsetY }
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
const freeEdgeIds = new Set(freeEdges.map((e) => e.id));
|
|
817
|
+
const elkEdgeMap = new Map(elkFree.edges.map((e) => [e.id, e]));
|
|
818
|
+
for (let i = 0; i < edges.length; i++) {
|
|
819
|
+
if (freeEdgeIds.has(edges[i].id) && elkEdgeMap.has(edges[i].id)) {
|
|
820
|
+
edges[i] = elkEdgeMap.get(edges[i].id);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
} catch {
|
|
824
|
+
for (const node of freeNodes) resultNodes.push(node);
|
|
825
|
+
}
|
|
564
826
|
}
|
|
565
827
|
const routedEdges = routeEdges(edges, resultNodes, allBackEdgeIds, allLaneIds, poolIds);
|
|
566
|
-
|
|
828
|
+
const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges);
|
|
829
|
+
return {
|
|
830
|
+
nodes: [...resultNodes, ...positionedArtifacts],
|
|
831
|
+
edges: routedEdges
|
|
832
|
+
};
|
|
567
833
|
}
|
|
568
834
|
|
|
569
835
|
// src/layout/index.ts
|