feat(smoothstep-edge): add bendPosition to getSmoothStepPath

This commit is contained in:
Kenny Williams
2025-07-02 20:12:00 -07:00
parent 549ec62d6d
commit eaea14c617
5 changed files with 104 additions and 5 deletions
@@ -69,6 +69,55 @@ const nodes: Node[] = [
targetPosition: Position.Bottom, targetPosition: Position.Bottom,
style: { background: 'rgba(255,255,255,0.5)' }, style: { background: 'rgba(255,255,255,0.5)' },
}, },
// Bend Position Examples
{
id: '9',
position: { x: 300, y: 0 },
data: { label: 'Source' },
sourcePosition: Position.Right,
targetPosition: Position.Right,
style: { background: 'rgba(255,255,255,0.5)' },
},
{
id: '10',
position: { x: 600, y: 150 },
data: { label: 'Target' },
sourcePosition: Position.Left,
targetPosition: Position.Left,
style: { background: 'rgba(255,255,255,0.5)' },
},
{
id: '11',
position: { x: 300, y: 300 },
data: { label: 'Source' },
sourcePosition: Position.Right,
targetPosition: Position.Right,
style: { background: 'rgba(255,255,255,0.5)' },
},
{
id: '12',
position: { x: 600, y: 450 },
data: { label: 'Target' },
sourcePosition: Position.Left,
targetPosition: Position.Left,
style: { background: 'rgba(255,255,255,0.5)' },
},
{
id: '13',
position: { x: 300, y: 600 },
data: { label: 'Source' },
sourcePosition: Position.Right,
targetPosition: Position.Right,
style: { background: 'rgba(255,255,255,0.5)' },
},
{
id: '14',
position: { x: 600, y: 750 },
data: { label: 'Target' },
sourcePosition: Position.Left,
targetPosition: Position.Left,
style: { background: 'rgba(255,255,255,0.5)' },
},
]; ];
const edges: Edge[] = [ const edges: Edge[] = [
@@ -102,6 +151,38 @@ const edges: Edge[] = [
source: '7', source: '7',
target: '8', target: '8',
}, },
// Bend Position Examples
{
id: 'e9-10',
source: '9',
target: '10',
label: 'bendPosition: 0.2',
pathOptions: {
bendPosition: 0.2,
},
interactionWidth: 0,
},
{
id: 'e11-12',
source: '11',
target: '12',
label: 'bendPosition: 0.5 (default)',
pathOptions: {
bendPosition: 0.5,
},
interactionWidth: 0,
},
{
id: 'e13-14',
source: '13',
target: '14',
label: 'bendPosition: 0.8',
pathOptions: {
bendPosition: 0.8,
},
interactionWidth: 0,
},
]; ];
const defaultEdgeOptions = { const defaultEdgeOptions = {
@@ -36,6 +36,7 @@ function createSmoothStepEdge(params: { isInternal: boolean }) {
targetPosition, targetPosition,
borderRadius: pathOptions?.borderRadius, borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset, offset: pathOptions?.offset,
bendPosition: pathOptions?.bendPosition,
}); });
const _id = params.isInternal ? undefined : id; const _id = params.isInternal ? undefined : id;
@@ -30,7 +30,8 @@
sourcePosition, sourcePosition,
targetPosition, targetPosition,
borderRadius: pathOptions?.borderRadius, borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset offset: pathOptions?.offset,
bendPosition: pathOptions?.bendPosition,
}) })
); );
</script> </script>
+1
View File
@@ -45,6 +45,7 @@ export type EdgeBase<
export type SmoothStepPathOptions = { export type SmoothStepPathOptions = {
offset?: number; offset?: number;
borderRadius?: number; borderRadius?: number;
bendPosition?: number;
}; };
export type StepPathOptions = { export type StepPathOptions = {
@@ -26,6 +26,12 @@ export interface GetSmoothStepPathParams {
centerY?: number; centerY?: number;
/** @default 20 */ /** @default 20 */
offset?: number; offset?: number;
/**
* Controls where the bend occurs along the path.
* 0 = at source, 1 = at target, 0.5 = midpoint
* @default 0.5
*/
bendPosition?: number;
} }
const handleDirections = { const handleDirections = {
@@ -63,6 +69,7 @@ function getPoints({
targetPosition = Position.Top, targetPosition = Position.Top,
center, center,
offset, offset,
bendPosition,
}: { }: {
source: XYPosition; source: XYPosition;
sourcePosition: Position; sourcePosition: Position;
@@ -70,6 +77,7 @@ function getPoints({
targetPosition: Position; targetPosition: Position;
center: Partial<XYPosition>; center: Partial<XYPosition>;
offset: number; offset: number;
bendPosition: number;
}): [XYPosition[], number, number, number, number] { }): [XYPosition[], number, number, number, number] {
const sourceDir = handleDirections[sourcePosition]; const sourceDir = handleDirections[sourcePosition];
const targetDir = handleDirections[targetPosition]; const targetDir = handleDirections[targetPosition];
@@ -88,17 +96,22 @@ function getPoints({
const sourceGapOffset = { x: 0, y: 0 }; const sourceGapOffset = { x: 0, y: 0 };
const targetGapOffset = { x: 0, y: 0 }; const targetGapOffset = { x: 0, y: 0 };
const [defaultCenterX, defaultCenterY, defaultOffsetX, defaultOffsetY] = getEdgeCenter({ const [, , defaultOffsetX, defaultOffsetY] = getEdgeCenter({
sourceX: source.x, sourceX: source.x,
sourceY: source.y, sourceY: source.y,
targetX: target.x, targetX: target.x,
targetY: target.y, targetY: target.y,
}); });
// Calculate bend position based on the bendPosition parameter
const bendX = sourceGapped.x + (targetGapped.x - sourceGapped.x) * bendPosition;
const bendY = sourceGapped.y + (targetGapped.y - sourceGapped.y) * bendPosition;
// opposite handle positions, default case // opposite handle positions, default case
if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) { if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) {
centerX = center.x ?? defaultCenterX; centerX = center.x ?? bendX;
centerY = center.y ?? defaultCenterY; centerY = center.y ?? bendY;
/* /*
* ---> * --->
* | * |
@@ -252,7 +265,8 @@ export function getSmoothStepPath({
centerX, centerX,
centerY, centerY,
offset = 20, offset = 20,
}: GetSmoothStepPathParams): [path: string, labelX: number, labelY: number, offsetX: number, offsetY: number] { bendPosition = 0.5,
}: GetSmoothStepPathParams): [path: string, labelX: number, labelY: number, offsetX: number, offsetY: number] {
const [points, labelX, labelY, offsetX, offsetY] = getPoints({ const [points, labelX, labelY, offsetX, offsetY] = getPoints({
source: { x: sourceX, y: sourceY }, source: { x: sourceX, y: sourceY },
sourcePosition, sourcePosition,
@@ -260,6 +274,7 @@ export function getSmoothStepPath({
targetPosition, targetPosition,
center: { x: centerX, y: centerY }, center: { x: centerX, y: centerY },
offset, offset,
bendPosition,
}); });
const path = points.reduce<string>((res, p, i) => { const path = points.reduce<string>((res, p, i) => {