From 68ccd683ade54c5030db30a01691d3796582b9d3 Mon Sep 17 00:00:00 2001 From: AustinMroz Date: Fri, 19 Dec 2025 20:03:52 -0800 Subject: [PATCH] Do not delay fit to view on graph restore (#7645) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 | | ------ | ----- | | before | after| 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) --- src/lib/litegraph/src/LGraphNode.ts | 12 +++++++----- src/scripts/app.ts | 2 +- src/services/litegraphService.ts | 12 +++++++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/lib/litegraph/src/LGraphNode.ts b/src/lib/litegraph/src/LGraphNode.ts index d5a2f1aa8..036bc5660 100644 --- a/src/lib/litegraph/src/LGraphNode.ts +++ b/src/lib/litegraph/src/LGraphNode.ts @@ -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) diff --git a/src/scripts/app.ts b/src/scripts/app.ts index d7b1e3a4a..f2fd59b3d 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -1235,7 +1235,7 @@ export class ComfyApp { requestAnimationFrame(() => useLitegraphService().fitView()) } } else { - requestAnimationFrame(() => useLitegraphService().fitView()) + useLitegraphService().fitView() } } } catch (error) { diff --git a/src/services/litegraphService.ts b/src/services/litegraphService.ts index a64a77add..e7e35458a 100644 --- a/src/services/litegraphService.ts +++ b/src/services/litegraphService.ts @@ -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