From 98d0863849882518fd8a12d037a11d5bc463972e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 23:38:38 +0000 Subject: [PATCH 1/3] Initial plan From ab5dd00e5294cde83b7d524a52d31159172e37cd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 23:45:11 +0000 Subject: [PATCH 2/3] perf: throttle stage drag sync and reuse background grid lines Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com> --- .../konva/CanvasBackgroundModule.ts | 42 +++++++++++++------ .../controlLayers/konva/CanvasStageModule.ts | 7 +++- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasBackgroundModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasBackgroundModule.ts index b700392c05f..e7c9116ec61 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasBackgroundModule.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasBackgroundModule.ts @@ -161,36 +161,54 @@ export class CanvasBackgroundModule extends CanvasModuleBase { let _x = 0; let _y = 0; - this.konva.linesGroup.destroyChildren(); - this.konva.lines = []; + const totalLines = xSteps + ySteps; + while (this.konva.lines.length > totalLines) { + this.konva.lines.pop()?.destroy(); + } + + let lineIndex = 0; for (let i = 0; i < xSteps; i++) { _x = gridFullRect.x1 + i * gridSpacing; - const line = new Konva.Line({ + const line = + this.konva.lines[lineIndex] ?? + new Konva.Line({ + listening: false, + perfectDrawEnabled: false, + }); + line.setAttrs({ x: _x, y: gridFullRect.y1, points: [0, 0, 0, ySize], stroke: _x % 64 ? this.config.GRID_LINE_COLOR_FINE : this.config.GRID_LINE_COLOR_COARSE, strokeWidth, - listening: false, - perfectDrawEnabled: false, }); - this.konva.lines.push(line); - this.konva.linesGroup.add(line); + this.konva.lines[lineIndex] = line; + if (line.getParent() !== this.konva.linesGroup) { + this.konva.linesGroup.add(line); + } + lineIndex += 1; } for (let i = 0; i < ySteps; i++) { _y = gridFullRect.y1 + i * gridSpacing; - const line = new Konva.Line({ + const line = + this.konva.lines[lineIndex] ?? + new Konva.Line({ + listening: false, + perfectDrawEnabled: false, + }); + line.setAttrs({ x: gridFullRect.x1, y: _y, points: [0, 0, xSize, 0], stroke: _y % 64 ? this.config.GRID_LINE_COLOR_FINE : this.config.GRID_LINE_COLOR_COARSE, strokeWidth, - listening: false, - perfectDrawEnabled: false, }); - this.konva.lines.push(line); - this.konva.linesGroup.add(line); + this.konva.lines[lineIndex] = line; + if (line.getParent() !== this.konva.linesGroup) { + this.konva.linesGroup.add(line); + } + lineIndex += 1; } }; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts index b205d724555..9279d65fd7a 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts @@ -7,6 +7,7 @@ import type { Coordinate, Dimensions, Rect, StageAttrs } from 'features/controlL import Konva from 'konva'; import type { KonvaEventObject } from 'konva/lib/Node'; import { atom, computed } from 'nanostores'; +import rafThrottle from 'raf-throttle'; import type { Logger } from 'roarr'; type CanvasStageModuleConfig = { @@ -488,9 +489,13 @@ export class CanvasStageModule extends CanvasModuleBase { return; } - this.syncStageAttrs(); + this.syncStageAttrsThrottled(); }; + syncStageAttrsThrottled = rafThrottle(() => { + this.syncStageAttrs(); + }); + onStageDragEnd = (e: KonvaEventObject) => { if (e.target !== this.konva.stage) { return; From 76eddb60ead5c264ceb2572fe968c36d176cfb65 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 23:48:39 +0000 Subject: [PATCH 3/3] perf: cleanup throttled stage sync and optimize grid line trimming Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com> --- .../features/controlLayers/konva/CanvasBackgroundModule.ts | 4 +--- .../web/src/features/controlLayers/konva/CanvasStageModule.ts | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasBackgroundModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasBackgroundModule.ts index e7c9116ec61..cbc964cd292 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasBackgroundModule.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasBackgroundModule.ts @@ -163,9 +163,7 @@ export class CanvasBackgroundModule extends CanvasModuleBase { const totalLines = xSteps + ySteps; - while (this.konva.lines.length > totalLines) { - this.konva.lines.pop()?.destroy(); - } + this.konva.lines.splice(totalLines).forEach((line) => line.destroy()); let lineIndex = 0; for (let i = 0; i < xSteps; i++) { diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts index 9279d65fd7a..e28f17be47e 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts @@ -597,6 +597,7 @@ export class CanvasStageModule extends CanvasModuleBase { destroy = () => { this.log.debug('Destroying module'); + this.syncStageAttrsThrottled.cancel(); this.subscriptions.forEach((unsubscribe) => unsubscribe()); this.subscriptions.clear(); if (this.resizeObserver) {