Merge pull request #5376 from kennyjwilli/bendposition

feat(smoothstep-edge): add bendPosition parameter to control bend location
This commit is contained in:
Moritz Klack
2025-07-10 11:32:06 +02:00
committed by GitHub
6 changed files with 198 additions and 9 deletions

View File

@@ -36,6 +36,7 @@ function createSmoothStepEdge(params: { isInternal: boolean }) {
targetPosition,
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset,
stepPosition: pathOptions?.stepPosition,
});
const _id = params.isInternal ? undefined : id;

View File

@@ -30,7 +30,8 @@
sourcePosition,
targetPosition,
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset
offset: pathOptions?.offset,
stepPosition: pathOptions?.stepPosition
})
);
</script>

View File

@@ -45,6 +45,7 @@ export type EdgeBase<
export type SmoothStepPathOptions = {
offset?: number;
borderRadius?: number;
stepPosition?: number;
};
export type StepPathOptions = {

View File

@@ -26,6 +26,12 @@ export interface GetSmoothStepPathParams {
centerY?: number;
/** @default 20 */
offset?: number;
/**
* Controls where the bend occurs along the path.
* 0 = at source, 1 = at target, 0.5 = midpoint
* @default 0.5
*/
stepPosition?: number;
}
const handleDirections = {
@@ -63,6 +69,7 @@ function getPoints({
targetPosition = Position.Top,
center,
offset,
stepPosition,
}: {
source: XYPosition;
sourcePosition: Position;
@@ -70,6 +77,7 @@ function getPoints({
targetPosition: Position;
center: Partial<XYPosition>;
offset: number;
stepPosition: number;
}): [XYPosition[], number, number, number, number] {
const sourceDir = handleDirections[sourcePosition];
const targetDir = handleDirections[targetPosition];
@@ -88,7 +96,7 @@ function getPoints({
const sourceGapOffset = { x: 0, y: 0 };
const targetGapOffset = { x: 0, y: 0 };
const [defaultCenterX, defaultCenterY, defaultOffsetX, defaultOffsetY] = getEdgeCenter({
const [, , defaultOffsetX, defaultOffsetY] = getEdgeCenter({
sourceX: source.x,
sourceY: source.y,
targetX: target.x,
@@ -97,8 +105,16 @@ function getPoints({
// opposite handle positions, default case
if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) {
centerX = center.x ?? defaultCenterX;
centerY = center.y ?? defaultCenterY;
if (dirAccessor === 'x') {
// Primary direction is horizontal, so stepPosition affects X coordinate
centerX = center.x ?? (sourceGapped.x + (targetGapped.x - sourceGapped.x) * stepPosition);
centerY = center.y ?? (sourceGapped.y + targetGapped.y) / 2;
} else {
// Primary direction is vertical, so stepPosition affects Y coordinate
centerX = center.x ?? (sourceGapped.x + targetGapped.x) / 2;
centerY = center.y ?? (sourceGapped.y + (targetGapped.y - sourceGapped.y) * stepPosition);
}
/*
* --->
* |
@@ -252,6 +268,7 @@ export function getSmoothStepPath({
centerX,
centerY,
offset = 20,
stepPosition = 0.5,
}: GetSmoothStepPathParams): [path: string, labelX: number, labelY: number, offsetX: number, offsetY: number] {
const [points, labelX, labelY, offsetX, offsetY] = getPoints({
source: { x: sourceX, y: sourceY },
@@ -260,6 +277,7 @@ export function getSmoothStepPath({
targetPosition,
center: { x: centerX, y: centerY },
offset,
stepPosition,
});
const path = points.reduce<string>((res, p, i) => {