refactor(core): pick target handle if handles are on top of each other

Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
braks
2023-05-11 15:33:42 +02:00
committed by Braks
parent f5e0cef116
commit fb1181f209
2 changed files with 29 additions and 13 deletions
+9 -9
View File
@@ -65,7 +65,7 @@ export default function useHandle({
isValidConnectionHandler = (!isTarget ? node.isValidTargetPos : node.isValidSourcePos) || alwaysValid isValidConnectionHandler = (!isTarget ? node.isValidTargetPos : node.isValidSourcePos) || alwaysValid
} }
let prevClosestHandle: ConnectionHandle | null let closestHandle: ConnectionHandle | null
let autoPanId = 0 let autoPanId = 0
@@ -119,7 +119,7 @@ export default function useHandle({
function onPointerMove(event: MouseTouchEvent) { function onPointerMove(event: MouseTouchEvent) {
connectionPosition = getEventPosition(event, containerBounds) connectionPosition = getEventPosition(event, containerBounds)
prevClosestHandle = getClosestHandle( closestHandle = getClosestHandle(
pointToRendererPoint(connectionPosition, viewport.value, false, [1, 1]), pointToRendererPoint(connectionPosition, viewport.value, false, [1, 1]),
connectionRadius.value, connectionRadius.value,
handleLookup, handleLookup,
@@ -132,7 +132,7 @@ export default function useHandle({
const result = isValidHandle( const result = isValidHandle(
event, event,
prevClosestHandle, closestHandle,
connectionMode.value, connectionMode.value,
resolveUnref(nodeId), resolveUnref(nodeId),
resolveUnref(handleId), resolveUnref(handleId),
@@ -148,20 +148,20 @@ export default function useHandle({
handleDomNode = result.handleDomNode handleDomNode = result.handleDomNode
updateConnection( updateConnection(
prevClosestHandle && isValid closestHandle && isValid
? rendererPointToPoint( ? rendererPointToPoint(
{ {
x: prevClosestHandle.x, x: closestHandle.x,
y: prevClosestHandle.y, y: closestHandle.y,
}, },
viewport.value, viewport.value,
) )
: connectionPosition, : connectionPosition,
result.endHandle, result.endHandle,
getConnectionStatus(!!prevClosestHandle, isValid), getConnectionStatus(!!closestHandle, isValid),
) )
if (!prevClosestHandle && !isValid && !handleDomNode) { if (!closestHandle && !isValid && !handleDomNode) {
return resetRecentHandle(prevActiveHandle) return resetRecentHandle(prevActiveHandle)
} }
@@ -179,7 +179,7 @@ export default function useHandle({
} }
function onPointerUp(event: MouseTouchEvent) { function onPointerUp(event: MouseTouchEvent) {
if ((prevClosestHandle || handleDomNode) && connection && isValid) { if ((closestHandle || handleDomNode) && connection && isValid) {
if (!onEdgeUpdate) { if (!onEdgeUpdate) {
emits.connect(connection) emits.connect(connection)
} else { } else {
+20 -4
View File
@@ -57,18 +57,31 @@ export function getClosestHandle(
connectionRadius: number, connectionRadius: number,
handles: ConnectionHandle[], handles: ConnectionHandle[],
): ConnectionHandle | null { ): ConnectionHandle | null {
let closestHandle: ConnectionHandle | null = null let closestHandles: ConnectionHandle[] = []
let minDistance = Infinity let minDistance = Infinity
handles.forEach((handle) => { handles.forEach((handle) => {
const distance = Math.sqrt((handle.x - pos.x) ** 2 + (handle.y - pos.y) ** 2) const distance = Math.sqrt((handle.x - pos.x) ** 2 + (handle.y - pos.y) ** 2)
if (distance <= connectionRadius && distance < minDistance) { 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 minDistance = distance
closestHandle = handle
} }
}) })
return closestHandle if (!closestHandles.length) {
return null
}
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 } // checks if and returns connection in fom of an object { source: 123, target: 312 }
@@ -89,6 +102,9 @@ export function isValidHandle(
const handleDomNode = doc.querySelector(`.vue-flow__handle[data-id="${handle?.nodeId}-${handle?.id}-${handle?.type}"]`) const handleDomNode = doc.querySelector(`.vue-flow__handle[data-id="${handle?.nodeId}-${handle?.id}-${handle?.type}"]`)
const { x, y } = getEventPosition(event) const { x, y } = getEventPosition(event)
const handleBelow = doc.elementFromPoint(x, y) const handleBelow = doc.elementFromPoint(x, y)
// we always want to prioritize the handle below the mouse cursor over the closest distance handle,
// 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 handleToCheck = handleBelow?.classList.contains('vue-flow__handle') ? handleBelow : handleDomNode
const result: ValidHandleResult = { const result: ValidHandleResult = {