1- import { Node , Position , MarkerType , XYPosition } from "reactflow" ;
1+ import { Position , internalsSymbol } from "reactflow" ;
22
33export function ResizeIcon ( ) {
44 return (
@@ -23,73 +23,78 @@ export function ResizeIcon() {
2323 ) ;
2424}
2525
26- // this helper function returns the intersection point
27- // of the line between the center of the intersectionNode and the target node
28- function getNodeIntersection ( intersectionNode : Node , targetNode : Node ) {
29- // https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a
30- const {
31- width : intersectionNodeWidth ,
32- height : intersectionNodeHeight ,
33- positionAbsolute : intersectionNodePosition ,
34- } = intersectionNode ;
35- const targetPosition = targetNode . positionAbsolute ! ;
26+ // returns the position (top,right,bottom or right) passed node compared to
27+ function getParams ( nodeA , nodeB ) {
28+ const centerA = getNodeCenter ( nodeA ) ;
29+ const centerB = getNodeCenter ( nodeB ) ;
3630
37- const w = intersectionNodeWidth ! / 2 ;
38- const h = intersectionNodeHeight ! / 2 ;
31+ const horizontalDiff = Math . abs ( centerA . x - centerB . x ) ;
32+ const verticalDiff = Math . abs ( centerA . y - centerB . y ) ;
3933
40- const x2 = intersectionNodePosition ! . x + w ;
41- const y2 = intersectionNodePosition ! . y + h ;
42- const x1 = targetPosition . x + w ;
43- const y1 = targetPosition . y + h ;
34+ let position ;
4435
45- const xx1 = ( x1 - x2 ) / ( 2 * w ) - ( y1 - y2 ) / ( 2 * h ) ;
46- const yy1 = ( x1 - x2 ) / ( 2 * w ) + ( y1 - y2 ) / ( 2 * h ) ;
47- const a = 1 / ( Math . abs ( xx1 ) + Math . abs ( yy1 ) ) ;
48- const xx3 = a * xx1 ;
49- const yy3 = a * yy1 ;
50- const x = w * ( xx3 + yy3 ) + x2 ;
51- const y = h * ( - xx3 + yy3 ) + y2 ;
36+ // when the horizontal difference between the nodes is bigger, we use Position.Left or Position.Right for the handle
37+ if ( horizontalDiff > verticalDiff ) {
38+ position = centerA . x > centerB . x ? Position . Left : Position . Right ;
39+ } else {
40+ // here the vertical difference between the nodes is bigger, so we use Position.Top or Position.Bottom for the handle
41+ position = centerA . y > centerB . y ? Position . Top : Position . Bottom ;
42+ }
5243
53- return { x, y } ;
44+ const [ x , y ] = getHandleCoordsByPosition ( nodeA , position ) ;
45+ return [ x , y , position ] ;
5446}
5547
56- // returns the position (top,right,bottom or right) passed node compared to the intersection point
57- function getEdgePosition ( node : Node , intersectionPoint : XYPosition ) {
58- const n = { ...node . positionAbsolute , ...node } ;
59- const nx = Math . round ( n . x ! ) ;
60- const ny = Math . round ( n . y ! ) ;
61- const px = Math . round ( intersectionPoint . x ) ;
62- const py = Math . round ( intersectionPoint . y ) ;
48+ function getHandleCoordsByPosition ( node , handlePosition ) {
49+ // all handles are from type source, that's why we use handleBounds.source here
50+ const handle = node [ internalsSymbol ] . handleBounds . source . find (
51+ ( h ) => h . position === handlePosition
52+ ) ;
6353
64- if ( px <= nx + 1 ) {
65- return Position . Left ;
66- }
67- if ( px >= nx + n . width ! - 1 ) {
68- return Position . Right ;
69- }
70- if ( py <= ny + 1 ) {
71- return Position . Top ;
72- }
73- if ( py >= n . y ! + n . height ! - 1 ) {
74- return Position . Bottom ;
54+ let offsetX = handle . width / 2 ;
55+ let offsetY = handle . height / 2 ;
56+
57+ // this is a tiny detail to make the markerEnd of an edge visible.
58+ // The handle position that gets calculated has the origin top-left, so depending which side we are using, we add a little offset
59+ // when the handlePosition is Position.Right for example, we need to add an offset as big as the handle itself in order to get the correct position
60+ switch ( handlePosition ) {
61+ case Position . Left :
62+ offsetX = 0 ;
63+ break ;
64+ case Position . Right :
65+ offsetX = handle . width ;
66+ break ;
67+ case Position . Top :
68+ offsetY = 0 ;
69+ break ;
70+ case Position . Bottom :
71+ offsetY = handle . height ;
72+ break ;
7573 }
7674
77- return Position . Top ;
75+ const x = node . positionAbsolute . x + handle . x + offsetX ;
76+ const y = node . positionAbsolute . y + handle . y + offsetY ;
77+
78+ return [ x , y ] ;
7879}
7980
80- // returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge
81- export function getEdgeParams ( source : Node , target : Node ) {
82- const sourceIntersectionPoint = getNodeIntersection ( source , target ) ;
83- const targetIntersectionPoint = getNodeIntersection ( target , source ) ;
81+ function getNodeCenter ( node ) {
82+ return {
83+ x : node . positionAbsolute . x + node . width / 2 ,
84+ y : node . positionAbsolute . y + node . height / 2 ,
85+ } ;
86+ }
8487
85- const sourcePos = getEdgePosition ( source , sourceIntersectionPoint ) ;
86- const targetPos = getEdgePosition ( target , targetIntersectionPoint ) ;
88+ // returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge
89+ export function getEdgeParams ( source , target ) {
90+ const [ sx , sy , sourcePos ] = getParams ( source , target ) ;
91+ const [ tx , ty , targetPos ] = getParams ( target , source ) ;
8792
8893 return {
89- sx : sourceIntersectionPoint . x ,
90- sy : sourceIntersectionPoint . y ,
91- tx : targetIntersectionPoint . x ,
92- ty : targetIntersectionPoint . y ,
94+ sx,
95+ sy,
96+ tx,
97+ ty,
9398 sourcePos,
9499 targetPos,
95100 } ;
0 commit comments