mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 11:11:53 +00:00
[Bug] Fix layout issue caused by absolute positioned slots (#908)
Before:  After:  Workflow: [dynamically_added_input.json](https://github.com/user-attachments/files/19640371/dynamically_added_input.json) This PR also fixes the issue that output slot's `pos` property is not relative to node pos.
This commit is contained in:
@@ -2871,16 +2871,37 @@ export class LGraphNode implements Positionable, IPinnable, IColorable {
|
|||||||
|
|
||||||
// default vertical slots
|
// default vertical slots
|
||||||
const offset = LiteGraph.NODE_SLOT_HEIGHT * 0.5
|
const offset = LiteGraph.NODE_SLOT_HEIGHT * 0.5
|
||||||
|
const slotIndex = is_input
|
||||||
|
? this.#defaultVerticalInputs.indexOf(this.inputs[slot_number])
|
||||||
|
: this.#defaultVerticalOutputs.indexOf(this.outputs[slot_number])
|
||||||
|
|
||||||
out[0] = is_input
|
out[0] = is_input
|
||||||
? nodeX + offset
|
? nodeX + offset
|
||||||
: nodeX + this.size[0] + 1 - offset
|
: nodeX + this.size[0] + 1 - offset
|
||||||
out[1] =
|
out[1] =
|
||||||
nodeY +
|
nodeY +
|
||||||
(slot_number + 0.7) * LiteGraph.NODE_SLOT_HEIGHT +
|
(slotIndex + 0.7) * LiteGraph.NODE_SLOT_HEIGHT +
|
||||||
(this.constructor.slot_start_y || 0)
|
(this.constructor.slot_start_y || 0)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal The inputs that are not positioned with absolute coordinates.
|
||||||
|
*/
|
||||||
|
get #defaultVerticalInputs() {
|
||||||
|
return this.inputs.filter((slot: INodeInputSlot) => !(
|
||||||
|
slot.pos ||
|
||||||
|
(this.widgets?.length && isWidgetInputSlot(slot))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal The outputs that are not positioned with absolute coordinates.
|
||||||
|
*/
|
||||||
|
get #defaultVerticalOutputs() {
|
||||||
|
return this.outputs.filter((slot: INodeOutputSlot) => !slot.pos)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the position of an input slot, in graph co-ordinates.
|
* Gets the position of an input slot, in graph co-ordinates.
|
||||||
*
|
*
|
||||||
@@ -2902,7 +2923,8 @@ export class LGraphNode implements Positionable, IPinnable, IColorable {
|
|||||||
// default vertical slots
|
// default vertical slots
|
||||||
const offsetX = LiteGraph.NODE_SLOT_HEIGHT * 0.5
|
const offsetX = LiteGraph.NODE_SLOT_HEIGHT * 0.5
|
||||||
const nodeOffsetY = this.constructor.slot_start_y || 0
|
const nodeOffsetY = this.constructor.slot_start_y || 0
|
||||||
const slotY = (slot + 0.7) * LiteGraph.NODE_SLOT_HEIGHT
|
const slotIndex = this.#defaultVerticalInputs.indexOf(this.inputs[slot])
|
||||||
|
const slotY = (slotIndex + 0.7) * LiteGraph.NODE_SLOT_HEIGHT
|
||||||
|
|
||||||
return [nodeX + offsetX, nodeY + slotY + nodeOffsetY]
|
return [nodeX + offsetX, nodeY + slotY + nodeOffsetY]
|
||||||
}
|
}
|
||||||
@@ -2924,12 +2946,13 @@ export class LGraphNode implements Positionable, IPinnable, IColorable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const outputPos = outputs?.[slot]?.pos
|
const outputPos = outputs?.[slot]?.pos
|
||||||
if (outputPos) return outputPos
|
if (outputPos) return [nodeX + outputPos[0], nodeY + outputPos[1]]
|
||||||
|
|
||||||
// default vertical slots
|
// default vertical slots
|
||||||
const offsetX = LiteGraph.NODE_SLOT_HEIGHT * 0.5
|
const offsetX = LiteGraph.NODE_SLOT_HEIGHT * 0.5
|
||||||
const nodeOffsetY = this.constructor.slot_start_y || 0
|
const nodeOffsetY = this.constructor.slot_start_y || 0
|
||||||
const slotY = (slot + 0.7) * LiteGraph.NODE_SLOT_HEIGHT
|
const slotIndex = this.#defaultVerticalOutputs.indexOf(this.outputs[slot])
|
||||||
|
const slotY = (slotIndex + 0.7) * LiteGraph.NODE_SLOT_HEIGHT
|
||||||
|
|
||||||
// TODO: Why +1?
|
// TODO: Why +1?
|
||||||
return [nodeX + width + 1 - offsetX, nodeY + slotY + nodeOffsetY]
|
return [nodeX + width + 1 - offsetX, nodeY + slotY + nodeOffsetY]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect } from "vitest"
|
import { describe, expect } from "vitest"
|
||||||
|
|
||||||
import { LGraphNode } from "@/litegraph"
|
import { LGraphNode, LiteGraph } from "@/litegraph"
|
||||||
import { LGraph } from "@/litegraph"
|
import { LGraph } from "@/litegraph"
|
||||||
import { NodeInputSlot, NodeOutputSlot } from "@/NodeSlot"
|
import { NodeInputSlot, NodeOutputSlot } from "@/NodeSlot"
|
||||||
|
|
||||||
@@ -314,4 +314,89 @@ describe("LGraphNode", () => {
|
|||||||
expect(slot?.name).toBe("Input1")
|
expect(slot?.name).toBe("Input1")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("LGraphNode slot positioning", () => {
|
||||||
|
test("should correctly position slots with absolute coordinates", () => {
|
||||||
|
// Setup
|
||||||
|
const node = new LGraphNode("test")
|
||||||
|
node.pos = [100, 100]
|
||||||
|
|
||||||
|
// Add input/output with absolute positions
|
||||||
|
node.addInput("abs-input", "number")
|
||||||
|
node.inputs[0].pos = [10, 20]
|
||||||
|
|
||||||
|
node.addOutput("abs-output", "number")
|
||||||
|
node.outputs[0].pos = [50, 30]
|
||||||
|
|
||||||
|
// Test
|
||||||
|
const inputPos = node.getInputPos(0)
|
||||||
|
const outputPos = node.getOutputPos(0)
|
||||||
|
|
||||||
|
// Absolute positions should be relative to node position
|
||||||
|
expect(inputPos).toEqual([110, 120]) // node.pos + slot.pos
|
||||||
|
expect(outputPos).toEqual([150, 130]) // node.pos + slot.pos
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should correctly position default vertical slots", () => {
|
||||||
|
// Setup
|
||||||
|
const node = new LGraphNode("test")
|
||||||
|
node.pos = [100, 100]
|
||||||
|
|
||||||
|
// Add multiple inputs/outputs without absolute positions
|
||||||
|
node.addInput("input1", "number")
|
||||||
|
node.addInput("input2", "number")
|
||||||
|
node.addOutput("output1", "number")
|
||||||
|
node.addOutput("output2", "number")
|
||||||
|
|
||||||
|
// Calculate expected positions
|
||||||
|
const slotOffset = LiteGraph.NODE_SLOT_HEIGHT * 0.5
|
||||||
|
const slotSpacing = LiteGraph.NODE_SLOT_HEIGHT
|
||||||
|
const nodeWidth = node.size[0]
|
||||||
|
|
||||||
|
// Test input positions
|
||||||
|
expect(node.getInputPos(0)).toEqual([
|
||||||
|
100 + slotOffset,
|
||||||
|
100 + (0 + 0.7) * slotSpacing,
|
||||||
|
])
|
||||||
|
expect(node.getInputPos(1)).toEqual([
|
||||||
|
100 + slotOffset,
|
||||||
|
100 + (1 + 0.7) * slotSpacing,
|
||||||
|
])
|
||||||
|
|
||||||
|
// Test output positions
|
||||||
|
expect(node.getOutputPos(0)).toEqual([
|
||||||
|
100 + nodeWidth + 1 - slotOffset,
|
||||||
|
100 + (0 + 0.7) * slotSpacing,
|
||||||
|
])
|
||||||
|
expect(node.getOutputPos(1)).toEqual([
|
||||||
|
100 + nodeWidth + 1 - slotOffset,
|
||||||
|
100 + (1 + 0.7) * slotSpacing,
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should skip absolute positioned slots when calculating vertical positions", () => {
|
||||||
|
// Setup
|
||||||
|
const node = new LGraphNode("test")
|
||||||
|
node.pos = [100, 100]
|
||||||
|
|
||||||
|
// Add mix of absolute and default positioned slots
|
||||||
|
node.addInput("abs-input", "number")
|
||||||
|
node.inputs[0].pos = [10, 20]
|
||||||
|
node.addInput("default-input1", "number")
|
||||||
|
node.addInput("default-input2", "number")
|
||||||
|
|
||||||
|
const slotOffset = LiteGraph.NODE_SLOT_HEIGHT * 0.5
|
||||||
|
const slotSpacing = LiteGraph.NODE_SLOT_HEIGHT
|
||||||
|
|
||||||
|
// Test: default positioned slots should be consecutive, ignoring absolute positioned ones
|
||||||
|
expect(node.getInputPos(1)).toEqual([
|
||||||
|
100 + slotOffset,
|
||||||
|
100 + (0 + 0.7) * slotSpacing, // First default slot starts at index 0
|
||||||
|
])
|
||||||
|
expect(node.getInputPos(2)).toEqual([
|
||||||
|
100 + slotOffset,
|
||||||
|
100 + (1 + 0.7) * slotSpacing, // Second default slot at index 1
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user