Merge remote-tracking branch 'origin/bl-grahhhh' into bl-building-on-top

This commit is contained in:
Benjamin Lu
2025-09-09 10:34:33 -07:00
2 changed files with 67 additions and 12 deletions

View File

@@ -0,0 +1,52 @@
/**
* 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'
// 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, update } = 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
// Force an immediate measurement once the element is resolved
if (containerRef.value) update()
}
}
// Notify subscribers when the bounding rect changes
watch([x, y, width, height], () => {
if (listeners.size) listeners.forEach((cb) => cb())
})
export function onCanvasRectChange(cb: () => void): () => void {
ensureContainer()
listeners.add(cb)
return () => listeners.delete(cb)
}
export function getCanvasClientOrigin() {
ensureContainer()
return { left: x.value || 0, top: y.value || 0 }
}

View File

@@ -21,6 +21,10 @@ import {
} from 'vue'
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 type { Point as LayoutPoint } from '@/renderer/core/layout/types'
@@ -52,7 +56,7 @@ const cleanupFunctions = new WeakMap<
Ref<HTMLElement | null>,
{
stopWatcher?: WatchStopHandle
handleResize?: () => void
unsubscribeRectChange?: () => void
}
>()
@@ -90,6 +94,8 @@ export function useDomSlotRegistration(options: SlotRegistrationOptions) {
if (!el || !transform?.screenToCanvas) return
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)
if (lastMeasuredBounds.value) {
@@ -106,10 +112,10 @@ export function useDomSlotRegistration(options: SlotRegistrationOptions) {
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 = {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
x: rect.left + rect.width / 2 - canvasLeft,
y: rect.top + rect.height / 2 - canvasTop
}
const centerCanvas = transform.screenToCanvas(centerScreen)
@@ -192,12 +198,11 @@ export function useDomSlotRegistration(options: SlotRegistrationOptions) {
const cleanup = cleanupFunctions.get(elRef) || {}
cleanup.stopWatcher = stopWatcher
// Window resize - remeasure as viewport changed
const handleResize = () => {
// Subscribe to canvas rect changes (covers window resize and layout changes)
const unsubscribe = onCanvasRectChange(() =>
scheduleMeasurement(measureAndCacheOffset)
}
window.addEventListener('resize', handleResize, { passive: true })
cleanup.handleResize = handleResize
)
cleanup.unsubscribeRectChange = unsubscribe
cleanupFunctions.set(elRef, cleanup)
})
@@ -209,9 +214,7 @@ export function useDomSlotRegistration(options: SlotRegistrationOptions) {
const cleanup = cleanupFunctions.get(elRef)
if (cleanup) {
if (cleanup.stopWatcher) cleanup.stopWatcher()
if (cleanup.handleResize) {
window.removeEventListener('resize', cleanup.handleResize)
}
if (cleanup.unsubscribeRectChange) cleanup.unsubscribeRectChange()
cleanupFunctions.delete(elRef)
}