mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-19 22:34:15 +00:00
Defer vue node layout calculations on hidden browser tabs (#8805)
## Summary If you load the window in Nodes 2.0, then switch tabs while it is still loading, the position of the nodes is calculated incorrectly due to useElementBounding returning left=0, top=0 for the canvas element in a hidden tab, causing clientPosToCanvasPos to miscalculate node positions from the ResizeObserver measurements ## Changes - **What**: - Store observed elements while document is in hidden state - Re-observe when tab becomes visible ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8805-Defer-vue-node-layout-calculations-on-hidden-browser-tabs-3046d73d365081019ae6c403c0ac6d1a) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -8,9 +8,11 @@
|
||||
* Supports different element types (nodes, slots, widgets, etc.) with
|
||||
* customizable data attributes and update handlers.
|
||||
*/
|
||||
import { getCurrentInstance, onMounted, onUnmounted, toValue } from 'vue'
|
||||
import { getCurrentInstance, onMounted, onUnmounted, toValue, watch } from 'vue'
|
||||
import type { MaybeRefOrGetter } from 'vue'
|
||||
|
||||
import { useDocumentVisibility } from '@vueuse/core'
|
||||
|
||||
import { useSharedCanvasPositionConversion } from '@/composables/element/useCanvasPositionConversion'
|
||||
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
|
||||
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
|
||||
@@ -59,9 +61,37 @@ const trackingConfigs: Map<string, ElementTrackingConfig> = new Map([
|
||||
]
|
||||
])
|
||||
|
||||
// Elements whose ResizeObserver fired while the tab was hidden
|
||||
const deferredElements = new Set<HTMLElement>()
|
||||
const visibility = useDocumentVisibility()
|
||||
|
||||
watch(visibility, (state) => {
|
||||
if (state !== 'visible' || deferredElements.size === 0) return
|
||||
|
||||
// Re-observe deferred elements to trigger fresh measurements
|
||||
for (const element of deferredElements) {
|
||||
if (element.isConnected) {
|
||||
resizeObserver.observe(element)
|
||||
}
|
||||
}
|
||||
deferredElements.clear()
|
||||
})
|
||||
|
||||
// Single ResizeObserver instance for all Vue elements
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
if (useCanvasStore().linearMode) return
|
||||
|
||||
// Skip measurements when tab is hidden — bounding rects are unreliable
|
||||
if (visibility.value === 'hidden') {
|
||||
for (const entry of entries) {
|
||||
if (entry.target instanceof HTMLElement) {
|
||||
deferredElements.add(entry.target)
|
||||
resizeObserver.unobserve(entry.target)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Canvas is ready when this code runs; no defensive guards needed.
|
||||
const conv = useSharedCanvasPositionConversion()
|
||||
// Group updates by type, then flush via each config's handler
|
||||
|
||||
Reference in New Issue
Block a user