bpmn-elk-layout 1.0.2 → 1.1.2
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/bin/bpmn-elk-layout.js +149 -4
- package/dist/bin/bpmn-elk-layout.js.map +1 -1
- package/dist/index.js +148 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +148 -3
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.js +148 -3
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +148 -3
- package/dist/index.node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -254,7 +254,6 @@ function isDebugEnabled() {
|
|
|
254
254
|
if (cliMode) return false;
|
|
255
255
|
return typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
|
|
256
256
|
}
|
|
257
|
-
var DEBUG = typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
|
|
258
257
|
|
|
259
258
|
// src/layout/edge-routing/edge-fixer.ts
|
|
260
259
|
var EdgeFixer = class {
|
|
@@ -325,6 +324,10 @@ var EdgeFixer = class {
|
|
|
325
324
|
const containerNodes = nodesByContainer.get(currentContainerId) ?? /* @__PURE__ */ new Map();
|
|
326
325
|
for (const edge of node.edges) {
|
|
327
326
|
if (edge.sections && edge.sections.length > 0) {
|
|
327
|
+
const hasPoolRelativeCoords = edge._poolRelativeCoords === true;
|
|
328
|
+
if (hasPoolRelativeCoords) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
328
331
|
this.fixEdgeIfCrossing(edge, containerNodes, containerOffsetX, containerOffsetY);
|
|
329
332
|
}
|
|
330
333
|
}
|
|
@@ -2450,7 +2453,15 @@ var LaneArranger = class {
|
|
|
2450
2453
|
const waypoints = [];
|
|
2451
2454
|
waypoints.push({ x: startX, y: startY });
|
|
2452
2455
|
if (Math.abs(startY - endY) > 10) {
|
|
2453
|
-
const midX = (
|
|
2456
|
+
const midX = this.findClearMidX(
|
|
2457
|
+
startX,
|
|
2458
|
+
endX,
|
|
2459
|
+
startY,
|
|
2460
|
+
endY,
|
|
2461
|
+
sourceId,
|
|
2462
|
+
targetId,
|
|
2463
|
+
nodePositions
|
|
2464
|
+
);
|
|
2454
2465
|
waypoints.push({ x: midX, y: startY });
|
|
2455
2466
|
waypoints.push({ x: midX, y: endY });
|
|
2456
2467
|
}
|
|
@@ -2468,6 +2479,109 @@ var LaneArranger = class {
|
|
|
2468
2479
|
}
|
|
2469
2480
|
}
|
|
2470
2481
|
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Find a clear X position for vertical edge segment that avoids obstacles.
|
|
2484
|
+
* Checks all three segments of the L-shaped path:
|
|
2485
|
+
* 1. Horizontal from (startX, startY) to (midX, startY)
|
|
2486
|
+
* 2. Vertical from (midX, startY) to (midX, endY)
|
|
2487
|
+
* 3. Horizontal from (midX, endY) to (endX, endY)
|
|
2488
|
+
*/
|
|
2489
|
+
findClearMidX(startX, endX, startY, endY, sourceId, targetId, nodePositions) {
|
|
2490
|
+
const margin = 15;
|
|
2491
|
+
const minY = Math.min(startY, endY);
|
|
2492
|
+
const maxY = Math.max(startY, endY);
|
|
2493
|
+
const rangeMinX = Math.min(startX, endX);
|
|
2494
|
+
const rangeMaxX = Math.max(startX, endX);
|
|
2495
|
+
if (isDebugEnabled()) {
|
|
2496
|
+
console.log(`[BPMN] findClearMidX: startX=${startX}, endX=${endX}, startY=${startY}, endY=${endY}`);
|
|
2497
|
+
}
|
|
2498
|
+
const allObstacles = [];
|
|
2499
|
+
for (const [nodeId, pos] of nodePositions) {
|
|
2500
|
+
if (nodeId === sourceId || nodeId === targetId) continue;
|
|
2501
|
+
const nodeLeft = pos.x;
|
|
2502
|
+
const nodeRight = pos.x + pos.width;
|
|
2503
|
+
const nodeTop = pos.y;
|
|
2504
|
+
const nodeBottom = pos.y + pos.height;
|
|
2505
|
+
const xOverlap = nodeRight > rangeMinX && nodeLeft < rangeMaxX;
|
|
2506
|
+
const yOverlapVertical = nodeBottom > minY && nodeTop < maxY;
|
|
2507
|
+
const yContainsStartY = nodeTop <= startY && nodeBottom >= startY;
|
|
2508
|
+
const yContainsEndY = nodeTop <= endY && nodeBottom >= endY;
|
|
2509
|
+
if (xOverlap && (yOverlapVertical || yContainsStartY || yContainsEndY)) {
|
|
2510
|
+
allObstacles.push({
|
|
2511
|
+
x: nodeLeft,
|
|
2512
|
+
y: nodeTop,
|
|
2513
|
+
width: pos.width,
|
|
2514
|
+
height: pos.height,
|
|
2515
|
+
right: nodeRight,
|
|
2516
|
+
bottom: nodeBottom,
|
|
2517
|
+
id: nodeId
|
|
2518
|
+
});
|
|
2519
|
+
if (isDebugEnabled()) {
|
|
2520
|
+
console.log(`[BPMN] findClearMidX: obstacle ${nodeId}: x=[${nodeLeft}, ${nodeRight}], y=[${nodeTop}, ${nodeBottom}]`);
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
if (allObstacles.length === 0) {
|
|
2525
|
+
return (startX + endX) / 2;
|
|
2526
|
+
}
|
|
2527
|
+
const isValidMidX = (midX) => {
|
|
2528
|
+
for (const obs of allObstacles) {
|
|
2529
|
+
const seg1MinX = Math.min(startX, midX);
|
|
2530
|
+
const seg1MaxX = Math.max(startX, midX);
|
|
2531
|
+
if (obs.y <= startY && obs.bottom >= startY && // Y range contains startY
|
|
2532
|
+
obs.right > seg1MinX && obs.x < seg1MaxX) {
|
|
2533
|
+
return false;
|
|
2534
|
+
}
|
|
2535
|
+
if (obs.x <= midX && obs.right >= midX && // X range contains midX
|
|
2536
|
+
obs.bottom > minY && obs.y < maxY) {
|
|
2537
|
+
return false;
|
|
2538
|
+
}
|
|
2539
|
+
const seg2MinX = Math.min(midX, endX);
|
|
2540
|
+
const seg2MaxX = Math.max(midX, endX);
|
|
2541
|
+
if (obs.y <= endY && obs.bottom >= endY && // Y range contains endY
|
|
2542
|
+
obs.right > seg2MinX && obs.x < seg2MaxX) {
|
|
2543
|
+
return false;
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
return true;
|
|
2547
|
+
};
|
|
2548
|
+
const candidates = [];
|
|
2549
|
+
candidates.push((startX + endX) / 2);
|
|
2550
|
+
candidates.push(startX + margin);
|
|
2551
|
+
candidates.push(endX - margin);
|
|
2552
|
+
for (const obs of allObstacles) {
|
|
2553
|
+
candidates.push(obs.x - margin);
|
|
2554
|
+
candidates.push(obs.right + margin);
|
|
2555
|
+
}
|
|
2556
|
+
const simpleMidX = (startX + endX) / 2;
|
|
2557
|
+
const validCandidates = candidates.filter((x) => x >= rangeMinX && x <= rangeMaxX).sort((a, b) => Math.abs(a - simpleMidX) - Math.abs(b - simpleMidX));
|
|
2558
|
+
for (const candidate of validCandidates) {
|
|
2559
|
+
if (isValidMidX(candidate)) {
|
|
2560
|
+
if (isDebugEnabled()) {
|
|
2561
|
+
console.log(`[BPMN] findClearMidX: found valid position ${candidate}`);
|
|
2562
|
+
}
|
|
2563
|
+
return candidate;
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
const leftMost = Math.min(...allObstacles.map((o) => o.x)) - margin;
|
|
2567
|
+
const rightMost = Math.max(...allObstacles.map((o) => o.right)) + margin;
|
|
2568
|
+
if (leftMost >= rangeMinX && isValidMidX(leftMost)) {
|
|
2569
|
+
if (isDebugEnabled()) {
|
|
2570
|
+
console.log(`[BPMN] findClearMidX: routing left of all obstacles at ${leftMost}`);
|
|
2571
|
+
}
|
|
2572
|
+
return leftMost;
|
|
2573
|
+
}
|
|
2574
|
+
if (rightMost <= rangeMaxX && isValidMidX(rightMost)) {
|
|
2575
|
+
if (isDebugEnabled()) {
|
|
2576
|
+
console.log(`[BPMN] findClearMidX: routing right of all obstacles at ${rightMost}`);
|
|
2577
|
+
}
|
|
2578
|
+
return rightMost;
|
|
2579
|
+
}
|
|
2580
|
+
if (isDebugEnabled()) {
|
|
2581
|
+
console.log(`[BPMN] findClearMidX: no valid route found, using midpoint ${simpleMidX}`);
|
|
2582
|
+
}
|
|
2583
|
+
return simpleMidX;
|
|
2584
|
+
}
|
|
2471
2585
|
};
|
|
2472
2586
|
|
|
2473
2587
|
// src/layout/post-processing/pool-arranger.ts
|
|
@@ -2548,7 +2662,7 @@ var PoolArranger = class {
|
|
|
2548
2662
|
pool.y = currentY;
|
|
2549
2663
|
if (isBlackBox) {
|
|
2550
2664
|
pool.width = maxPoolWidth;
|
|
2551
|
-
pool.height =
|
|
2665
|
+
pool.height = 60;
|
|
2552
2666
|
} else if (hasLanes) {
|
|
2553
2667
|
pool.width = maxPoolWidth;
|
|
2554
2668
|
} else {
|
|
@@ -5060,6 +5174,7 @@ var DiagramBuilder = class {
|
|
|
5060
5174
|
}
|
|
5061
5175
|
}
|
|
5062
5176
|
}
|
|
5177
|
+
this.ensureOrthogonalWaypoints(waypoints);
|
|
5063
5178
|
const edgeModel = {
|
|
5064
5179
|
id: `${edge.id}_di`,
|
|
5065
5180
|
bpmnElement: edge.id,
|
|
@@ -5126,6 +5241,36 @@ var DiagramBuilder = class {
|
|
|
5126
5241
|
y: (lastPoint?.y ?? 0) - labelHeight - 4
|
|
5127
5242
|
};
|
|
5128
5243
|
}
|
|
5244
|
+
/**
|
|
5245
|
+
* Ensure all waypoint segments are orthogonal (horizontal or vertical)
|
|
5246
|
+
* If a diagonal segment is found, insert intermediate bend points to create
|
|
5247
|
+
* an L-shaped orthogonal path.
|
|
5248
|
+
*
|
|
5249
|
+
* Strategy: For diagonal segments, we use "horizontal first" - go horizontally
|
|
5250
|
+
* to the target X, then vertically to the target Y.
|
|
5251
|
+
*/
|
|
5252
|
+
ensureOrthogonalWaypoints(waypoints) {
|
|
5253
|
+
if (waypoints.length < 2) return;
|
|
5254
|
+
const tolerance = 1;
|
|
5255
|
+
let i = 0;
|
|
5256
|
+
while (i < waypoints.length - 1) {
|
|
5257
|
+
const current = waypoints[i];
|
|
5258
|
+
const next = waypoints[i + 1];
|
|
5259
|
+
if (!current || !next) {
|
|
5260
|
+
i++;
|
|
5261
|
+
continue;
|
|
5262
|
+
}
|
|
5263
|
+
const dx = Math.abs(next.x - current.x);
|
|
5264
|
+
const dy = Math.abs(next.y - current.y);
|
|
5265
|
+
if (dx > tolerance && dy > tolerance) {
|
|
5266
|
+
const bendPoint = { x: next.x, y: current.y };
|
|
5267
|
+
waypoints.splice(i + 1, 0, bendPoint);
|
|
5268
|
+
i++;
|
|
5269
|
+
} else {
|
|
5270
|
+
i++;
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5129
5274
|
};
|
|
5130
5275
|
|
|
5131
5276
|
// src/transform/model-builder.ts
|