@@ -21,6 +21,15 @@ export interface ConnectionHandle {
21
21
y : number
22
22
}
23
23
24
+ function defaultValidHandleResult ( ) : ValidHandleResult {
25
+ return {
26
+ handleDomNode : null ,
27
+ isValid : false ,
28
+ connection : { source : '' , target : '' , sourceHandle : null , targetHandle : null } ,
29
+ endHandle : null ,
30
+ }
31
+ }
32
+
24
33
export function resetRecentHandle ( handleDomNode : Element ) : void {
25
34
handleDomNode ?. classList . remove ( 'valid' , 'connecting' , 'vue-flow__handle-valid' , 'vue-flow__handle-connecting' )
26
35
}
@@ -53,29 +62,45 @@ export function getHandles(
53
62
} , [ ] )
54
63
}
55
64
56
- export function getClosestHandle ( pos : XYPosition , connectionRadius : number , handles : ConnectionHandle [ ] ) {
57
- let closestHandles : ConnectionHandle [ ] = [ ]
65
+ export function getClosestHandle (
66
+ pos : XYPosition ,
67
+ connectionRadius : number ,
68
+ handles : ConnectionHandle [ ] ,
69
+ validator : ( handle : ConnectionHandle ) => ValidHandleResult ,
70
+ ) {
71
+ let closestHandles : { handle : ConnectionHandle ; validHandleResult : ValidHandleResult } [ ] = [ ]
58
72
let minDistance = Infinity
59
73
60
74
handles . forEach ( ( handle ) => {
61
75
const distance = Math . sqrt ( ( handle . x - pos . x ) ** 2 + ( handle . y - pos . y ) ** 2 )
76
+
62
77
if ( distance <= connectionRadius ) {
63
- if ( distance < minDistance ) {
64
- closestHandles = [ handle ]
65
- } else if ( distance === minDistance ) {
66
- // when multiple handles are on the same distance we collect all of them
67
- closestHandles . push ( handle )
78
+ const validHandleResult = validator ( handle )
79
+
80
+ if ( distance <= minDistance && validHandleResult . isValid ) {
81
+ if ( distance < minDistance ) {
82
+ closestHandles = [ { handle, validHandleResult } ]
83
+ } else if ( distance === minDistance ) {
84
+ // when multiple handles are on the same distance we collect all of them
85
+ closestHandles . push ( {
86
+ handle,
87
+ validHandleResult,
88
+ } )
89
+ }
90
+
91
+ minDistance = distance
68
92
}
69
-
70
- minDistance = distance
71
93
}
72
94
} )
73
95
74
96
if ( ! closestHandles . length ) {
75
- return null
97
+ return { handle : null , validHandleResult : defaultValidHandleResult ( ) }
76
98
}
77
99
78
- return closestHandles
100
+ return closestHandles . length === 1
101
+ ? closestHandles [ 0 ]
102
+ : // if multiple handles are layout on top of each other we take the one with type = target because it's more likely that the user wants to connect to this one
103
+ closestHandles . find ( ( { handle } ) => handle . type === 'target' ) || closestHandles [ 0 ]
79
104
}
80
105
81
106
// checks if and returns connection in fom of an object { source: 123, target: 312 }
@@ -101,12 +126,7 @@ export function isValidHandle(
101
126
// because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor
102
127
const handleToCheck = handleBelow ?. classList . contains ( 'vue-flow__handle' ) ? handleBelow : handleDomNode
103
128
104
- const result : ValidHandleResult = {
105
- handleDomNode : handleToCheck ,
106
- isValid : false ,
107
- connection : { source : '' , target : '' , sourceHandle : null , targetHandle : null } ,
108
- endHandle : null ,
109
- }
129
+ const result = defaultValidHandleResult ( )
110
130
111
131
if ( handleToCheck ) {
112
132
const handleType = getHandleType ( undefined , handleToCheck )
0 commit comments