mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-25 08:49:36 +00:00
Revert "refactor(vue-nodes): typed TransformState InjectionKey, safer ResizeObserver sizing, centralized slot tracking, and small readability updates"
This reverts commit 428752619c.
This commit is contained in:
@@ -1,199 +0,0 @@
|
||||
/**
|
||||
* Centralized Slot Element Tracking
|
||||
*
|
||||
* Registers slot connector DOM elements per node, measures their canvas-space
|
||||
* positions in a single batched pass, and caches offsets so that node moves
|
||||
* update slot positions without DOM reads.
|
||||
*/
|
||||
import { type Ref, inject, nextTick, onMounted, onUnmounted, watch } from 'vue'
|
||||
|
||||
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
|
||||
import { TransformStateKey } from '@/renderer/core/layout/injectionKeys'
|
||||
import { getSlotKey } from '@/renderer/core/layout/slots/slotIdentifier'
|
||||
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
|
||||
import type { Point } from '@/renderer/core/layout/types'
|
||||
|
||||
type SlotEntry = {
|
||||
el: HTMLElement
|
||||
index: number
|
||||
isInput: boolean
|
||||
cachedOffset?: { x: number; y: number }
|
||||
}
|
||||
|
||||
type NodeEntry = {
|
||||
nodeId: string
|
||||
screenToCanvas?: (p: Point) => Point
|
||||
slots: Map<string, SlotEntry>
|
||||
stopWatch?: () => void
|
||||
}
|
||||
|
||||
// Registry of nodes and their slots
|
||||
const nodeRegistry = new Map<string, NodeEntry>()
|
||||
|
||||
// RAF batching
|
||||
const pendingNodes = new Set<string>()
|
||||
let rafId: number | null = null
|
||||
|
||||
function scheduleNodeMeasure(nodeId: string) {
|
||||
pendingNodes.add(nodeId)
|
||||
if (rafId == null) {
|
||||
rafId = requestAnimationFrame(() => {
|
||||
rafId = null
|
||||
runBatchedMeasure()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function runBatchedMeasure() {
|
||||
if (pendingNodes.size === 0) return
|
||||
|
||||
// Read container origin once
|
||||
const container = document.getElementById('graph-canvas-container')
|
||||
const originRect = container?.getBoundingClientRect()
|
||||
const originLeft = originRect?.left ?? 0
|
||||
const originTop = originRect?.top ?? 0
|
||||
|
||||
for (const nodeId of Array.from(pendingNodes)) {
|
||||
pendingNodes.delete(nodeId)
|
||||
const node = nodeRegistry.get(nodeId)
|
||||
if (!node) continue
|
||||
if (!node.screenToCanvas) continue
|
||||
const nodeLayout = layoutStore.getNodeLayoutRef(nodeId).value
|
||||
if (!nodeLayout) continue
|
||||
|
||||
for (const [slotKey, entry] of node.slots) {
|
||||
const rect = entry.el.getBoundingClientRect()
|
||||
const centerScreen = {
|
||||
x: rect.left + rect.width / 2 - originLeft,
|
||||
y: rect.top + rect.height / 2 - originTop
|
||||
}
|
||||
const centerCanvas = node.screenToCanvas(centerScreen)
|
||||
|
||||
// Cache offset relative to node position for fast updates later
|
||||
entry.cachedOffset = {
|
||||
x: centerCanvas.x - nodeLayout.position.x,
|
||||
y: centerCanvas.y - nodeLayout.position.y
|
||||
}
|
||||
|
||||
// Persist layout in canvas coordinates
|
||||
const size = LiteGraph.NODE_SLOT_HEIGHT
|
||||
const half = size / 2
|
||||
layoutStore.updateSlotLayout(slotKey, {
|
||||
nodeId,
|
||||
index: entry.index,
|
||||
type: entry.isInput ? 'input' : 'output',
|
||||
position: { x: centerCanvas.x, y: centerCanvas.y },
|
||||
bounds: {
|
||||
x: centerCanvas.x - half,
|
||||
y: centerCanvas.y - half,
|
||||
width: size,
|
||||
height: size
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateNodeSlotsFromCache(nodeId: string) {
|
||||
const node = nodeRegistry.get(nodeId)
|
||||
if (!node) return
|
||||
const nodeLayout = layoutStore.getNodeLayoutRef(nodeId).value
|
||||
if (!nodeLayout) return
|
||||
|
||||
for (const [slotKey, entry] of node.slots) {
|
||||
if (!entry.cachedOffset) {
|
||||
// schedule a remeasure to seed offset
|
||||
scheduleNodeMeasure(nodeId)
|
||||
continue
|
||||
}
|
||||
const centerCanvas = {
|
||||
x: nodeLayout.position.x + entry.cachedOffset.x,
|
||||
y: nodeLayout.position.y + entry.cachedOffset.y
|
||||
}
|
||||
const size = LiteGraph.NODE_SLOT_HEIGHT
|
||||
const half = size / 2
|
||||
layoutStore.updateSlotLayout(slotKey, {
|
||||
nodeId,
|
||||
index: entry.index,
|
||||
type: entry.isInput ? 'input' : 'output',
|
||||
position: { x: centerCanvas.x, y: centerCanvas.y },
|
||||
bounds: {
|
||||
x: centerCanvas.x - half,
|
||||
y: centerCanvas.y - half,
|
||||
width: size,
|
||||
height: size
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function useSlotElementTracking(options: {
|
||||
nodeId: string
|
||||
index: number
|
||||
isInput: boolean
|
||||
element: Ref<HTMLElement | null>
|
||||
}) {
|
||||
const { nodeId, index, isInput, element } = options
|
||||
|
||||
// Get transform utilities from TransformPane
|
||||
const transformState = inject(TransformStateKey)
|
||||
|
||||
onMounted(async () => {
|
||||
if (!nodeId) return
|
||||
await nextTick()
|
||||
const el = element.value
|
||||
if (!el) return
|
||||
|
||||
// Ensure node entry
|
||||
let node = nodeRegistry.get(nodeId)
|
||||
if (!node) {
|
||||
node = {
|
||||
nodeId,
|
||||
screenToCanvas: transformState?.screenToCanvas,
|
||||
slots: new Map()
|
||||
}
|
||||
nodeRegistry.set(nodeId, node)
|
||||
// Subscribe once per node to layout changes for fast cached updates
|
||||
const nodeRef = layoutStore.getNodeLayoutRef(nodeId)
|
||||
const stop = watch(
|
||||
nodeRef,
|
||||
(newLayout, oldLayout) => {
|
||||
if (newLayout && oldLayout) {
|
||||
// Update from cache on any position/size change
|
||||
updateNodeSlotsFromCache(nodeId)
|
||||
}
|
||||
},
|
||||
{ flush: 'post' }
|
||||
)
|
||||
node.stopWatch = () => stop()
|
||||
}
|
||||
|
||||
// Register slot
|
||||
const slotKey = getSlotKey(nodeId, index, isInput)
|
||||
node.slots.set(slotKey, { el, index, isInput })
|
||||
|
||||
// Seed measurement
|
||||
scheduleNodeMeasure(nodeId)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (!nodeId) return
|
||||
const node = nodeRegistry.get(nodeId)
|
||||
if (!node) return
|
||||
|
||||
// Remove this slot from registry and layout
|
||||
const slotKey = getSlotKey(nodeId, index, isInput)
|
||||
node.slots.delete(slotKey)
|
||||
layoutStore.deleteSlotLayout(slotKey)
|
||||
|
||||
// If node has no more slots, clean up
|
||||
if (node.slots.size === 0) {
|
||||
if (node.stopWatch) node.stopWatch()
|
||||
nodeRegistry.delete(nodeId)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
remeasure: () => scheduleNodeMeasure(nodeId)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user