diff --git a/browser_tests/fixtures/ComfyPage.ts b/browser_tests/fixtures/ComfyPage.ts index b01de101e5..8059fb4cb4 100644 --- a/browser_tests/fixtures/ComfyPage.ts +++ b/browser_tests/fixtures/ComfyPage.ts @@ -1657,7 +1657,8 @@ export const comfyPageFixture = base.extend<{ 'Comfy.userId': userId, // Set tutorial completed to true to avoid loading the tutorial workflow. 'Comfy.TutorialCompleted': true, - 'Comfy.SnapToGrid.GridSize': testComfySnapToGridGridSize + 'Comfy.SnapToGrid.GridSize': testComfySnapToGridGridSize, + 'Comfy.VueNodes.AutoScaleLayout': false }) } catch (e) { console.error(e) diff --git a/src/composables/graph/useVueNodeLifecycle.ts b/src/composables/graph/useVueNodeLifecycle.ts index 2b32e51bf3..6ebac700fd 100644 --- a/src/composables/graph/useVueNodeLifecycle.ts +++ b/src/composables/graph/useVueNodeLifecycle.ts @@ -9,6 +9,7 @@ import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMutations' import { layoutStore } from '@/renderer/core/layout/store/layoutStore' import { useLayoutSync } from '@/renderer/core/layout/sync/useLayoutSync' +import { scaleLayoutForVueNodes } from '@/renderer/extensions/vueNodes/layout/scaleLayoutForVueNodes' import { app as comfyApp } from '@/scripts/app' function useVueNodeLifecycleIndividual() { @@ -77,6 +78,15 @@ function useVueNodeLifecycleIndividual() { (enabled) => { if (enabled) { initializeNodeManager() + + const graph = comfyApp.canvas.graph + if (graph && !graph.extra) { + graph.extra = {} + } + if (graph && !graph.extra.vueNodesScaled) { + scaleLayoutForVueNodes() + graph.extra.vueNodesScaled = true + } } else { disposeNodeManagerAndSyncs() } diff --git a/src/platform/settings/constants/coreSettings.ts b/src/platform/settings/constants/coreSettings.ts index c4fda0ef92..2b8eba44c9 100644 --- a/src/platform/settings/constants/coreSettings.ts +++ b/src/platform/settings/constants/coreSettings.ts @@ -1065,6 +1065,16 @@ export const CORE_SETTINGS: SettingParams[] = [ experimental: true, versionAdded: '1.27.1' }, + { + id: 'Comfy.VueNodes.AutoScaleLayout', + name: 'Auto-scale layout for Vue nodes', + tooltip: + 'Automatically scale node positions when switching to Vue rendering to prevent overlap', + type: 'boolean', + experimental: true, + defaultValue: false, + versionAdded: '1.30.3' + }, { id: 'Comfy.Assets.UseAssetAPI', name: 'Use Asset API for model library', diff --git a/src/renderer/extensions/vueNodes/layout/scaleLayoutForVueNodes.ts b/src/renderer/extensions/vueNodes/layout/scaleLayoutForVueNodes.ts new file mode 100644 index 0000000000..873a18c15d --- /dev/null +++ b/src/renderer/extensions/vueNodes/layout/scaleLayoutForVueNodes.ts @@ -0,0 +1,86 @@ +import type { Rect } from '@/lib/litegraph/src/interfaces' +import { createBounds } from '@/lib/litegraph/src/measure' +import { useSettingStore } from '@/platform/settings/settingStore' +import { layoutStore } from '@/renderer/core/layout/store/layoutStore' +import type { NodeBoundsUpdate } from '@/renderer/core/layout/types' +import { app as comfyApp } from '@/scripts/app' + +const SCALE_FACTOR = 1.75 + +export function scaleLayoutForVueNodes() { + const settingStore = useSettingStore() + + const autoScaleLayoutSetting = settingStore.get( + 'Comfy.VueNodes.AutoScaleLayout' + ) + + if (autoScaleLayoutSetting === false) { + return + } + + const canvas = comfyApp.canvas + const graph = canvas.graph + + if (!graph || !graph.nodes) return + + const lgBounds = createBounds(graph.nodes) + + if (!lgBounds) return + + const allVueNodes = layoutStore.getAllNodes().value + + const lgBoundsCenterX = lgBounds![0] + lgBounds![2] / 2 + const lgBoundsCenterY = lgBounds![1] + lgBounds![3] / 2 + + const lgNodesById = new Map( + graph.nodes.map((node) => [String(node.id), node]) + ) + + const yjsMoveNodeUpdates: NodeBoundsUpdate[] = [] + const scaledNodesForBounds: Array<{ boundingRect: Rect }> = [] + + for (const vueNode of allVueNodes.values()) { + const lgNode = lgNodesById.get(String(vueNode.id)) + if (!lgNode) continue + + const vectorX = lgNode.pos[0] - lgBoundsCenterX + const vectorY = lgNode.pos[1] - lgBoundsCenterY + const newX = lgBoundsCenterX + vectorX * SCALE_FACTOR + const newY = lgBoundsCenterY + vectorY * SCALE_FACTOR + + yjsMoveNodeUpdates.push({ + nodeId: vueNode.id, + bounds: { + x: newX, + y: newY, + width: vueNode.bounds.width, + height: vueNode.bounds.height + } + }) + + scaledNodesForBounds.push({ + boundingRect: [newX, newY, vueNode.bounds.width, vueNode.bounds.height] + }) + } + + layoutStore.batchUpdateNodeBounds(yjsMoveNodeUpdates) + + const scaledLgBounds = createBounds(scaledNodesForBounds) + + graph.groups.forEach((group) => { + const vectorX = group.pos[0] - lgBoundsCenterX + const vectorY = group.pos[1] - lgBoundsCenterY + + group.pos = [ + lgBoundsCenterX + vectorX * SCALE_FACTOR, + lgBoundsCenterY + vectorY * SCALE_FACTOR + ] + group.size = [group.size[0] * SCALE_FACTOR, group.size[1] * SCALE_FACTOR] + }) + + if (scaledLgBounds) { + canvas.ds.fitToBounds(scaledLgBounds, { + zoom: 0.5 //Makes it so the fit to view is slightly zoomed out and not edge to edge. + }) + } +} diff --git a/src/schemas/apiSchema.ts b/src/schemas/apiSchema.ts index df1b102d11..30b0e57eba 100644 --- a/src/schemas/apiSchema.ts +++ b/src/schemas/apiSchema.ts @@ -469,6 +469,7 @@ const zSettings = z.object({ 'Comfy.Canvas.LeftMouseClickBehavior': z.string(), 'Comfy.Canvas.MouseWheelScroll': z.string(), 'Comfy.VueNodes.Enabled': z.boolean(), + 'Comfy.VueNodes.AutoScaleLayout': z.boolean(), 'Comfy.Assets.UseAssetAPI': z.boolean(), 'Comfy-Desktop.AutoUpdate': z.boolean(), 'Comfy-Desktop.SendStatistics': z.boolean(), diff --git a/src/scripts/app.ts b/src/scripts/app.ts index 24f6124dc8..9858156503 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -5,6 +5,7 @@ import { reactive, unref } from 'vue' import { shallowRef } from 'vue' import { useCanvasPositionConversion } from '@/composables/element/useCanvasPositionConversion' +import { useVueFeatureFlags } from '@/composables/useVueFeatureFlags' import { registerProxyWidgets } from '@/core/graph/subgraph/proxyWidget' import { st, t } from '@/i18n' import type { IContextMenuValue } from '@/lib/litegraph/src/interfaces' @@ -98,6 +99,7 @@ import { $el, ComfyUI } from './ui' import { ComfyAppMenu } from './ui/menu/index' import { clone } from './utils' import { type ComfyWidgetConstructor } from './widgets' +import { scaleLayoutForVueNodes } from '@/renderer/extensions/vueNodes/layout/scaleLayoutForVueNodes' export const ANIM_PREVIEW_WIDGET = '$$comfy_animation_preview' @@ -1181,6 +1183,18 @@ export class ComfyApp { try { // @ts-expect-error Discrepancies between zod and litegraph - in progress this.graph.configure(graphData) + + const vueMode = useVueFeatureFlags().shouldRenderVueNodes.value + + if (!this.graph.extra) { + this.graph.extra = {} + } + + if (vueMode && !this.graph.extra.vueNodesScaled) { + scaleLayoutForVueNodes() + this.graph.extra.vueNodesScaled = true + } + if ( restore_view && useSettingStore().get('Comfy.EnableWorkflowViewRestore')