Feat/vue noes arrange alg improved (#6357)

## Summary

Improve the previous [vue node arrange
alg](5a1284660c/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)

<img width="1868" height="1646" alt="image"
src="https://github.com/user-attachments/assets/bc816819-211f-4619-a02a-8d167b5dc1fd"
/>

<img width="1868" height="1648" alt="image (1)"
src="https://github.com/user-attachments/assets/61faf530-1994-4cf9-bca9-a7ab6f9740c2"
/>

┆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 <action@github.com>
Co-authored-by: JakeSchroeder <jake@axiom.co>
This commit is contained in:
Simula_r
2025-10-28 20:23:23 -07:00
committed by GitHub
parent a54c1516ae
commit 133662cdc7
3 changed files with 41 additions and 51 deletions

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -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 &&