fix(core): filter closest handles by validity
This commit is contained in:
@@ -21,6 +21,15 @@ export interface ConnectionHandle {
|
||||
y: number
|
||||
}
|
||||
|
||||
function defaultValidHandleResult(): ValidHandleResult {
|
||||
return {
|
||||
handleDomNode: null,
|
||||
isValid: false,
|
||||
connection: { source: '', target: '', sourceHandle: null, targetHandle: null },
|
||||
endHandle: null,
|
||||
}
|
||||
}
|
||||
|
||||
export function resetRecentHandle(handleDomNode: Element): void {
|
||||
handleDomNode?.classList.remove('valid', 'connecting', 'vue-flow__handle-valid', 'vue-flow__handle-connecting')
|
||||
}
|
||||
@@ -53,29 +62,45 @@ export function getHandles(
|
||||
}, [])
|
||||
}
|
||||
|
||||
export function getClosestHandle(pos: XYPosition, connectionRadius: number, handles: ConnectionHandle[]) {
|
||||
let closestHandles: ConnectionHandle[] = []
|
||||
export function getClosestHandle(
|
||||
pos: XYPosition,
|
||||
connectionRadius: number,
|
||||
handles: ConnectionHandle[],
|
||||
validator: (handle: ConnectionHandle) => ValidHandleResult,
|
||||
) {
|
||||
let closestHandles: { handle: ConnectionHandle; validHandleResult: ValidHandleResult }[] = []
|
||||
let minDistance = Infinity
|
||||
|
||||
handles.forEach((handle) => {
|
||||
const distance = Math.sqrt((handle.x - pos.x) ** 2 + (handle.y - pos.y) ** 2)
|
||||
if (distance <= connectionRadius) {
|
||||
if (distance < minDistance) {
|
||||
closestHandles = [handle]
|
||||
} else if (distance === minDistance) {
|
||||
// when multiple handles are on the same distance we collect all of them
|
||||
closestHandles.push(handle)
|
||||
}
|
||||
|
||||
minDistance = distance
|
||||
if (distance <= connectionRadius) {
|
||||
const validHandleResult = validator(handle)
|
||||
|
||||
if (distance <= minDistance && validHandleResult.isValid) {
|
||||
if (distance < minDistance) {
|
||||
closestHandles = [{ handle, validHandleResult }]
|
||||
} else if (distance === minDistance) {
|
||||
// when multiple handles are on the same distance we collect all of them
|
||||
closestHandles.push({
|
||||
handle,
|
||||
validHandleResult,
|
||||
})
|
||||
}
|
||||
|
||||
minDistance = distance
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!closestHandles.length) {
|
||||
return null
|
||||
return { handle: null, validHandleResult: defaultValidHandleResult() }
|
||||
}
|
||||
|
||||
return closestHandles
|
||||
return closestHandles.length === 1
|
||||
? closestHandles[0]
|
||||
: // 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
|
||||
closestHandles.find(({ handle }) => handle.type === 'target') || closestHandles[0]
|
||||
}
|
||||
|
||||
// checks if and returns connection in fom of an object { source: 123, target: 312 }
|
||||
@@ -101,12 +126,7 @@ export function isValidHandle(
|
||||
// because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor
|
||||
const handleToCheck = handleBelow?.classList.contains('vue-flow__handle') ? handleBelow : handleDomNode
|
||||
|
||||
const result: ValidHandleResult = {
|
||||
handleDomNode: handleToCheck,
|
||||
isValid: false,
|
||||
connection: { source: '', target: '', sourceHandle: null, targetHandle: null },
|
||||
endHandle: null,
|
||||
}
|
||||
const result = defaultValidHandleResult()
|
||||
|
||||
if (handleToCheck) {
|
||||
const handleType = getHandleType(undefined, handleToCheck)
|
||||
|
||||
Reference in New Issue
Block a user