@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.cjs
CHANGED
|
@@ -1311,63 +1311,197 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
|
|
|
1311
1311
|
|
|
1312
1312
|
// src/layout/bpmn-custom-layout.ts
|
|
1313
1313
|
var LANE_LABEL_W = 28;
|
|
1314
|
-
var LANE_H_PAD =
|
|
1315
|
-
var COL_GAP =
|
|
1316
|
-
var ROW_HEIGHT =
|
|
1317
|
-
var ROW_GAP =
|
|
1318
|
-
var LANE_V_PAD =
|
|
1319
|
-
var POOL_H_PAD =
|
|
1320
|
-
var POOL_V_GAP =
|
|
1321
|
-
var LANE_MIN_H =
|
|
1322
|
-
var POOL_MIN_W =
|
|
1323
|
-
var POOL_INNER_PAD =
|
|
1314
|
+
var LANE_H_PAD = 40;
|
|
1315
|
+
var COL_GAP = 100;
|
|
1316
|
+
var ROW_HEIGHT = 100;
|
|
1317
|
+
var ROW_GAP = 80;
|
|
1318
|
+
var LANE_V_PAD = 60;
|
|
1319
|
+
var POOL_H_PAD = 80;
|
|
1320
|
+
var POOL_V_GAP = 60;
|
|
1321
|
+
var LANE_MIN_H = 200;
|
|
1322
|
+
var POOL_MIN_W = 840;
|
|
1323
|
+
var POOL_INNER_PAD = 10;
|
|
1324
|
+
var BACK_EDGE_CLEARANCE = 70;
|
|
1325
|
+
var LAYOUT_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
|
|
1326
|
+
"DataObject",
|
|
1327
|
+
"DataObjectReference",
|
|
1328
|
+
"DataInput",
|
|
1329
|
+
"DataOutput",
|
|
1330
|
+
"DataStore",
|
|
1331
|
+
"DataStoreReference",
|
|
1332
|
+
"Annotation",
|
|
1333
|
+
"Group"
|
|
1334
|
+
]);
|
|
1335
|
+
var COLLAPSED_SUBPROCESS_TYPES = /* @__PURE__ */ new Set([
|
|
1336
|
+
"SubProcess",
|
|
1337
|
+
"Transaction",
|
|
1338
|
+
"EventSubProcess",
|
|
1339
|
+
"AdHocSubProcess"
|
|
1340
|
+
]);
|
|
1324
1341
|
function nW(node) {
|
|
1325
1342
|
return node.width ?? node.measured?.width ?? 120;
|
|
1326
1343
|
}
|
|
1327
1344
|
function nH(node) {
|
|
1328
1345
|
return node.height ?? node.measured?.height ?? 60;
|
|
1329
1346
|
}
|
|
1347
|
+
var BOUNDARY_SPACING = 10;
|
|
1348
|
+
function repositionBoundaryEvents(boundaryEvents, positionedContent) {
|
|
1349
|
+
if (boundaryEvents.length === 0) return [];
|
|
1350
|
+
const hostById = new Map(positionedContent.map((n) => [n.id, n]));
|
|
1351
|
+
const byHost = /* @__PURE__ */ new Map();
|
|
1352
|
+
for (const be of boundaryEvents) {
|
|
1353
|
+
const hostId = be.data.attachedToRef;
|
|
1354
|
+
if (!hostId) continue;
|
|
1355
|
+
if (!byHost.has(hostId)) byHost.set(hostId, []);
|
|
1356
|
+
byHost.get(hostId).push(be);
|
|
1357
|
+
}
|
|
1358
|
+
const result = [];
|
|
1359
|
+
for (const be of boundaryEvents) {
|
|
1360
|
+
const hostId = be.data.attachedToRef;
|
|
1361
|
+
if (!hostId) {
|
|
1362
|
+
result.push(be);
|
|
1363
|
+
continue;
|
|
1364
|
+
}
|
|
1365
|
+
const host = hostById.get(hostId);
|
|
1366
|
+
if (!host) {
|
|
1367
|
+
result.push(be);
|
|
1368
|
+
continue;
|
|
1369
|
+
}
|
|
1370
|
+
const hostGroup = byHost.get(hostId);
|
|
1371
|
+
const siblingIdx = hostGroup.findIndex((n) => n.id === be.id);
|
|
1372
|
+
const hostW = nW(host);
|
|
1373
|
+
const hostH = nH(host);
|
|
1374
|
+
const beH = nH(be);
|
|
1375
|
+
const totalGroupW = hostGroup.reduce((s, b) => s + nW(b), 0) + (hostGroup.length - 1) * BOUNDARY_SPACING;
|
|
1376
|
+
const groupStartX = host.position.x + hostW / 2 - totalGroupW / 2;
|
|
1377
|
+
const offsetX = hostGroup.slice(0, siblingIdx).reduce((s, b) => s + nW(b) + BOUNDARY_SPACING, 0);
|
|
1378
|
+
result.push({
|
|
1379
|
+
...be,
|
|
1380
|
+
position: {
|
|
1381
|
+
x: groupStartX + offsetX,
|
|
1382
|
+
y: host.position.y + hostH - beH / 2
|
|
1383
|
+
}
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
return result;
|
|
1387
|
+
}
|
|
1388
|
+
var SP_PAD = 48;
|
|
1389
|
+
function layoutSubProcess(children, edges) {
|
|
1390
|
+
if (children.length === 0) {
|
|
1391
|
+
return { children: [], width: 280, height: 160 };
|
|
1392
|
+
}
|
|
1393
|
+
const boundaryEvents = children.filter((n) => n.data.elementType === "BoundaryEvent");
|
|
1394
|
+
const mainChildren = children.filter((n) => n.data.elementType !== "BoundaryEvent");
|
|
1395
|
+
if (mainChildren.length === 0) {
|
|
1396
|
+
return {
|
|
1397
|
+
children: repositionBoundaryEvents(boundaryEvents, []),
|
|
1398
|
+
width: 280,
|
|
1399
|
+
height: 160
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
const contentIds = new Set(mainChildren.map((n) => n.id));
|
|
1403
|
+
const seqEdges = extractSeqEdges(edges, contentIds);
|
|
1404
|
+
const backIds = detectBackEdges([...contentIds], seqEdges);
|
|
1405
|
+
const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
|
|
1406
|
+
const columns = assignColumns([...contentIds], fwdEdges);
|
|
1407
|
+
const pairs = detectGatewayPairs(mainChildren, fwdEdges);
|
|
1408
|
+
const rows = assignRows(mainChildren, fwdEdges, columns, pairs);
|
|
1409
|
+
const maxCol = Math.max(0, ...[...columns.values()]);
|
|
1410
|
+
const colW = /* @__PURE__ */ new Map();
|
|
1411
|
+
for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
|
|
1412
|
+
for (const node of mainChildren) {
|
|
1413
|
+
const c = columns.get(node.id) ?? 0;
|
|
1414
|
+
colW.set(c, Math.max(colW.get(c) ?? 0, nW(node)));
|
|
1415
|
+
}
|
|
1416
|
+
const colX = /* @__PURE__ */ new Map();
|
|
1417
|
+
let cumX = 0;
|
|
1418
|
+
for (let c = 0; c <= maxCol; c++) {
|
|
1419
|
+
colX.set(c, cumX);
|
|
1420
|
+
cumX += (colW.get(c) ?? 120) + COL_GAP;
|
|
1421
|
+
}
|
|
1422
|
+
const contentW = cumX - COL_GAP;
|
|
1423
|
+
const rowVals = [...rows.values()];
|
|
1424
|
+
const minRow = Math.min(0, ...rowVals);
|
|
1425
|
+
const maxRow = Math.max(0, ...rowVals);
|
|
1426
|
+
const rowCount = maxRow - minRow + 1;
|
|
1427
|
+
const contentH = rowCount * ROW_HEIGHT + Math.max(0, rowCount - 1) * ROW_GAP;
|
|
1428
|
+
const spW = Math.max(280, SP_PAD * 2 + contentW);
|
|
1429
|
+
const spH = Math.max(160, SP_PAD * 2 + contentH);
|
|
1430
|
+
const positionedChildren = mainChildren.map((node) => {
|
|
1431
|
+
const c = columns.get(node.id) ?? 0;
|
|
1432
|
+
const r = rows.get(node.id) ?? 0;
|
|
1433
|
+
const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - nW(node) / 2;
|
|
1434
|
+
const rowOffset = (r - minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - nH(node) / 2;
|
|
1435
|
+
return {
|
|
1436
|
+
...node,
|
|
1437
|
+
position: { x: SP_PAD + colOffset, y: SP_PAD + rowOffset }
|
|
1438
|
+
};
|
|
1439
|
+
});
|
|
1440
|
+
const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, positionedChildren);
|
|
1441
|
+
return {
|
|
1442
|
+
children: [...positionedChildren, ...positionedBoundaries],
|
|
1443
|
+
width: spW,
|
|
1444
|
+
height: spH
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1330
1447
|
function layoutPool(pool, lanes, content, allEdges) {
|
|
1331
|
-
|
|
1448
|
+
const boundaryEvents = content.filter((n) => n.data.elementType === "BoundaryEvent");
|
|
1449
|
+
const mainContent = content.filter((n) => n.data.elementType !== "BoundaryEvent");
|
|
1450
|
+
if (mainContent.length === 0) {
|
|
1451
|
+
const positionedBoundaries2 = repositionBoundaryEvents(boundaryEvents, []);
|
|
1332
1452
|
if (lanes.length === 0) {
|
|
1333
|
-
return { nodes:
|
|
1453
|
+
return { nodes: positionedBoundaries2, width: 300, height: 140 };
|
|
1334
1454
|
}
|
|
1335
1455
|
const laneH = LANE_MIN_H;
|
|
1336
1456
|
const h = POOL_INNER_PAD * 2 + lanes.length * laneH + Math.max(0, lanes.length - 1) * POOL_INNER_PAD;
|
|
1337
|
-
const w = POOL_MIN_W;
|
|
1338
1457
|
return {
|
|
1339
|
-
nodes:
|
|
1340
|
-
...
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1458
|
+
nodes: [
|
|
1459
|
+
...positionedBoundaries2,
|
|
1460
|
+
...lanes.map((lane, i) => ({
|
|
1461
|
+
...lane,
|
|
1462
|
+
position: { x: POOL_INNER_PAD, y: POOL_INNER_PAD + i * (laneH + POOL_INNER_PAD) },
|
|
1463
|
+
width: POOL_MIN_W - POOL_INNER_PAD * 2,
|
|
1464
|
+
height: laneH
|
|
1465
|
+
}))
|
|
1466
|
+
],
|
|
1467
|
+
width: POOL_MIN_W,
|
|
1346
1468
|
height: h
|
|
1347
1469
|
};
|
|
1348
1470
|
}
|
|
1349
|
-
const contentIds = new Set(content.map((n) => n.id));
|
|
1350
|
-
const seqEdges = extractSeqEdges(allEdges, contentIds);
|
|
1351
|
-
const backIds = detectBackEdges([...contentIds], seqEdges);
|
|
1352
|
-
const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
|
|
1353
|
-
const columns = assignColumns([...contentIds], fwdEdges);
|
|
1354
|
-
const pairs = detectGatewayPairs(content, fwdEdges);
|
|
1355
|
-
const rows = assignRows(content, fwdEdges, columns, pairs);
|
|
1356
1471
|
const lanePositionsDistinct = lanes.some((l) => Math.abs(l.position.y) > 10);
|
|
1357
1472
|
const sortedLanes = lanePositionsDistinct ? [...lanes].sort((a, b) => a.position.y - b.position.y) : [...lanes];
|
|
1358
1473
|
const hasLanes = sortedLanes.length > 0;
|
|
1474
|
+
const laneIdSet = new Set(sortedLanes.map((l) => l.id));
|
|
1359
1475
|
const nodeLaneId = /* @__PURE__ */ new Map();
|
|
1360
|
-
for (const node of
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1476
|
+
for (const node of mainContent) {
|
|
1477
|
+
const lId = hasLanes && node.parentId && laneIdSet.has(node.parentId) ? node.parentId : "_pool_";
|
|
1478
|
+
nodeLaneId.set(node.id, lId);
|
|
1479
|
+
}
|
|
1480
|
+
const contentIds = new Set(mainContent.map((n) => n.id));
|
|
1481
|
+
const seqEdges = extractSeqEdges(allEdges, contentIds);
|
|
1482
|
+
const backIds = detectBackEdges([...contentIds], seqEdges);
|
|
1483
|
+
const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
|
|
1484
|
+
const columns = assignColumns([...contentIds], fwdEdges);
|
|
1485
|
+
const rows = /* @__PURE__ */ new Map();
|
|
1486
|
+
const contentByLane = /* @__PURE__ */ new Map();
|
|
1487
|
+
for (const node of mainContent) {
|
|
1488
|
+
const lId = nodeLaneId.get(node.id) ?? "_pool_";
|
|
1489
|
+
if (!contentByLane.has(lId)) contentByLane.set(lId, []);
|
|
1490
|
+
contentByLane.get(lId).push(node);
|
|
1491
|
+
}
|
|
1492
|
+
for (const [, laneNodes] of contentByLane) {
|
|
1493
|
+
const laneNodeIds = new Set(laneNodes.map((n) => n.id));
|
|
1494
|
+
const intraEdges = fwdEdges.filter(
|
|
1495
|
+
(e) => laneNodeIds.has(e.source) && laneNodeIds.has(e.target)
|
|
1496
|
+
);
|
|
1497
|
+
const lanePairs = detectGatewayPairs(laneNodes, intraEdges);
|
|
1498
|
+
const laneRows = assignRows(laneNodes, intraEdges, columns, lanePairs);
|
|
1499
|
+
for (const [id, row] of laneRows) rows.set(id, row);
|
|
1366
1500
|
}
|
|
1367
1501
|
const laneIds = hasLanes ? sortedLanes.map((l) => l.id) : ["_pool_"];
|
|
1368
1502
|
const laneStats = /* @__PURE__ */ new Map();
|
|
1369
1503
|
for (const laneId of laneIds) {
|
|
1370
|
-
const laneRows =
|
|
1504
|
+
const laneRows = mainContent.filter((n) => nodeLaneId.get(n.id) === laneId).map((n) => rows.get(n.id) ?? 0);
|
|
1371
1505
|
if (laneRows.length === 0) {
|
|
1372
1506
|
laneStats.set(laneId, { minRow: 0, maxRow: 0, rowCount: 1, height: LANE_MIN_H });
|
|
1373
1507
|
} else {
|
|
@@ -1382,7 +1516,7 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
1382
1516
|
const maxCol = Math.max(0, ...[...columns.values()]);
|
|
1383
1517
|
const colW = /* @__PURE__ */ new Map();
|
|
1384
1518
|
for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
|
|
1385
|
-
for (const node of
|
|
1519
|
+
for (const node of mainContent) {
|
|
1386
1520
|
const c = columns.get(node.id) ?? 0;
|
|
1387
1521
|
colW.set(c, Math.max(colW.get(c) ?? 0, nW(node)));
|
|
1388
1522
|
}
|
|
@@ -1405,7 +1539,7 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
1405
1539
|
if (i < laneIds.length - 1) cumY += POOL_INNER_PAD;
|
|
1406
1540
|
}
|
|
1407
1541
|
const poolH = cumY + POOL_INNER_PAD;
|
|
1408
|
-
const positionedContent =
|
|
1542
|
+
const positionedContent = mainContent.map((node) => {
|
|
1409
1543
|
const c = columns.get(node.id) ?? 0;
|
|
1410
1544
|
const r = rows.get(node.id) ?? 0;
|
|
1411
1545
|
const laneId = nodeLaneId.get(node.id) ?? "_pool_";
|
|
@@ -1413,14 +1547,14 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
1413
1547
|
const lYOff = laneY.get(laneId) ?? 0;
|
|
1414
1548
|
const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - nW(node) / 2;
|
|
1415
1549
|
const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - nH(node) / 2;
|
|
1416
|
-
const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
|
|
1417
1550
|
const contentH_stat = stat.rowCount * ROW_HEIGHT + Math.max(0, stat.rowCount - 1) * ROW_GAP;
|
|
1418
1551
|
const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - contentH_stat) / 2);
|
|
1552
|
+
const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
|
|
1419
1553
|
const x = isLaneChild ? LANE_LABEL_W + LANE_H_PAD + colOffset : POOL_H_PAD + colOffset;
|
|
1420
1554
|
const y = isLaneChild ? vertTopOffset + rowOffset : lYOff + vertTopOffset + rowOffset;
|
|
1421
1555
|
return { ...node, position: { x, y } };
|
|
1422
1556
|
});
|
|
1423
|
-
const NODE_MIN_GAP =
|
|
1557
|
+
const NODE_MIN_GAP = 24;
|
|
1424
1558
|
const resolvedContent = [...positionedContent];
|
|
1425
1559
|
for (const laneId of laneIds) {
|
|
1426
1560
|
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);
|
|
@@ -1437,30 +1571,24 @@ function layoutPool(pool, lanes, content, allEdges) {
|
|
|
1437
1571
|
if (prevRight + NODE_MIN_GAP > curr.position.x) {
|
|
1438
1572
|
resolvedContent[laneNodeIndices[k].i] = {
|
|
1439
1573
|
...curr,
|
|
1440
|
-
position: {
|
|
1441
|
-
x: prevRight + NODE_MIN_GAP,
|
|
1442
|
-
y: curr.position.y
|
|
1443
|
-
}
|
|
1574
|
+
position: { x: prevRight + NODE_MIN_GAP, y: curr.position.y }
|
|
1444
1575
|
};
|
|
1445
1576
|
}
|
|
1446
1577
|
}
|
|
1447
1578
|
}
|
|
1579
|
+
const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, resolvedContent);
|
|
1448
1580
|
const positionedLanes = hasLanes ? sortedLanes.map((lane) => ({
|
|
1449
1581
|
...lane,
|
|
1450
|
-
// x: after pool label strip + left inner padding
|
|
1451
|
-
// y: laneY already includes top POOL_INNER_PAD offset
|
|
1452
1582
|
position: { x: POOL_INNER_PAD, y: laneY.get(lane.id) ?? POOL_INNER_PAD },
|
|
1453
1583
|
width: laneW,
|
|
1454
1584
|
height: laneStats.get(lane.id)?.height ?? LANE_MIN_H
|
|
1455
1585
|
})) : [];
|
|
1456
1586
|
return {
|
|
1457
|
-
nodes: [...resolvedContent, ...positionedLanes],
|
|
1587
|
+
nodes: [...resolvedContent, ...positionedBoundaries, ...positionedLanes],
|
|
1458
1588
|
width: poolW,
|
|
1459
1589
|
height: poolH
|
|
1460
1590
|
};
|
|
1461
1591
|
}
|
|
1462
|
-
var BACK_EDGE_CLEARANCE = 50;
|
|
1463
|
-
var SAME_ROW_THRESHOLD = 15;
|
|
1464
1592
|
function absolutePos(nodeId, byId, cache) {
|
|
1465
1593
|
const cached = cache.get(nodeId);
|
|
1466
1594
|
if (cached) return cached;
|
|
@@ -1479,10 +1607,17 @@ function absolutePos(nodeId, byId, cache) {
|
|
|
1479
1607
|
function laneOf(node, laneIds) {
|
|
1480
1608
|
return node.parentId && laneIds.has(node.parentId) ? node.parentId : void 0;
|
|
1481
1609
|
}
|
|
1610
|
+
function gapMidX(sAbs, sW, tAbs, tW) {
|
|
1611
|
+
const leftRightEdge = Math.min(sAbs.x + sW, tAbs.x + tW);
|
|
1612
|
+
const rightLeftEdge = Math.max(sAbs.x, tAbs.x);
|
|
1613
|
+
return leftRightEdge < rightLeftEdge ? (leftRightEdge + rightLeftEdge) / 2 : sAbs.x + sW / 2;
|
|
1614
|
+
}
|
|
1615
|
+
var SAME_ROW_THRESHOLD = 15;
|
|
1482
1616
|
function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
1483
1617
|
const byId = new Map(layoutNodes.map((n) => [n.id, n]));
|
|
1484
1618
|
const cache = /* @__PURE__ */ new Map();
|
|
1485
1619
|
const abs = (id) => absolutePos(id, byId, cache);
|
|
1620
|
+
const sortedLanes = [...laneIds].map((id) => byId.get(id)).filter((n) => !!n).sort((a, b) => abs(a.id).y - abs(b.id).y);
|
|
1486
1621
|
return edges.map((edge) => {
|
|
1487
1622
|
const edgeType = edge.data?.edgeType ?? edge.type;
|
|
1488
1623
|
if (edgeType !== "sequenceFlow") {
|
|
@@ -1497,11 +1632,22 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
1497
1632
|
const tAbs = abs(tgt.id);
|
|
1498
1633
|
const sW = nW(src), sH = nH(src);
|
|
1499
1634
|
const tW = nW(tgt), tH = nH(tgt);
|
|
1500
|
-
const sCX = sAbs.x + sW / 2
|
|
1501
|
-
const tCX = tAbs.x + tW / 2
|
|
1502
|
-
const
|
|
1503
|
-
const
|
|
1504
|
-
|
|
1635
|
+
const sCX = sAbs.x + sW / 2;
|
|
1636
|
+
const tCX = tAbs.x + tW / 2;
|
|
1637
|
+
const sCY = sAbs.y + sH / 2;
|
|
1638
|
+
const tCY = tAbs.y + tH / 2;
|
|
1639
|
+
const getPool = (nodeId) => {
|
|
1640
|
+
const node = byId.get(nodeId);
|
|
1641
|
+
if (!node) return null;
|
|
1642
|
+
if (poolIds.has(nodeId)) return nodeId;
|
|
1643
|
+
if (node.parentId && poolIds.has(node.parentId)) return node.parentId;
|
|
1644
|
+
if (node.parentId) {
|
|
1645
|
+
const gp = byId.get(node.parentId)?.parentId ?? null;
|
|
1646
|
+
if (gp && poolIds.has(gp)) return gp;
|
|
1647
|
+
}
|
|
1648
|
+
return node.parentId ?? null;
|
|
1649
|
+
};
|
|
1650
|
+
if (getPool(edge.source) !== getPool(edge.target)) {
|
|
1505
1651
|
const d = { ...edge.data };
|
|
1506
1652
|
delete d.routingPoints;
|
|
1507
1653
|
return { ...edge, data: d };
|
|
@@ -1511,33 +1657,49 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
1511
1657
|
const topY = Math.min(sAbs.y, tAbs.y) - BACK_EDGE_CLEARANCE;
|
|
1512
1658
|
routingPoints = [
|
|
1513
1659
|
{ x: sCX, y: sAbs.y },
|
|
1514
|
-
// [0] discarded
|
|
1515
1660
|
{ x: sCX, y: topY },
|
|
1516
|
-
// [1] go up
|
|
1517
1661
|
{ x: tCX, y: topY },
|
|
1518
|
-
|
|
1519
|
-
{ x: tCX, y: tAbs.y }
|
|
1520
|
-
// [3] discarded
|
|
1662
|
+
{ x: tCX, y: tAbs.y + tH }
|
|
1521
1663
|
];
|
|
1522
1664
|
} else if (laneOf(src, laneIds) !== laneOf(tgt, laneIds)) {
|
|
1523
|
-
const goingDown = tAbs.y > sAbs.y;
|
|
1524
|
-
const sharedX = Math.abs(sCX - tCX) < 10 ? sCX : (sCX + tCX) / 2;
|
|
1525
1665
|
const srcLane = byId.get(src.parentId ?? "");
|
|
1526
1666
|
const tgtLane = byId.get(tgt.parentId ?? "");
|
|
1527
1667
|
if (srcLane && tgtLane && laneIds.has(srcLane.id) && laneIds.has(tgtLane.id)) {
|
|
1528
|
-
const
|
|
1529
|
-
const
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
{ x: sharedX, y:
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1668
|
+
const goingDown = tAbs.y > sAbs.y;
|
|
1669
|
+
const sharedX = gapMidX(sAbs, sW, tAbs, tW);
|
|
1670
|
+
const srcLaneIdx = sortedLanes.findIndex((l) => l.id === srcLane.id);
|
|
1671
|
+
const tgtLaneIdx = sortedLanes.findIndex((l) => l.id === tgtLane.id);
|
|
1672
|
+
const pts = [];
|
|
1673
|
+
if (goingDown) {
|
|
1674
|
+
pts.push({ x: sCX, y: sAbs.y + sH });
|
|
1675
|
+
pts.push({ x: sharedX, y: sAbs.y + sH });
|
|
1676
|
+
const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
|
|
1677
|
+
const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
|
|
1678
|
+
for (let i = fromIdx; i < toIdx; i++) {
|
|
1679
|
+
const lane = sortedLanes[i];
|
|
1680
|
+
const laneBot = abs(lane.id).y + (lane.height ?? LANE_MIN_H);
|
|
1681
|
+
pts.push({ x: sharedX, y: laneBot });
|
|
1682
|
+
}
|
|
1683
|
+
const lastY = pts[pts.length - 1].y;
|
|
1684
|
+
pts.push({ x: tCX, y: lastY });
|
|
1685
|
+
pts.push({ x: tCX, y: tAbs.y + tH });
|
|
1686
|
+
} else {
|
|
1687
|
+
pts.push({ x: sCX, y: sAbs.y });
|
|
1688
|
+
pts.push({ x: sharedX, y: sAbs.y });
|
|
1689
|
+
const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
|
|
1690
|
+
const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
|
|
1691
|
+
for (let i = toIdx; i > fromIdx; i--) {
|
|
1692
|
+
const lane = sortedLanes[i];
|
|
1693
|
+
const laneTop = abs(lane.id).y;
|
|
1694
|
+
pts.push({ x: sharedX, y: laneTop });
|
|
1695
|
+
}
|
|
1696
|
+
const lastY = pts[pts.length - 1].y;
|
|
1697
|
+
pts.push({ x: tCX, y: lastY });
|
|
1698
|
+
pts.push({ x: tCX, y: tAbs.y });
|
|
1699
|
+
}
|
|
1700
|
+
routingPoints = pts;
|
|
1540
1701
|
} else {
|
|
1702
|
+
const sharedX = gapMidX(sAbs, sW, tAbs, tW);
|
|
1541
1703
|
routingPoints = [
|
|
1542
1704
|
{ x: sCX, y: sCY },
|
|
1543
1705
|
{ x: sharedX, y: sCY },
|
|
@@ -1556,39 +1718,108 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
|
|
|
1556
1718
|
if (exitsTop || exitsBottom) {
|
|
1557
1719
|
routingPoints = [
|
|
1558
1720
|
{ x: sCX, y: exitsTop ? sAbs.y : sAbs.y + sH },
|
|
1559
|
-
// [0] discarded
|
|
1560
1721
|
{ x: sCX, y: tCY },
|
|
1561
|
-
// [1] vertical to target row
|
|
1562
1722
|
{ x: tCX, y: tCY },
|
|
1563
|
-
// [2] horizontal to target
|
|
1564
1723
|
{ x: tCX, y: exitsTop ? tAbs.y + tH : tAbs.y }
|
|
1565
|
-
// [3] discarded
|
|
1566
1724
|
];
|
|
1567
1725
|
} else {
|
|
1568
|
-
const
|
|
1569
|
-
const midX = goingRight ? sAbs.x + sW + COL_GAP / 2 : sAbs.x - COL_GAP / 2;
|
|
1726
|
+
const midX = gapMidX(sAbs, sW, tAbs, tW);
|
|
1570
1727
|
routingPoints = [
|
|
1571
1728
|
{ x: sAbs.x + sW, y: sCY },
|
|
1572
|
-
// [0] discarded
|
|
1573
1729
|
{ x: midX, y: sCY },
|
|
1574
|
-
// [1] horizontal exit
|
|
1575
1730
|
{ x: midX, y: tCY },
|
|
1576
|
-
// [2] vertical to target row
|
|
1577
1731
|
{ x: tAbs.x, y: tCY }
|
|
1578
|
-
// [3] discarded
|
|
1579
1732
|
];
|
|
1580
1733
|
}
|
|
1581
1734
|
}
|
|
1582
1735
|
return { ...edge, data: { ...edge.data, routingPoints } };
|
|
1583
1736
|
});
|
|
1584
1737
|
}
|
|
1738
|
+
var ARTIFACT_ABOVE_GAP = 16;
|
|
1739
|
+
var ARTIFACT_H_SPACING = 12;
|
|
1740
|
+
function positionArtifacts(artifacts, resultNodes, edges) {
|
|
1741
|
+
if (artifacts.length === 0) return [];
|
|
1742
|
+
const byId = new Map(resultNodes.map((n) => [n.id, n]));
|
|
1743
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1744
|
+
const absPos = (id) => absolutePos(id, byId, cache);
|
|
1745
|
+
const artifactsByNode = /* @__PURE__ */ new Map();
|
|
1746
|
+
const ungrouped = [];
|
|
1747
|
+
for (const artifact of artifacts) {
|
|
1748
|
+
if (artifact.data.elementType === "Group") {
|
|
1749
|
+
ungrouped.push(artifact);
|
|
1750
|
+
continue;
|
|
1751
|
+
}
|
|
1752
|
+
const connEdge = edges.find((e) => {
|
|
1753
|
+
const t = e.data?.edgeType ?? e.type;
|
|
1754
|
+
return (t === "association" || t === "dataAssociation") && (e.source === artifact.id || e.target === artifact.id);
|
|
1755
|
+
});
|
|
1756
|
+
if (!connEdge) {
|
|
1757
|
+
ungrouped.push(artifact);
|
|
1758
|
+
continue;
|
|
1759
|
+
}
|
|
1760
|
+
const connId = connEdge.source === artifact.id ? connEdge.target : connEdge.source;
|
|
1761
|
+
if (!byId.has(connId)) {
|
|
1762
|
+
ungrouped.push(artifact);
|
|
1763
|
+
continue;
|
|
1764
|
+
}
|
|
1765
|
+
if (!artifactsByNode.has(connId)) artifactsByNode.set(connId, []);
|
|
1766
|
+
artifactsByNode.get(connId).push(artifact);
|
|
1767
|
+
}
|
|
1768
|
+
const positioned = [...ungrouped];
|
|
1769
|
+
for (const [connId, arts] of artifactsByNode) {
|
|
1770
|
+
const connNode = byId.get(connId);
|
|
1771
|
+
const connAbsP = absPos(connId);
|
|
1772
|
+
const totalW = arts.reduce((s, a) => s + nW(a), 0) + (arts.length - 1) * ARTIFACT_H_SPACING;
|
|
1773
|
+
const desiredAbsY = connAbsP.y - ARTIFACT_ABOVE_GAP - Math.max(...arts.map(nH));
|
|
1774
|
+
let desiredAbsX = connAbsP.x + nW(connNode) / 2 - totalW / 2;
|
|
1775
|
+
for (const artifact of arts) {
|
|
1776
|
+
const parentAbsP = artifact.parentId ? absPos(artifact.parentId) : { x: 0, y: 0 };
|
|
1777
|
+
positioned.push({
|
|
1778
|
+
...artifact,
|
|
1779
|
+
position: {
|
|
1780
|
+
x: desiredAbsX - parentAbsP.x,
|
|
1781
|
+
y: desiredAbsY - parentAbsP.y
|
|
1782
|
+
}
|
|
1783
|
+
});
|
|
1784
|
+
desiredAbsX += nW(artifact) + ARTIFACT_H_SPACING;
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
return positioned;
|
|
1788
|
+
}
|
|
1585
1789
|
async function bpmnCustomLayout(nodes, edges) {
|
|
1586
|
-
const
|
|
1587
|
-
const
|
|
1588
|
-
const
|
|
1790
|
+
const artifacts = nodes.filter((n) => LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
|
|
1791
|
+
const mainNodes = nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
|
|
1792
|
+
const pools = mainNodes.filter((n) => n.data.elementType === "Pool");
|
|
1793
|
+
const lanes = mainNodes.filter((n) => n.data.elementType === "Lane");
|
|
1794
|
+
const expandedSubProcesses = mainNodes.filter(
|
|
1795
|
+
(n) => COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType) && n.data.isExpanded
|
|
1796
|
+
);
|
|
1797
|
+
const subProcessLayouts = /* @__PURE__ */ new Map();
|
|
1798
|
+
const workingMainNodes = [...mainNodes];
|
|
1799
|
+
for (const sp of expandedSubProcesses) {
|
|
1800
|
+
const spChildren = workingMainNodes.filter((n) => n.parentId === sp.id);
|
|
1801
|
+
const result = layoutSubProcess(spChildren, edges);
|
|
1802
|
+
subProcessLayouts.set(sp.id, result);
|
|
1803
|
+
const spIdx = workingMainNodes.findIndex((n) => n.id === sp.id);
|
|
1804
|
+
if (spIdx >= 0) {
|
|
1805
|
+
workingMainNodes[spIdx] = {
|
|
1806
|
+
...workingMainNodes[spIdx],
|
|
1807
|
+
width: result.width,
|
|
1808
|
+
height: result.height,
|
|
1809
|
+
measured: { width: result.width, height: result.height }
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
const content = workingMainNodes.filter((n) => {
|
|
1814
|
+
if (!LAYOUT_CONTAINER_TYPES.has(n.data.elementType)) return true;
|
|
1815
|
+
if (COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)) return true;
|
|
1816
|
+
return false;
|
|
1817
|
+
});
|
|
1589
1818
|
if (pools.length === 0) {
|
|
1590
1819
|
const { bpmnElkLayout: bpmnElkLayout2 } = await Promise.resolve().then(() => (init_elk(), elk_exports));
|
|
1591
|
-
|
|
1820
|
+
const elkResult = await bpmnElkLayout2(nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType)), edges);
|
|
1821
|
+
const posArtifacts = positionArtifacts(artifacts, elkResult.nodes, edges);
|
|
1822
|
+
return { nodes: [...elkResult.nodes, ...posArtifacts], edges: elkResult.edges };
|
|
1592
1823
|
}
|
|
1593
1824
|
const poolIds = new Set(pools.map((p) => p.id));
|
|
1594
1825
|
const allLaneIds = new Set(lanes.map((l) => l.id));
|
|
@@ -1608,7 +1839,10 @@ async function bpmnCustomLayout(nodes, edges) {
|
|
|
1608
1839
|
const poolContent = content.filter(
|
|
1609
1840
|
(n) => n.parentId === pool.id || n.parentId != null && laneIds.has(n.parentId)
|
|
1610
1841
|
);
|
|
1611
|
-
const
|
|
1842
|
+
const poolBoundaries = workingMainNodes.filter(
|
|
1843
|
+
(n) => n.data.elementType === "BoundaryEvent" && (n.parentId === pool.id || n.parentId != null && laneIds.has(n.parentId))
|
|
1844
|
+
);
|
|
1845
|
+
const result = layoutPool(pool, poolLanes, [...poolContent, ...poolBoundaries], edges);
|
|
1612
1846
|
resultNodes.push({
|
|
1613
1847
|
...pool,
|
|
1614
1848
|
position: { x: 0, y: stackY },
|
|
@@ -1620,12 +1854,44 @@ async function bpmnCustomLayout(nodes, edges) {
|
|
|
1620
1854
|
}
|
|
1621
1855
|
stackY += result.height + POOL_V_GAP;
|
|
1622
1856
|
}
|
|
1857
|
+
for (const [, spLayout] of subProcessLayouts) {
|
|
1858
|
+
for (const child of spLayout.children) {
|
|
1859
|
+
resultNodes.push(child);
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1623
1862
|
const layoutted = new Set(resultNodes.map((n) => n.id));
|
|
1624
|
-
|
|
1625
|
-
|
|
1863
|
+
const freeNodes = workingMainNodes.filter((n) => !layoutted.has(n.id));
|
|
1864
|
+
if (freeNodes.length > 0) {
|
|
1865
|
+
const freeEdges = edges.filter(
|
|
1866
|
+
(e) => freeNodes.some((n) => n.id === e.source || n.id === e.target)
|
|
1867
|
+
);
|
|
1868
|
+
try {
|
|
1869
|
+
const { bpmnElkLayout: bpmnElkLayout2 } = await Promise.resolve().then(() => (init_elk(), elk_exports));
|
|
1870
|
+
const elkFree = await bpmnElkLayout2(freeNodes, freeEdges);
|
|
1871
|
+
const offsetY = stackY;
|
|
1872
|
+
for (const node of elkFree.nodes) {
|
|
1873
|
+
resultNodes.push({
|
|
1874
|
+
...node,
|
|
1875
|
+
position: { x: node.position.x, y: node.position.y + offsetY }
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
const freeEdgeIds = new Set(freeEdges.map((e) => e.id));
|
|
1879
|
+
const elkEdgeMap = new Map(elkFree.edges.map((e) => [e.id, e]));
|
|
1880
|
+
for (let i = 0; i < edges.length; i++) {
|
|
1881
|
+
if (freeEdgeIds.has(edges[i].id) && elkEdgeMap.has(edges[i].id)) {
|
|
1882
|
+
edges[i] = elkEdgeMap.get(edges[i].id);
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
} catch {
|
|
1886
|
+
for (const node of freeNodes) resultNodes.push(node);
|
|
1887
|
+
}
|
|
1626
1888
|
}
|
|
1627
1889
|
const routedEdges = routeEdges(edges, resultNodes, allBackEdgeIds, allLaneIds, poolIds);
|
|
1628
|
-
|
|
1890
|
+
const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges);
|
|
1891
|
+
return {
|
|
1892
|
+
nodes: [...resultNodes, ...positionedArtifacts],
|
|
1893
|
+
edges: routedEdges
|
|
1894
|
+
};
|
|
1629
1895
|
}
|
|
1630
1896
|
|
|
1631
1897
|
// src/layout/index.ts
|