Easy Connect
Fed up with tiny little connection handles? Make your whole node act as one! Keep in mind though that you need to define separate drag handles in this case to still be able to drag the node.
import { Position, MarkerType, type XYPosition, type InternalNode } from '@xyflow/svelte';
// this helper function returns the intersection point
// of the line between the center of the intersectionNode and the target node
function getNodeIntersection(intersectionNode: InternalNode, targetNode: InternalNode) {
// https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a
const intersectionNodePosition = intersectionNode.internals.positionAbsolute || {
x: 0,
y: 0,
};
const targetPosition = targetNode.internals.positionAbsolute || {
x: 0,
y: 0,
};
const w = (intersectionNode.measured.width ?? 0) / 2;
const h = (intersectionNode.measured.height ?? 0) / 2;
const x2 = intersectionNodePosition.x + w;
const y2 = intersectionNodePosition.y + h;
const x1 = targetPosition.x + (targetNode.measured.width ?? 0) / 2;
const y1 = targetPosition.y + (targetNode.measured.height ?? 0) / 2;
const xx1 = (x1 - x2) / (2 * w) - (y1 - y2) / (2 * h);
const yy1 = (x1 - x2) / (2 * w) + (y1 - y2) / (2 * h);
const a = 1 / (Math.abs(xx1) + Math.abs(yy1));
const xx3 = a * xx1;
const yy3 = a * yy1;
const x = w * (xx3 + yy3) + x2;
const y = h * (-xx3 + yy3) + y2;
return { x, y };
}
// returns the position (top,right,bottom or right) passed node compared to the intersection point
function getEdgePosition(node: InternalNode, intersectionPoint: XYPosition) {
if (!node.measured.width || !node.measured.height) {
return null;
}
const nx = Math.round(node.internals.positionAbsolute?.x ?? 0);
const ny = Math.round(node.internals.positionAbsolute?.y ?? 0);
const px = Math.round(intersectionPoint.x);
const py = Math.round(intersectionPoint.y);
if (px <= nx + 1) {
return Position.Left;
}
if (px >= nx + node.measured.width - 1) {
return Position.Right;
}
if (py <= ny + 1) {
return Position.Top;
}
if (py >= ny + node.measured.height - 1) {
return Position.Bottom;
}
return Position.Top;
}
// returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge
export function getEdgeParams(source: InternalNode, target: InternalNode) {
const sourceIntersectionPoint = getNodeIntersection(source, target);
const targetIntersectionPoint = getNodeIntersection(target, source);
const sourcePos = getEdgePosition(source, sourceIntersectionPoint);
const targetPos = getEdgePosition(target, targetIntersectionPoint);
return {
sx: sourceIntersectionPoint.x,
sy: sourceIntersectionPoint.y,
tx: targetIntersectionPoint.x,
ty: targetIntersectionPoint.y,
sourcePos,
targetPos,
};
}Last updated on