mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 19:21:54 +00:00
Fix slot layout validity on rendering system change
This commit is contained in:
@@ -183,6 +183,7 @@ let cleanupNodeManager: (() => void) | null = null
|
|||||||
|
|
||||||
// Slot layout sync management
|
// Slot layout sync management
|
||||||
let slotSync: ReturnType<typeof useSlotLayoutSync> | null = null
|
let slotSync: ReturnType<typeof useSlotLayoutSync> | null = null
|
||||||
|
let slotSyncStarted = false
|
||||||
let linkSync: ReturnType<typeof useLinkLayoutSync> | null = null
|
let linkSync: ReturnType<typeof useLinkLayoutSync> | null = null
|
||||||
const vueNodeData = ref<ReadonlyMap<string, VueNodeData>>(new Map())
|
const vueNodeData = ref<ReadonlyMap<string, VueNodeData>>(new Map())
|
||||||
const nodeState = ref<ReadonlyMap<string, NodeState>>(new Map())
|
const nodeState = ref<ReadonlyMap<string, NodeState>>(new Map())
|
||||||
@@ -240,12 +241,6 @@ const initializeNodeManager = () => {
|
|||||||
const { startSync } = useLayoutSync()
|
const { startSync } = useLayoutSync()
|
||||||
startSync(canvasStore.canvas)
|
startSync(canvasStore.canvas)
|
||||||
|
|
||||||
// Initialize slot layout sync for hit detection
|
|
||||||
slotSync = useSlotLayoutSync()
|
|
||||||
if (canvasStore.canvas) {
|
|
||||||
slotSync.start(canvasStore.canvas as LGraphCanvas)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize link layout sync for event-driven updates
|
// Initialize link layout sync for event-driven updates
|
||||||
linkSync = useLinkLayoutSync()
|
linkSync = useLinkLayoutSync()
|
||||||
if (canvasStore.canvas) {
|
if (canvasStore.canvas) {
|
||||||
@@ -266,12 +261,6 @@ const disposeNodeManagerAndSyncs = () => {
|
|||||||
nodeManager = null
|
nodeManager = null
|
||||||
cleanupNodeManager = null
|
cleanupNodeManager = null
|
||||||
|
|
||||||
// Clean up slot layout sync
|
|
||||||
if (slotSync) {
|
|
||||||
slotSync.stop()
|
|
||||||
slotSync = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up link layout sync
|
// Clean up link layout sync
|
||||||
if (linkSync) {
|
if (linkSync) {
|
||||||
linkSync.stop()
|
linkSync.stop()
|
||||||
@@ -298,6 +287,68 @@ watch(
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Ensure slot layout sync starts whenever a canvas is available (LiteGraph mode)
|
||||||
|
watch(
|
||||||
|
() => canvasStore.canvas,
|
||||||
|
(canvas, oldCanvas) => {
|
||||||
|
if (!canvas) {
|
||||||
|
// Canvas was removed - stop sync if active
|
||||||
|
if (slotSync && slotSyncStarted) {
|
||||||
|
slotSync.stop()
|
||||||
|
slotSyncStarted = false
|
||||||
|
}
|
||||||
|
// Clear any stale slot layouts when canvas is torn down
|
||||||
|
layoutStore.clearAllSlotLayouts()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Canvas changed - restart sync
|
||||||
|
if (oldCanvas && oldCanvas !== canvas) {
|
||||||
|
if (slotSync && slotSyncStarted) {
|
||||||
|
slotSync.stop()
|
||||||
|
slotSyncStarted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start sync if not in Vue mode and not already started
|
||||||
|
if (!slotSync) slotSync = useSlotLayoutSync()
|
||||||
|
if (!slotSyncStarted && !isVueNodesEnabled.value) {
|
||||||
|
const started = slotSync.start(canvas as LGraphCanvas)
|
||||||
|
slotSyncStarted = started
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// On rendering mode change, clear slot layouts and manage slot sync
|
||||||
|
watch(
|
||||||
|
() => isVueNodesEnabled.value,
|
||||||
|
(enabled) => {
|
||||||
|
// Always clear invalid slot layouts from the prior mode
|
||||||
|
layoutStore.clearAllSlotLayouts()
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
// Switching TO Vue: Stop slot sync to avoid duplicate registration
|
||||||
|
if (slotSync && slotSyncStarted) {
|
||||||
|
slotSync.stop()
|
||||||
|
slotSyncStarted = false
|
||||||
|
}
|
||||||
|
// DOM will re-register via useDomSlotRegistration
|
||||||
|
} else {
|
||||||
|
// Switching TO LiteGraph
|
||||||
|
if (canvasStore.canvas && comfyApp.graph) {
|
||||||
|
// Ensure slot sync is active
|
||||||
|
if (!slotSync) slotSync = useSlotLayoutSync()
|
||||||
|
if (!slotSyncStarted) {
|
||||||
|
const started = slotSync.start(canvasStore.canvas as LGraphCanvas)
|
||||||
|
slotSyncStarted = started
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: false }
|
||||||
|
)
|
||||||
|
|
||||||
// Transform state for viewport culling
|
// Transform state for viewport culling
|
||||||
const { syncWithCanvas } = useTransformState()
|
const { syncWithCanvas } = useTransformState()
|
||||||
|
|
||||||
@@ -726,6 +777,7 @@ onUnmounted(() => {
|
|||||||
if (slotSync) {
|
if (slotSync) {
|
||||||
slotSync.stop()
|
slotSync.stop()
|
||||||
slotSync = null
|
slotSync = null
|
||||||
|
slotSyncStarted = false
|
||||||
}
|
}
|
||||||
if (linkSync) {
|
if (linkSync) {
|
||||||
linkSync.stop()
|
linkSync.stop()
|
||||||
|
|||||||
@@ -371,7 +371,19 @@ class LayoutStoreImpl implements LayoutStore {
|
|||||||
updateSlotLayout(key: string, layout: SlotLayout): void {
|
updateSlotLayout(key: string, layout: SlotLayout): void {
|
||||||
const existing = this.slotLayouts.get(key)
|
const existing = this.slotLayouts.get(key)
|
||||||
|
|
||||||
if (!existing) {
|
if (existing) {
|
||||||
|
// Short-circuit if bounds and position unchanged (prevents spatial index churn)
|
||||||
|
if (
|
||||||
|
existing.bounds.x === layout.bounds.x &&
|
||||||
|
existing.bounds.y === layout.bounds.y &&
|
||||||
|
existing.bounds.width === layout.bounds.width &&
|
||||||
|
existing.bounds.height === layout.bounds.height &&
|
||||||
|
existing.position.x === layout.position.x &&
|
||||||
|
existing.position.y === layout.position.y
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
logger.debug('Adding slot:', {
|
logger.debug('Adding slot:', {
|
||||||
nodeId: layout.nodeId,
|
nodeId: layout.nodeId,
|
||||||
type: layout.type,
|
type: layout.type,
|
||||||
@@ -419,6 +431,15 @@ class LayoutStoreImpl implements LayoutStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all slot layouts and their spatial index (O(1) operations)
|
||||||
|
* Used when switching rendering modes (Vue ↔ LiteGraph)
|
||||||
|
*/
|
||||||
|
clearAllSlotLayouts(): void {
|
||||||
|
this.slotLayouts.clear()
|
||||||
|
this.slotSpatialIndex.clear()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update reroute layout data
|
* Update reroute layout data
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
|
|||||||
* Compute and register slot layouts for a node
|
* Compute and register slot layouts for a node
|
||||||
* @param node LiteGraph node to process
|
* @param node LiteGraph node to process
|
||||||
*/
|
*/
|
||||||
function computeAndRegisterSlots(node: LGraphNode): void {
|
export function computeAndRegisterSlots(node: LGraphNode): void {
|
||||||
const nodeId = String(node.id)
|
const nodeId = String(node.id)
|
||||||
const nodeLayout = layoutStore.getNodeLayoutRef(nodeId).value
|
const nodeLayout = layoutStore.getNodeLayoutRef(nodeId).value
|
||||||
|
|
||||||
@@ -59,15 +59,16 @@ export function useSlotLayoutSync() {
|
|||||||
/**
|
/**
|
||||||
* Start slot layout sync with full event-driven functionality
|
* Start slot layout sync with full event-driven functionality
|
||||||
* @param canvas LiteGraph canvas instance
|
* @param canvas LiteGraph canvas instance
|
||||||
|
* @returns true if sync was actually started, false if early-returned
|
||||||
*/
|
*/
|
||||||
function start(canvas: LGraphCanvas): void {
|
function start(canvas: LGraphCanvas): boolean {
|
||||||
// When Vue nodes are enabled, slot DOM registers exact positions.
|
// When Vue nodes are enabled, slot DOM registers exact positions.
|
||||||
// Skip calculated registration to avoid conflicts.
|
// Skip calculated registration to avoid conflicts.
|
||||||
if (LiteGraph.vueNodesMode) {
|
if (LiteGraph.vueNodesMode) {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
const graph = canvas?.graph
|
const graph = canvas?.graph
|
||||||
if (!graph) return
|
if (!graph) return false
|
||||||
|
|
||||||
// Initial registration for all nodes in the current graph
|
// Initial registration for all nodes in the current graph
|
||||||
for (const node of graph._nodes) {
|
for (const node of graph._nodes) {
|
||||||
@@ -135,6 +136,8 @@ export function useSlotLayoutSync() {
|
|||||||
graph.onTrigger = origTrigger || undefined
|
graph.onTrigger = origTrigger || undefined
|
||||||
graph.onAfterChange = origAfterChange || undefined
|
graph.onAfterChange = origAfterChange || undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ export interface LayoutStore {
|
|||||||
deleteSlotLayout(key: string): void
|
deleteSlotLayout(key: string): void
|
||||||
deleteNodeSlotLayouts(nodeId: NodeId): void
|
deleteNodeSlotLayouts(nodeId: NodeId): void
|
||||||
deleteRerouteLayout(rerouteId: RerouteId): void
|
deleteRerouteLayout(rerouteId: RerouteId): void
|
||||||
|
clearAllSlotLayouts(): void
|
||||||
|
|
||||||
// Get layout data
|
// Get layout data
|
||||||
getLinkLayout(linkId: LinkId): LinkLayout | null
|
getLinkLayout(linkId: LinkId): LinkLayout | null
|
||||||
|
|||||||
Reference in New Issue
Block a user