mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-28 10:12:11 +00:00
Add offset
This commit is contained in:
65
src/renderer/core/layout/dom/canvasRectCache.ts
Normal file
65
src/renderer/core/layout/dom/canvasRectCache.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Canvas Rect Cache (VueUse-based)
|
||||||
|
*
|
||||||
|
* Tracks the client-origin and size of the graph canvas container using
|
||||||
|
* useElementBounding, and exposes a small API to read the rect and
|
||||||
|
* subscribe to changes.
|
||||||
|
*
|
||||||
|
* We assume no document scrolling (body is overflow: hidden). Layout
|
||||||
|
* changes are driven by window resize and container/splitter changes.
|
||||||
|
*/
|
||||||
|
import { useElementBounding } from '@vueuse/core'
|
||||||
|
import { shallowRef, watch } from 'vue'
|
||||||
|
|
||||||
|
type Rect = DOMRectReadOnly
|
||||||
|
|
||||||
|
// Target container element (covers the canvas fully and shares its origin)
|
||||||
|
const containerRef = shallowRef<HTMLElement | null>(null)
|
||||||
|
|
||||||
|
// Bind bounding measurement once; element may be resolved later
|
||||||
|
const { x, y, width, height } = useElementBounding(containerRef, {
|
||||||
|
// Track layout changes from resize; scrolling is disabled globally
|
||||||
|
windowResize: true,
|
||||||
|
windowScroll: false,
|
||||||
|
immediate: true
|
||||||
|
})
|
||||||
|
|
||||||
|
// Listener registry for external subscribers
|
||||||
|
const listeners = new Set<() => void>()
|
||||||
|
|
||||||
|
function ensureContainer() {
|
||||||
|
if (!containerRef.value) {
|
||||||
|
containerRef.value = document.getElementById(
|
||||||
|
'graph-canvas-container'
|
||||||
|
) as HTMLElement | null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify subscribers when the bounding rect changes
|
||||||
|
watch([x, y, width, height], () => {
|
||||||
|
if (listeners.size) listeners.forEach((cb) => cb())
|
||||||
|
})
|
||||||
|
|
||||||
|
export function invalidate(notify = false) {
|
||||||
|
if (notify && listeners.size) listeners.forEach((cb) => cb())
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onCanvasRectChange(cb: () => void): () => void {
|
||||||
|
ensureContainer()
|
||||||
|
listeners.add(cb)
|
||||||
|
return () => listeners.delete(cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCanvasRect(): Rect {
|
||||||
|
ensureContainer()
|
||||||
|
const lx = x.value || 0
|
||||||
|
const ly = y.value || 0
|
||||||
|
const w = width.value || 0
|
||||||
|
const h = height.value || 0
|
||||||
|
return new DOMRect(lx, ly, w, h)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCanvasClientOrigin() {
|
||||||
|
ensureContainer()
|
||||||
|
return { left: x.value || 0, top: y.value || 0 }
|
||||||
|
}
|
||||||
@@ -21,6 +21,10 @@ import {
|
|||||||
} from 'vue'
|
} from 'vue'
|
||||||
|
|
||||||
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
|
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
|
||||||
|
import {
|
||||||
|
getCanvasClientOrigin,
|
||||||
|
onCanvasRectChange
|
||||||
|
} from '@/renderer/core/layout/dom/canvasRectCache'
|
||||||
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
|
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
|
||||||
import type { Point as LayoutPoint } from '@/renderer/core/layout/types'
|
import type { Point as LayoutPoint } from '@/renderer/core/layout/types'
|
||||||
|
|
||||||
@@ -52,7 +56,7 @@ const cleanupFunctions = new WeakMap<
|
|||||||
Ref<HTMLElement | null>,
|
Ref<HTMLElement | null>,
|
||||||
{
|
{
|
||||||
stopWatcher?: WatchStopHandle
|
stopWatcher?: WatchStopHandle
|
||||||
handleResize?: () => void
|
unsubscribeRectChange?: () => void
|
||||||
}
|
}
|
||||||
>()
|
>()
|
||||||
|
|
||||||
@@ -90,6 +94,8 @@ export function useDomSlotRegistration(options: SlotRegistrationOptions) {
|
|||||||
if (!el || !transform?.screenToCanvas) return
|
if (!el || !transform?.screenToCanvas) return
|
||||||
|
|
||||||
const rect = el.getBoundingClientRect()
|
const rect = el.getBoundingClientRect()
|
||||||
|
// Normalize to canvas-relative screen coordinates (CSS pixels)
|
||||||
|
const { left: canvasLeft, top: canvasTop } = getCanvasClientOrigin()
|
||||||
|
|
||||||
// Skip if bounds haven't changed significantly (within 0.5px)
|
// Skip if bounds haven't changed significantly (within 0.5px)
|
||||||
if (lastMeasuredBounds.value) {
|
if (lastMeasuredBounds.value) {
|
||||||
@@ -106,10 +112,10 @@ export function useDomSlotRegistration(options: SlotRegistrationOptions) {
|
|||||||
|
|
||||||
lastMeasuredBounds.value = rect
|
lastMeasuredBounds.value = rect
|
||||||
|
|
||||||
// Center of the visual connector (dot) in screen coords
|
// Center of the visual connector (dot) in canvas-relative screen coords
|
||||||
const centerScreen = {
|
const centerScreen = {
|
||||||
x: rect.left + rect.width / 2,
|
x: rect.left + rect.width / 2 - canvasLeft,
|
||||||
y: rect.top + rect.height / 2
|
y: rect.top + rect.height / 2 - canvasTop
|
||||||
}
|
}
|
||||||
const centerCanvas = transform.screenToCanvas(centerScreen)
|
const centerCanvas = transform.screenToCanvas(centerScreen)
|
||||||
|
|
||||||
@@ -192,12 +198,11 @@ export function useDomSlotRegistration(options: SlotRegistrationOptions) {
|
|||||||
const cleanup = cleanupFunctions.get(elRef) || {}
|
const cleanup = cleanupFunctions.get(elRef) || {}
|
||||||
cleanup.stopWatcher = stopWatcher
|
cleanup.stopWatcher = stopWatcher
|
||||||
|
|
||||||
// Window resize - remeasure as viewport changed
|
// Subscribe to canvas rect changes (covers window resize and layout changes)
|
||||||
const handleResize = () => {
|
const unsubscribe = onCanvasRectChange(() =>
|
||||||
scheduleMeasurement(measureAndCacheOffset)
|
scheduleMeasurement(measureAndCacheOffset)
|
||||||
}
|
)
|
||||||
window.addEventListener('resize', handleResize, { passive: true })
|
cleanup.unsubscribeRectChange = unsubscribe
|
||||||
cleanup.handleResize = handleResize
|
|
||||||
cleanupFunctions.set(elRef, cleanup)
|
cleanupFunctions.set(elRef, cleanup)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -209,9 +214,7 @@ export function useDomSlotRegistration(options: SlotRegistrationOptions) {
|
|||||||
const cleanup = cleanupFunctions.get(elRef)
|
const cleanup = cleanupFunctions.get(elRef)
|
||||||
if (cleanup) {
|
if (cleanup) {
|
||||||
if (cleanup.stopWatcher) cleanup.stopWatcher()
|
if (cleanup.stopWatcher) cleanup.stopWatcher()
|
||||||
if (cleanup.handleResize) {
|
if (cleanup.unsubscribeRectChange) cleanup.unsubscribeRectChange()
|
||||||
window.removeEventListener('resize', cleanup.handleResize)
|
|
||||||
}
|
|
||||||
cleanupFunctions.delete(elRef)
|
cleanupFunctions.delete(elRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user