Improve link drag & drop (#380)

- Resolves
https://github.com/Comfy-Org/litegraph.js/issues/309#issuecomment-2508726168
- Output issue still pending
- Splits connecting links `pointerup` handler to separate function,
which can now be called from `CanvasPointer` callbacks
  - Minor refactor; no functional changes

### Behaviour change

When moving existing links from an input slot, the link will not be
disconnected until the drop event occurs.

### Current

Shift + drag


https://github.com/user-attachments/assets/0b98f9bf-3d5f-467e-9a9b-e5695e5a0d0b

### Proposed

Shift + drag

https://github.com/user-attachments/assets/0bc36215-0247-41da-8050-e8df09addf23
This commit is contained in:
filtered
2025-03-04 01:26:56 +11:00
committed by GitHub
parent 37b9798602
commit cef6ab6ced

View File

@@ -2242,16 +2242,16 @@ export class LGraphCanvas implements ConnectionColorContext {
if (!link) continue
const slot = link.target_slot
const linked_node = graph._nodes_by_id[link.target_id]
const input = linked_node.inputs[slot]
const pos = linked_node.getConnectionPos(true, slot)
const otherNode = graph._nodes_by_id[link.target_id]
const input = otherNode.inputs[slot]
const pos = otherNode.getConnectionPos(true, slot)
this.connecting_links.push({
node: linked_node,
slot: slot,
input: input,
node: otherNode,
slot,
input,
output: null,
pos: pos,
pos,
direction: LinkDirection.RIGHT,
})
}
@@ -2320,14 +2320,21 @@ export class LGraphCanvas implements ConnectionColorContext {
slot,
output: linked_node.outputs[slot],
pos: linked_node.getConnectionPos(false, slot),
afterRerouteId: link_info.parentId,
}
this.connecting_links = [connecting]
pointer.onDragStart = () => {
if (this.allow_reconnect_links && !LiteGraph.click_do_break_link_to)
node.disconnectInput(i)
connecting.output = linked_node.outputs[slot]
}
pointer.onDragEnd = (upEvent) => {
if (this.allow_reconnect_links && !LiteGraph.click_do_break_link_to) {
node.disconnectInput(i)
}
this.#processConnectingLinks(upEvent)
connecting.output = linked_node.outputs[slot]
this.connecting_links = null
}
this.dirty_bgcanvas = true
}
@@ -2902,13 +2909,52 @@ export class LGraphCanvas implements ConnectionColorContext {
const x = e.canvasX
const y = e.canvasY
const node = graph.getNodeOnPos(x, y, this.visible_nodes)
if (this.connecting_links?.length) {
// node below mouse
const firstLink = this.connecting_links[0]
this.#processConnectingLinks(e)
} else {
this.dirty_canvas = true
// @ts-expect-error Unused param
this.node_over?.onMouseUp?.(e, [x - this.node_over.pos[0], y - this.node_over.pos[1]], this)
this.node_capturing_input?.onMouseUp?.(e, [
x - this.node_capturing_input.pos[0],
y - this.node_capturing_input.pos[1],
])
}
this.connecting_links = null
} else if (e.button === 1) {
// middle button
this.dirty_canvas = true
this.dragging_canvas = false
} else if (e.button === 2) {
// right button
this.dirty_canvas = true
}
pointer.isDown = false
pointer.isDouble = false
graph.change()
e.stopPropagation()
e.preventDefault()
return
}
#processConnectingLinks(e: CanvasPointerEvent) {
const { graph, connecting_links } = this
if (!graph) throw new NullGraphError()
if (!connecting_links) return
const { canvasX: x, canvasY: y } = e
const node = graph.getNodeOnPos(x, y, this.visible_nodes)
const firstLink = connecting_links[0]
if (node) {
for (const link of this.connecting_links) {
for (const link of connecting_links) {
// dragging a connection
this.#dirty()
@@ -2953,7 +2999,7 @@ export class LGraphCanvas implements ConnectionColorContext {
} else if (firstLink.input || firstLink.output) {
// For external event only.
const linkReleaseContextExtended: LinkReleaseContextExtended = {
links: this.connecting_links,
links: connecting_links,
}
this.emitEvent({
subType: "empty-release",
@@ -2988,35 +3034,6 @@ export class LGraphCanvas implements ConnectionColorContext {
}
}
}
} else {
this.dirty_canvas = true
// @ts-expect-error Unused param
this.node_over?.onMouseUp?.(e, [x - this.node_over.pos[0], y - this.node_over.pos[1]], this)
this.node_capturing_input?.onMouseUp?.(e, [
x - this.node_capturing_input.pos[0],
y - this.node_capturing_input.pos[1],
])
}
this.connecting_links = null
} else if (e.button === 1) {
// middle button
this.dirty_canvas = true
this.dragging_canvas = false
} else if (e.button === 2) {
// right button
this.dirty_canvas = true
}
pointer.isDown = false
pointer.isDouble = false
graph.change()
e.stopPropagation()
e.preventDefault()
return
}
/**