From c8d9e88e2b534fafe461276c74a4d7c32cb63c45 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Sat, 20 Dec 2025 12:37:39 -0800 Subject: [PATCH] [backport cloud/1.35] Do not delay fit to view on graph restore (#7677) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of #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. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7677-backport-cloud-1-35-Do-not-delay-fit-to-view-on-graph-restore-2cf6d73d365081b390b3ed6be968a12b) by [Unito](https://www.unito.io) Co-authored-by: AustinMroz --- src/lib/litegraph/src/LGraphNode.ts | 12 +++++++----- src/scripts/app.ts | 7 +------ src/services/litegraphService.ts | 12 +++++++++--- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/lib/litegraph/src/LGraphNode.ts b/src/lib/litegraph/src/LGraphNode.ts index f87c1ceae..69ebf7c23 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 3a953e963..65b5edda4 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -1224,12 +1224,7 @@ export class ComfyApp { this.canvas.ds.offset = graphData.extra.ds.offset this.canvas.ds.scale = graphData.extra.ds.scale } else { - // @note: Set view after the graph has been rendered once. fitView uses - // boundingRect on nodes to calculate the view bounds, which only become - // available after the first render. - 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