@aranzatech/diagrams-bpmn 0.3.4 → 0.3.5

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.
@@ -514,23 +514,44 @@ function layoutPool(pool, lanes, content, allEdges) {
514
514
  laneStats.set(laneId, { minRow, maxRow, rowCount, height });
515
515
  }
516
516
  }
517
- const maxCol = Math.max(0, ...[...columns.values()]);
518
- const colW = /* @__PURE__ */ new Map();
519
- for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
520
- for (const node of mainContent) {
521
- const c = columns.get(node.id) ?? 0;
522
- colW.set(c, Math.max(colW.get(c) ?? 0, layoutW(node)));
523
- }
524
- const colX = /* @__PURE__ */ new Map();
525
- let cumX = 0;
526
- for (let c = 0; c <= maxCol; c++) {
527
- colX.set(c, cumX);
528
- cumX += (colW.get(c) ?? 120) + COL_GAP;
517
+ const laneColumnLayouts = /* @__PURE__ */ new Map();
518
+ for (const laneId of laneIds) {
519
+ const laneNodes = mainContent.filter(
520
+ (node) => (nodeLaneId.get(node.id) ?? "_pool_") === laneId
521
+ );
522
+ const usedCols = [...new Set(laneNodes.map((node) => columns.get(node.id) ?? 0))].sort((a, b) => a - b);
523
+ const colW = /* @__PURE__ */ new Map();
524
+ for (const col of usedCols) colW.set(col, 0);
525
+ for (const node of laneNodes) {
526
+ const col = columns.get(node.id) ?? 0;
527
+ colW.set(col, Math.max(colW.get(col) ?? 0, layoutW(node)));
528
+ }
529
+ const colX = /* @__PURE__ */ new Map();
530
+ let laneCumX = 0;
531
+ for (const col of usedCols) {
532
+ colX.set(col, laneCumX);
533
+ laneCumX += (colW.get(col) ?? 120) + COL_GAP;
534
+ }
535
+ laneColumnLayouts.set(laneId, {
536
+ colW,
537
+ colX,
538
+ contentW: usedCols.length > 0 ? laneCumX - COL_GAP : 0
539
+ });
529
540
  }
530
- const contentW = cumX - COL_GAP;
531
- const innerW = LANE_LABEL_W + LANE_H_PAD + contentW + LANE_H_PAD;
541
+ const baseLaneInnerW = Math.max(
542
+ 0,
543
+ ...laneIds.filter((laneId) => laneId !== "_pool_").map((laneId) => {
544
+ const contentW = laneColumnLayouts.get(laneId)?.contentW ?? 0;
545
+ return LANE_LABEL_W + LANE_H_PAD + contentW + LANE_H_PAD;
546
+ })
547
+ );
548
+ const basePoolInnerW = Math.max(
549
+ 0,
550
+ ...laneIds.filter((laneId) => laneId === "_pool_").map((laneId) => (laneColumnLayouts.get(laneId)?.contentW ?? 0) + POOL_H_PAD * 2)
551
+ );
552
+ const innerW = Math.max(baseLaneInnerW, basePoolInnerW);
532
553
  const poolW = Math.max(POOL_MIN_W, innerW + POOL_INNER_PAD * 2);
533
- const laneW = poolW - POOL_INNER_PAD * 2;
554
+ let laneW = poolW - POOL_INNER_PAD * 2;
534
555
  const laneY = /* @__PURE__ */ new Map();
535
556
  let cumY = POOL_INNER_PAD;
536
557
  for (let i = 0; i < laneIds.length; i++) {
@@ -545,10 +566,11 @@ function layoutPool(pool, lanes, content, allEdges) {
545
566
  const r = rows.get(node.id) ?? 0;
546
567
  const laneId = nodeLaneId.get(node.id) ?? "_pool_";
547
568
  const stat = laneStats.get(laneId);
569
+ const laneLayout = laneColumnLayouts.get(laneId);
548
570
  const lYOff = laneY.get(laneId) ?? 0;
549
571
  const lw = layoutW(node);
550
572
  const lh = layoutH(node);
551
- const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - lw / 2;
573
+ const colOffset = (laneLayout?.colX.get(c) ?? 0) + (laneLayout?.colW.get(c) ?? 120) / 2 - lw / 2;
552
574
  const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - lh / 2;
553
575
  const contentH_stat = stat.rowCount * ROW_HEIGHT + Math.max(0, stat.rowCount - 1) * ROW_GAP;
554
576
  const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - contentH_stat) / 2);
@@ -557,8 +579,94 @@ function layoutPool(pool, lanes, content, allEdges) {
557
579
  const y = isLaneChild ? vertTopOffset + rowOffset : lYOff + vertTopOffset + rowOffset;
558
580
  return applyLayoutMinSize({ ...node, position: { x, y } });
559
581
  });
582
+ const handoffAdjustedContent = [...positionedContent];
583
+ const nodeIndexById = new Map(handoffAdjustedContent.map((node, index) => [node.id, index]));
584
+ const outgoingBySource = /* @__PURE__ */ new Map();
585
+ for (const edge of fwdEdges) {
586
+ if (!outgoingBySource.has(edge.source)) outgoingBySource.set(edge.source, []);
587
+ outgoingBySource.get(edge.source).push(edge);
588
+ }
589
+ const crossLaneEdges = fwdEdges.filter((edge) => {
590
+ const srcLane = nodeLaneId.get(edge.source) ?? "_pool_";
591
+ const tgtLane = nodeLaneId.get(edge.target) ?? "_pool_";
592
+ return srcLane !== tgtLane;
593
+ }).sort(
594
+ (a, b) => (columns.get(a.target) ?? 0) - (columns.get(b.target) ?? 0) || (columns.get(a.source) ?? 0) - (columns.get(b.source) ?? 0)
595
+ );
596
+ for (const edge of crossLaneEdges) {
597
+ const srcIndex = nodeIndexById.get(edge.source);
598
+ const tgtIndex = nodeIndexById.get(edge.target);
599
+ if (srcIndex == null || tgtIndex == null) continue;
600
+ const srcNode = handoffAdjustedContent[srcIndex];
601
+ const tgtNode = handoffAdjustedContent[tgtIndex];
602
+ const tgtLaneId = nodeLaneId.get(tgtNode.id) ?? "_pool_";
603
+ const tgtCol = columns.get(tgtNode.id) ?? 0;
604
+ const siblingTargets = (outgoingBySource.get(edge.source) ?? []).filter((candidate) => (columns.get(candidate.target) ?? 0) === tgtCol).map((candidate) => handoffAdjustedContent[nodeIndexById.get(candidate.target) ?? -1]).filter((node) => !!node);
605
+ const siblingAlignedX = siblingTargets.reduce(
606
+ (max, node) => Math.max(max, node.position.x),
607
+ Number.NEGATIVE_INFINITY
608
+ );
609
+ const minTargetX = Math.max(
610
+ siblingAlignedX,
611
+ srcNode.position.x + layoutW(srcNode) / 2 + layoutW(tgtNode) / 2 + COL_GAP
612
+ );
613
+ if (tgtNode.position.x >= minTargetX) continue;
614
+ const delta = minTargetX - tgtNode.position.x;
615
+ for (let i = 0; i < handoffAdjustedContent.length; i++) {
616
+ const candidate = handoffAdjustedContent[i];
617
+ if ((nodeLaneId.get(candidate.id) ?? "_pool_") !== tgtLaneId) continue;
618
+ if ((columns.get(candidate.id) ?? 0) < tgtCol) continue;
619
+ handoffAdjustedContent[i] = {
620
+ ...candidate,
621
+ position: {
622
+ x: candidate.position.x + delta,
623
+ y: candidate.position.y
624
+ }
625
+ };
626
+ }
627
+ }
628
+ for (const [sourceId, outgoing] of outgoingBySource) {
629
+ if (outgoing.length < 2) continue;
630
+ const hasCrossLaneSibling = outgoing.some((edge) => {
631
+ const srcLane = nodeLaneId.get(edge.source) ?? "_pool_";
632
+ const tgtLane = nodeLaneId.get(edge.target) ?? "_pool_";
633
+ return srcLane !== tgtLane;
634
+ });
635
+ if (!hasCrossLaneSibling) continue;
636
+ const siblingsByCol = /* @__PURE__ */ new Map();
637
+ for (const edge of outgoing) {
638
+ const col = columns.get(edge.target) ?? 0;
639
+ const node = handoffAdjustedContent[nodeIndexById.get(edge.target) ?? -1];
640
+ if (!node) continue;
641
+ if (!siblingsByCol.has(col)) siblingsByCol.set(col, []);
642
+ siblingsByCol.get(col).push(node);
643
+ }
644
+ for (const [col, siblings] of siblingsByCol) {
645
+ if (siblings.length < 2) continue;
646
+ const alignedX = Math.max(...siblings.map((node) => node.position.x));
647
+ for (let i = 0; i < handoffAdjustedContent.length; i++) {
648
+ const candidate = handoffAdjustedContent[i];
649
+ if (!siblings.some((node) => node.id === candidate.id)) continue;
650
+ const laneId = nodeLaneId.get(candidate.id) ?? "_pool_";
651
+ for (let j = 0; j < handoffAdjustedContent.length; j++) {
652
+ const maybeShift = handoffAdjustedContent[j];
653
+ if ((nodeLaneId.get(maybeShift.id) ?? "_pool_") !== laneId) continue;
654
+ if ((columns.get(maybeShift.id) ?? 0) < col) continue;
655
+ const delta = alignedX - candidate.position.x;
656
+ if (delta <= 0) continue;
657
+ handoffAdjustedContent[j] = {
658
+ ...maybeShift,
659
+ position: {
660
+ x: maybeShift.position.x + delta,
661
+ y: maybeShift.position.y
662
+ }
663
+ };
664
+ }
665
+ }
666
+ }
667
+ }
560
668
  const NODE_MIN_GAP = 24;
561
- const resolvedContent = [...positionedContent];
669
+ const resolvedContent = [...handoffAdjustedContent];
562
670
  for (const laneId of laneIds) {
563
671
  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);
564
672
  for (let k = 1; k < laneNodeIndices.length; k++) {
@@ -580,6 +688,15 @@ function layoutPool(pool, lanes, content, allEdges) {
580
688
  }
581
689
  }
582
690
  const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, resolvedContent);
691
+ const laneChildRight = resolvedContent.filter((node) => hasLanes && !!node.parentId && node.parentId !== pool.id).reduce((max, node) => Math.max(max, node.position.x + nW(node) + LANE_H_PAD), 0);
692
+ const poolChildRight = resolvedContent.filter((node) => !hasLanes || !node.parentId || node.parentId === pool.id).reduce((max, node) => Math.max(max, node.position.x + nW(node) + POOL_H_PAD), 0);
693
+ const boundaryRight = positionedBoundaries.reduce(
694
+ (max, node) => Math.max(max, node.position.x + nW(node) + (hasLanes ? LANE_H_PAD : POOL_H_PAD)),
695
+ 0
696
+ );
697
+ const finalInnerW = Math.max(innerW, laneChildRight, poolChildRight, boundaryRight);
698
+ const finalPoolW = Math.max(POOL_MIN_W, finalInnerW + POOL_INNER_PAD * 2);
699
+ laneW = finalPoolW - POOL_INNER_PAD * 2;
583
700
  const positionedLanes = hasLanes ? sortedLanes.map((lane) => ({
584
701
  ...lane,
585
702
  position: { x: POOL_INNER_PAD, y: laneY.get(lane.id) ?? POOL_INNER_PAD },
@@ -588,7 +705,7 @@ function layoutPool(pool, lanes, content, allEdges) {
588
705
  })) : [];
589
706
  return {
590
707
  nodes: [...resolvedContent, ...positionedBoundaries, ...positionedLanes],
591
- width: poolW,
708
+ width: finalPoolW,
592
709
  height: poolH
593
710
  };
594
711
  }