mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
fix: skip redundant appScalePercentage updates during zoom/pan (#9403)
## What Add equality check before updating `appScalePercentage` reactive ref. ## Why Firefox profiler shows 586 `setElementText` markers from continuous text interpolation updates during zoom/pan. The rounded percentage value often doesn't change between events. ## How Extract `updateAppScalePercentage()` helper with equality guard — compares new rounded value to current before assigning to the ref. ## Perf Impact Expected: eliminates ~90% of `setElementText` markers during zoom/pan ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9403-fix-skip-redundant-appScalePercentage-updates-during-zoom-pan-31a6d73d3650812db8f2d68ac73c95b0) by [Unito](https://www.unito.io)
This commit is contained in:
87
src/renderer/core/canvas/canvasStore.test.ts
Normal file
87
src/renderer/core/canvas/canvasStore.test.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||
|
||||
vi.mock('@/composables/useAppMode', () => ({
|
||||
useAppMode: () => ({
|
||||
isAppMode: { value: false },
|
||||
setMode: vi.fn()
|
||||
})
|
||||
}))
|
||||
|
||||
vi.mock('@/scripts/app', () => ({
|
||||
app: {
|
||||
canvas: {
|
||||
ds: {
|
||||
scale: 1,
|
||||
offset: [0, 0] as [number, number],
|
||||
onChanged: undefined as
|
||||
| ((scale: number, offset: [number, number]) => void)
|
||||
| undefined,
|
||||
element: null,
|
||||
changeScale: vi.fn()
|
||||
},
|
||||
setDirty: vi.fn(),
|
||||
graph: null,
|
||||
selectedItems: new Set(),
|
||||
subgraph: undefined,
|
||||
canvas: {
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
describe('useCanvasStore', () => {
|
||||
let store: ReturnType<typeof useCanvasStore>
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useCanvasStore()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('appScalePercentage', () => {
|
||||
it('rounds scale to integer percentage', async () => {
|
||||
const { app } = await import('@/scripts/app')
|
||||
|
||||
app.canvas.ds.scale = 1.004
|
||||
store.initScaleSync()
|
||||
expect(store.appScalePercentage).toBe(100)
|
||||
|
||||
app.canvas.ds.scale = 1.506
|
||||
app.canvas.ds.onChanged!(app.canvas.ds.scale, app.canvas.ds.offset)
|
||||
expect(store.appScalePercentage).toBe(151)
|
||||
})
|
||||
|
||||
it('updates reactive value when rounded scale changes', async () => {
|
||||
const { app } = await import('@/scripts/app')
|
||||
|
||||
app.canvas.ds.scale = 1.0
|
||||
store.initScaleSync()
|
||||
expect(store.appScalePercentage).toBe(100)
|
||||
|
||||
app.canvas.ds.scale = 1.5
|
||||
app.canvas.ds.onChanged!(app.canvas.ds.scale, app.canvas.ds.offset)
|
||||
|
||||
expect(store.appScalePercentage).toBe(150)
|
||||
})
|
||||
|
||||
it('preserves original onChanged handler', async () => {
|
||||
const { app } = await import('@/scripts/app')
|
||||
const originalHandler = vi.fn()
|
||||
app.canvas.ds.onChanged = originalHandler
|
||||
|
||||
app.canvas.ds.scale = 1.0
|
||||
store.initScaleSync()
|
||||
|
||||
app.canvas.ds.scale = 2.0
|
||||
app.canvas.ds.onChanged!(app.canvas.ds.scale, app.canvas.ds.offset)
|
||||
|
||||
expect(originalHandler).toHaveBeenCalledWith(2.0, app.canvas.ds.offset)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -43,6 +43,9 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||
|
||||
// Reactive scale percentage that syncs with app.canvas.ds.scale
|
||||
const appScalePercentage = ref(100)
|
||||
const updateAppScalePercentage = (scale: number) => {
|
||||
appScalePercentage.value = Math.round(scale * 100)
|
||||
}
|
||||
|
||||
const { isAppMode, setMode } = useAppMode()
|
||||
const linearMode = computed({
|
||||
@@ -59,12 +62,12 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||
if (app.canvas?.ds) {
|
||||
// Initial sync
|
||||
originalOnChanged = app.canvas.ds.onChanged
|
||||
appScalePercentage.value = Math.round(app.canvas.ds.scale * 100)
|
||||
updateAppScalePercentage(app.canvas.ds.scale)
|
||||
|
||||
// Set up continuous sync
|
||||
app.canvas.ds.onChanged = () => {
|
||||
if (app.canvas?.ds?.scale) {
|
||||
appScalePercentage.value = Math.round(app.canvas.ds.scale * 100)
|
||||
updateAppScalePercentage(app.canvas.ds.scale)
|
||||
}
|
||||
// Call original handler if exists
|
||||
originalOnChanged?.(app.canvas.ds.scale, app.canvas.ds.offset)
|
||||
@@ -106,7 +109,7 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||
app.canvas.setDirty(true, true)
|
||||
|
||||
// Update reactive value immediately for UI consistency
|
||||
appScalePercentage.value = Math.round(newScale * 100)
|
||||
updateAppScalePercentage(newScale)
|
||||
}
|
||||
|
||||
const currentGraph = shallowRef<LGraph | null>(null)
|
||||
|
||||
Reference in New Issue
Block a user