diff --git a/packages/system/src/utils/edges/smoothstep-edge.ts b/packages/system/src/utils/edges/smoothstep-edge.ts index 3b6730e7..60e0e9dc 100644 --- a/packages/system/src/utils/edges/smoothstep-edge.ts +++ b/packages/system/src/utils/edges/smoothstep-edge.ts @@ -69,6 +69,9 @@ function getPoints({ let points: XYPosition[] = []; let centerX, centerY; + const sourceGapOffset = { x: 0, y: 0 }; + const targetGapOffset = { x: 0, y: 0 }; + const [defaultCenterX, defaultCenterY, defaultOffsetX, defaultOffsetY] = getEdgeCenter({ sourceX: source.x, sourceY: source.y, @@ -111,6 +114,20 @@ function getPoints({ points = sourceDir.y === currDir ? sourceTarget : targetSource; } + if (sourcePosition === targetPosition) { + const diff = Math.abs(source[dirAccessor] - target[dirAccessor]); + + // if an edge goes from right to right for example (sourcePosition === targetPosition) and the distance between source.x and target.x is less than the offset, the added point and the gapped source/target will overlap. This leads to a weird edge path. To avoid this we add a gapOffset to the source/target + if (diff <= offset) { + const gapOffset = Math.min(offset - 1, offset - diff); + if (sourceDir[dirAccessor] === currDir) { + sourceGapOffset[dirAccessor] = gapOffset; + } else { + targetGapOffset[dirAccessor] = gapOffset; + } + } + } + // these are conditions for handling mixed handle positions like Right -> Bottom for example if (sourcePosition !== targetPosition) { const dirAccessorOpposite = dirAccessor === 'x' ? 'y' : 'x'; @@ -126,11 +143,28 @@ function getPoints({ } } - centerX = points[0].x; - centerY = points[0].y; + const sourceGapPoint = { x: sourceGapped.x - sourceGapOffset.x, y: sourceGapped.y - sourceGapOffset.y }; + const targetGapPoint = { x: targetGapped.x - targetGapOffset.x, y: targetGapped.y - targetGapOffset.y }; + const maxXDistance = Math.max(Math.abs(sourceGapPoint.x - points[0].x), Math.abs(targetGapPoint.x - points[0].x)); + const maxYDistance = Math.max(Math.abs(sourceGapPoint.y - points[0].y), Math.abs(targetGapPoint.y - points[0].y)); + + // we want to place the label on the longest segment of the edge + if (maxXDistance >= maxYDistance) { + centerX = (sourceGapPoint.x + targetGapPoint.x) / 2; + centerY = points[0].y; + } else { + centerX = points[0].x; + centerY = (sourceGapPoint.y + targetGapPoint.y) / 2; + } } - const pathPoints = [source, sourceGapped, ...points, targetGapped, target]; + const pathPoints = [ + source, + { x: sourceGapped.x - sourceGapOffset.x, y: sourceGapped.y - sourceGapOffset.y }, + ...points, + { x: targetGapped.x - targetGapOffset.x, y: targetGapped.y - targetGapOffset.y }, + target, + ]; return [pathPoints, centerX, centerY, defaultOffsetX, defaultOffsetY]; }