Do not delay fit to view on graph restore (#7645)

Fixes a bug where swapping to a different workflow from the inside of a
subgraph would cause nodes to be in an incorrect position after swapping
back. in vue mode

Prior to an unknown-but-recent PR, all nodes would would stack on the
origin. This PR instead solves the remaining issue where having
`ComfyEnableWorkflowViewRestore` would cause incorrect node positions.

This is done by not delaying the fitView by a frame (which causes it to
occur after the graph is no longer in the configuring state). In order
to accomplish this, the code in LGraphNode has been updated to allow
measuring node bounds without requiring a ctx argument. This arg is only
used to ensure sufficient width for a node's title and is irrelevant
when loading an existing graph.

| Before | After |
| ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/7f73817b-36e9-4400-8342-9e660cb36628"/>
| <img width="360" alt="after"
src="https://github.com/user-attachments/assets/c7ab4b99-2797-4276-9703-58d489cc3eaf"
/>|

See also #7591, which solves similar issues, but does not resolve this
bug.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7645-Do-not-delay-fit-to-view-on-graph-restore-2ce6d73d36508153972cc7b5948ce375)
by [Unito](https://www.unito.io)
This commit is contained in:
AustinMroz
2025-12-19 20:03:52 -08:00
committed by GitHub
parent 88df6627f0
commit 68ccd683ad
3 changed files with 17 additions and 9 deletions

View File

@@ -2000,7 +2000,7 @@ export class LGraphNode
* @param out `x, y, width, height` are written to this array.
* @param ctx The canvas context to use for measuring text.
*/
measure(out: Rect, ctx: CanvasRenderingContext2D): void {
measure(out: Rect, ctx?: CanvasRenderingContext2D): void {
const titleMode = this.title_mode
const renderTitle =
titleMode != TitleMode.TRANSPARENT_TITLE &&
@@ -2013,11 +2013,13 @@ export class LGraphNode
out[2] = this.size[0]
out[3] = this.size[1] + titleHeight
} else {
ctx.font = this.innerFontStyle
if (ctx) ctx.font = this.innerFontStyle
this._collapsed_width = Math.min(
this.size[0],
ctx.measureText(this.getTitle() ?? '').width +
LiteGraph.NODE_TITLE_HEIGHT * 2
ctx
? ctx.measureText(this.getTitle() ?? '').width +
LiteGraph.NODE_TITLE_HEIGHT * 2
: 0
)
out[2] = this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH
out[3] = LiteGraph.NODE_TITLE_HEIGHT
@@ -2047,7 +2049,7 @@ export class LGraphNode
* Calculates the render area of this node, populating both {@link boundingRect} and {@link renderArea}.
* Called automatically at the start of every frame.
*/
updateArea(ctx: CanvasRenderingContext2D): void {
updateArea(ctx?: CanvasRenderingContext2D): void {
const bounds = this.#boundingRect
this.measure(bounds, ctx)
this.onBounding?.(bounds)

View File

@@ -1235,7 +1235,7 @@ export class ComfyApp {
requestAnimationFrame(() => useLitegraphService().fitView())
}
} else {
requestAnimationFrame(() => useLitegraphService().fitView())
useLitegraphService().fitView()
}
}
} catch (error) {

View File

@@ -868,6 +868,13 @@ export const useLitegraphService = () => {
app.canvas.animateToBounds(graphNode.boundingRect)
}
function ensureBounds(nodes: LGraphNode[]) {
for (const node of nodes) {
if (!node.boundingRect.every((i) => i === 0)) continue
node.updateArea()
}
}
/**
* Resets the canvas view to the default
*/
@@ -881,11 +888,10 @@ export const useLitegraphService = () => {
}
function fitView() {
const canvas = canvasStore.canvas
if (!canvas) return
const canvas = canvasStore.getCanvas()
const nodes = canvas.graph?.nodes
if (!nodes) return
ensureBounds(nodes)
const bounds = createBounds(nodes)
if (!bounds) return