From 133662cdc73c0470ce84eb576dd7043174ba26c9 Mon Sep 17 00:00:00 2001
From: Simula_r <18093452+simula-r@users.noreply.github.com>
Date: Tue, 28 Oct 2025 20:23:23 -0700
Subject: [PATCH] Feat/vue noes arrange alg improved (#6357)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Summary
Improve the previous [vue node arrange
alg](https://github.com/Comfy-Org/ComfyUI_frontend/blob/5a1284660c41f2705eb8c633054a7babbac92442/src/renderer/extensions/vueNodes/layout/scaleLayoutForVueNodes.ts)
to match Litegraph much closer visually.
- In addition to the scaling of the LG node's x,y and then setting the
vue nodes position to that, we can also scale the width and height of
the LG node and set that for the Vue node wxh.
- Change from scaling from the center to the top left
- Change the zoom offset to account for the scale for seamless
transition
## Screenshots (if applicable)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6357-Feat-vue-noes-arrange-alg-improved-29b6d73d365081e7813bd6f19ce1202a)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action
Co-authored-by: JakeSchroeder
---
src/composables/graph/useVueNodeLifecycle.ts | 12 +---
...ueNodes.ts => ensureCorrectLayoutScale.ts} | 66 +++++++++++--------
src/scripts/app.ts | 14 +---
3 files changed, 41 insertions(+), 51 deletions(-)
rename src/renderer/extensions/vueNodes/layout/{scaleLayoutForVueNodes.ts => ensureCorrectLayoutScale.ts} (50%)
diff --git a/src/composables/graph/useVueNodeLifecycle.ts b/src/composables/graph/useVueNodeLifecycle.ts
index 6ebac700f..fbce66dce 100644
--- a/src/composables/graph/useVueNodeLifecycle.ts
+++ b/src/composables/graph/useVueNodeLifecycle.ts
@@ -9,7 +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 { ensureCorrectLayoutScale } from '@/renderer/extensions/vueNodes/layout/ensureCorrectLayoutScale'
import { app as comfyApp } from '@/scripts/app'
function useVueNodeLifecycleIndividual() {
@@ -78,15 +78,7 @@ 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
- }
+ ensureCorrectLayoutScale()
} else {
disposeNodeManagerAndSyncs()
}
diff --git a/src/renderer/extensions/vueNodes/layout/scaleLayoutForVueNodes.ts b/src/renderer/extensions/vueNodes/layout/ensureCorrectLayoutScale.ts
similarity index 50%
rename from src/renderer/extensions/vueNodes/layout/scaleLayoutForVueNodes.ts
rename to src/renderer/extensions/vueNodes/layout/ensureCorrectLayoutScale.ts
index 873a18c15..3d1050e43 100644
--- a/src/renderer/extensions/vueNodes/layout/scaleLayoutForVueNodes.ts
+++ b/src/renderer/extensions/vueNodes/layout/ensureCorrectLayoutScale.ts
@@ -1,4 +1,4 @@
-import type { Rect } from '@/lib/litegraph/src/interfaces'
+import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import { createBounds } from '@/lib/litegraph/src/measure'
import { useSettingStore } from '@/platform/settings/settingStore'
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
@@ -7,7 +7,7 @@ import { app as comfyApp } from '@/scripts/app'
const SCALE_FACTOR = 1.75
-export function scaleLayoutForVueNodes() {
+export function ensureCorrectLayoutScale() {
const settingStore = useSettingStore()
const autoScaleLayoutSetting = settingStore.get(
@@ -19,68 +19,76 @@ export function scaleLayoutForVueNodes() {
}
const canvas = comfyApp.canvas
- const graph = canvas.graph
+ const graph = canvas?.graph
if (!graph || !graph.nodes) return
+ if (graph.extra?.vueNodesScaled === true) {
+ return
+ }
+
+ const vueNodesEnabled = settingStore.get('Comfy.VueNodes.Enabled')
+ if (!vueNodesEnabled) {
+ 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 originX = lgBounds[0]
+ const originY = lgBounds[1]
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
+ const lgBodyY = lgNode.pos[1] - LiteGraph.NODE_TITLE_HEIGHT
+
+ const relativeX = lgNode.pos[0] - originX
+ const relativeY = lgBodyY - originY
+ const newX = originX + relativeX * SCALE_FACTOR
+ const newY = originY + relativeY * SCALE_FACTOR
+ const newWidth = lgNode.width * SCALE_FACTOR
+ const newHeight = lgNode.height * SCALE_FACTOR
yjsMoveNodeUpdates.push({
nodeId: vueNode.id,
bounds: {
x: newX,
y: newY,
- width: vueNode.bounds.width,
- height: vueNode.bounds.height
+ width: newWidth,
+ height: newHeight
}
})
-
- 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
+ const groupBodyY = group.pos[1] - LiteGraph.NODE_TITLE_HEIGHT
- group.pos = [
- lgBoundsCenterX + vectorX * SCALE_FACTOR,
- lgBoundsCenterY + vectorY * SCALE_FACTOR
- ]
+ const relativeX = group.pos[0] - originX
+ const relativeY = groupBodyY - originY
+
+ const newPosY =
+ originY + relativeY * SCALE_FACTOR + LiteGraph.NODE_TITLE_HEIGHT
+
+ group.pos = [originX + relativeX * SCALE_FACTOR, newPosY]
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.
- })
- }
+ const originScreen = canvas.ds.convertOffsetToCanvas([originX, originY])
+ canvas.ds.changeScale(canvas.ds.scale / SCALE_FACTOR, originScreen)
+
+ if (!graph.extra) graph.extra = {}
+ graph.extra.vueNodesScaled = true
}
diff --git a/src/scripts/app.ts b/src/scripts/app.ts
index 985815650..3e815e87d 100644
--- a/src/scripts/app.ts
+++ b/src/scripts/app.ts
@@ -5,7 +5,6 @@ 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'
@@ -99,7 +98,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'
+import { ensureCorrectLayoutScale } from '@/renderer/extensions/vueNodes/layout/ensureCorrectLayoutScale'
export const ANIM_PREVIEW_WIDGET = '$$comfy_animation_preview'
@@ -1184,16 +1183,7 @@ export class ComfyApp {
// @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
- }
+ ensureCorrectLayoutScale()
if (
restore_view &&