Skip to content

Commit 68a231a

Browse files
psychedelicioushipsterusername
authored andcommitted
feat(ui): move canvas stage and base layer to nanostores
1 parent 21ab650 commit 68a231a

File tree

11 files changed

+67
-94
lines changed

11 files changed

+67
-94
lines changed

invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { $logger } from 'app/logging/logger';
22
import { canvasMerged } from 'features/canvas/store/actions';
3+
import { $canvasBaseLayer } from 'features/canvas/store/canvasNanostore';
34
import { setMergedCanvas } from 'features/canvas/store/canvasSlice';
45
import { getFullBaseLayerBlob } from 'features/canvas/util/getFullBaseLayerBlob';
5-
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
66
import { addToast } from 'features/system/store/systemSlice';
77
import { t } from 'i18next';
88
import { imagesApi } from 'services/api/endpoints/images';
@@ -30,7 +30,7 @@ export const addCanvasMergedListener = () => {
3030
return;
3131
}
3232

33-
const canvasBaseLayer = getCanvasBaseLayer();
33+
const canvasBaseLayer = $canvasBaseLayer.get();
3434

3535
if (!canvasBaseLayer) {
3636
moduleLog.error('Problem getting canvas base layer');

invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,16 @@ import useCanvasMouseOut from 'features/canvas/hooks/useCanvasMouseOut';
1010
import useCanvasMouseUp from 'features/canvas/hooks/useCanvasMouseUp';
1111
import useCanvasWheel from 'features/canvas/hooks/useCanvasZoom';
1212
import {
13-
$isModifyingBoundingBox,
13+
$canvasBaseLayer, $canvasStage,$isModifyingBoundingBox,
1414
$isMouseOverBoundingBox,
1515
$isMovingStage,
1616
$isTransformingBoundingBox,
17-
$tool,
18-
} from 'features/canvas/store/canvasNanostore';
17+
$tool } from 'features/canvas/store/canvasNanostore';
1918
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
2019
import {
2120
canvasResized,
2221
selectCanvasSlice,
2322
} from 'features/canvas/store/canvasSlice';
24-
import {
25-
setCanvasBaseLayer,
26-
setCanvasStage,
27-
} from 'features/canvas/util/konvaInstanceProvider';
2823
import type Konva from 'konva';
2924
import type { KonvaEventObject } from 'konva/lib/Node';
3025
import type { Vector2d } from 'konva/lib/types';
@@ -80,9 +75,9 @@ const IAICanvas = () => {
8075
const isMouseOverBoundingBox = useStore($isMouseOverBoundingBox);
8176
const tool = useStore($tool);
8277
useCanvasHotkeys();
83-
const canvasStageRefCallback = useCallback((el: Konva.Stage) => {
84-
setCanvasStage(el as Konva.Stage);
85-
stageRef.current = el;
78+
const canvasStageRefCallback = useCallback((stageElement: Konva.Stage) => {
79+
$canvasStage.set(stageElement);
80+
stageRef.current = stageElement;
8681
}, []);
8782
const stageCursor = useMemo(() => {
8883
if (tool === 'move' || isStaging) {
@@ -105,10 +100,14 @@ const IAICanvas = () => {
105100
shouldRestrictStrokesToBox,
106101
tool,
107102
]);
108-
const canvasBaseLayerRefCallback = useCallback((el: Konva.Layer) => {
109-
setCanvasBaseLayer(el as Konva.Layer);
110-
canvasBaseLayerRef.current = el;
111-
}, []);
103+
104+
const canvasBaseLayerRefCallback = useCallback(
105+
(layerElement: Konva.Layer) => {
106+
$canvasBaseLayer.set(layerElement);
107+
canvasBaseLayerRef.current = layerElement;
108+
},
109+
[]
110+
);
112111

113112
const lastCursorPositionRef = useRef<Vector2d>({ x: 0, y: 0 });
114113

invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
$cursorPosition,
66
$isMovingBoundingBox,
77
$isTransformingBoundingBox,
8+
$tool,
89
} from 'features/canvas/store/canvasNanostore';
910
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
1011
import { rgbaColorToString } from 'features/canvas/util/colorToString';
@@ -89,7 +90,7 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
8990
const maskColorString = useAppSelector((s) =>
9091
rgbaColorToString({ ...s.canvas.maskColor, a: 0.5 })
9192
);
92-
const tool = useAppSelector((s) => s.canvas.tool);
93+
const tool = useStore($tool);
9394
const layer = useAppSelector((s) => s.canvas.layer);
9495
const dotRadius = useAppSelector((s) => 1.5 / s.canvas.stageScale);
9596
const strokeWidth = useAppSelector((s) => 1.5 / s.canvas.stageScale);

invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
canvasMerged,
1616
canvasSavedToGallery,
1717
} from 'features/canvas/store/actions';
18-
import { $tool } from 'features/canvas/store/canvasNanostore';
18+
import { $canvasBaseLayer,$tool } from 'features/canvas/store/canvasNanostore';
1919
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
2020
import {
2121
resetCanvas,
@@ -25,7 +25,6 @@ import {
2525
} from 'features/canvas/store/canvasSlice';
2626
import type { CanvasLayer } from 'features/canvas/store/canvasTypes';
2727
import { LAYER_NAMES_DICT } from 'features/canvas/store/canvasTypes';
28-
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
2928
import { InvIconButton } from 'index';
3029
import { memo, useCallback, useMemo } from 'react';
3130
import { useHotkeys } from 'react-hotkeys-hook';
@@ -53,7 +52,6 @@ const IAICanvasToolbar = () => {
5352
const layer = useAppSelector((s) => s.canvas.layer);
5453
const tool = useStore($tool);
5554
const isStaging = useAppSelector(isStagingSelector);
56-
const canvasBaseLayer = getCanvasBaseLayer();
5755
const { t } = useTranslation();
5856
const { isClipboardAPIAvailable } = useCopyImageToClipboard();
5957

@@ -82,7 +80,7 @@ const IAICanvasToolbar = () => {
8280
enabled: () => true,
8381
preventDefault: true,
8482
},
85-
[canvasBaseLayer]
83+
[]
8684
);
8785

8886
useHotkeys(
@@ -94,7 +92,7 @@ const IAICanvasToolbar = () => {
9492
enabled: () => !isStaging,
9593
preventDefault: true,
9694
},
97-
[canvasBaseLayer]
95+
[]
9896
);
9997

10098
useHotkeys(
@@ -106,7 +104,7 @@ const IAICanvasToolbar = () => {
106104
enabled: () => !isStaging,
107105
preventDefault: true,
108106
},
109-
[canvasBaseLayer]
107+
[]
110108
);
111109

112110
useHotkeys(
@@ -118,7 +116,7 @@ const IAICanvasToolbar = () => {
118116
enabled: () => !isStaging && isClipboardAPIAvailable,
119117
preventDefault: true,
120118
},
121-
[canvasBaseLayer, isClipboardAPIAvailable]
119+
[isClipboardAPIAvailable]
122120
);
123121

124122
useHotkeys(
@@ -130,7 +128,7 @@ const IAICanvasToolbar = () => {
130128
enabled: () => !isStaging,
131129
preventDefault: true,
132130
},
133-
[canvasBaseLayer]
131+
[]
134132
);
135133

136134
const handleSelectMoveTool = useCallback(() => {
@@ -143,7 +141,7 @@ const IAICanvasToolbar = () => {
143141
);
144142

145143
const handleResetCanvasView = (shouldScaleTo1 = false) => {
146-
const canvasBaseLayer = getCanvasBaseLayer();
144+
const canvasBaseLayer = $canvasBaseLayer.get();
147145
if (!canvasBaseLayer) {
148146
return;
149147
}

invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
22
import {
3-
$tool,
3+
$canvasStage, $tool,
44
$toolStash,
55
resetCanvasInteractionState,
6-
resetToolInteractionState,
7-
} from 'features/canvas/store/canvasNanostore';
6+
resetToolInteractionState } from 'features/canvas/store/canvasNanostore';
87
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
98
import {
109
clearMask,
1110
setIsMaskEnabled,
1211
setShouldShowBoundingBox,
1312
setShouldSnapToGrid,
1413
} from 'features/canvas/store/canvasSlice';
15-
import { getCanvasStage } from 'features/canvas/util/konvaInstanceProvider';
1614
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
1715
import { useCallback, useEffect } from 'react';
1816
import { useHotkeys } from 'react-hotkeys-hook';
@@ -26,7 +24,6 @@ const useInpaintingCanvasHotkeys = () => {
2624
const isStaging = useAppSelector(isStagingSelector);
2725
const isMaskEnabled = useAppSelector((s) => s.canvas.isMaskEnabled);
2826
const shouldSnapToGrid = useAppSelector((s) => s.canvas.shouldSnapToGrid);
29-
const canvasStage = getCanvasStage();
3027

3128
// Beta Keys
3229
const handleClearMask = useCallback(() => dispatch(clearMask()), [dispatch]);
@@ -102,35 +99,29 @@ const useInpaintingCanvasHotkeys = () => {
10299
});
103100
}, []);
104101

105-
const onKeyDown = useCallback(
106-
(e: KeyboardEvent) => {
107-
if (e.repeat || e.key !== ' ') {
108-
return;
109-
}
110-
if ($toolStash.get() || $tool.get() === 'move') {
111-
return;
112-
}
113-
canvasStage?.container().focus();
114-
$toolStash.set($tool.get());
115-
$tool.set('move');
116-
resetToolInteractionState();
117-
},
118-
[canvasStage]
119-
);
120-
const onKeyUp = useCallback(
121-
(e: KeyboardEvent) => {
122-
if (e.repeat || e.key !== ' ') {
123-
return;
124-
}
125-
if (!$toolStash.get() || $tool.get() !== 'move') {
126-
return;
127-
}
128-
canvasStage?.container().focus();
129-
$tool.set($toolStash.get() ?? 'move');
130-
$toolStash.set(null);
131-
},
132-
[canvasStage]
133-
);
102+
const onKeyDown = useCallback((e: KeyboardEvent) => {
103+
if (e.repeat || e.key !== ' ') {
104+
return;
105+
}
106+
if ($toolStash.get() || $tool.get() === 'move') {
107+
return;
108+
}
109+
$canvasStage.get()?.container().focus();
110+
$toolStash.set($tool.get());
111+
$tool.set('move');
112+
resetToolInteractionState();
113+
}, []);
114+
const onKeyUp = useCallback((e: KeyboardEvent) => {
115+
if (e.repeat || e.key !== ' ') {
116+
return;
117+
}
118+
if (!$toolStash.get() || $tool.get() !== 'move') {
119+
return;
120+
}
121+
$canvasStage.get()?.container().focus();
122+
$tool.set($toolStash.get() ?? 'move');
123+
$toolStash.set(null);
124+
}, []);
134125

135126
useEffect(() => {
136127
window.addEventListener('keydown', onKeyDown);

invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
import { useAppDispatch } from 'app/store/storeHooks';
2-
import { $tool } from 'features/canvas/store/canvasNanostore';
2+
import { $canvasBaseLayer,$canvasStage,$tool } from 'features/canvas/store/canvasNanostore';
33
import {
44
commitColorPickerColor,
55
setColorPickerColor,
66
} from 'features/canvas/store/canvasSlice';
7-
import {
8-
getCanvasBaseLayer,
9-
getCanvasStage,
10-
} from 'features/canvas/util/konvaInstanceProvider';
117
import Konva from 'konva';
128
import { useCallback } from 'react';
139

1410
const useColorPicker = () => {
1511
const dispatch = useAppDispatch();
16-
const canvasBaseLayer = getCanvasBaseLayer();
17-
const stage = getCanvasStage();
1812

1913
const updateColorUnderCursor = useCallback(() => {
14+
const stage = $canvasStage.get();
15+
const canvasBaseLayer = $canvasBaseLayer.get();
2016
if (!stage || !canvasBaseLayer) {
2117
return;
2218
}
@@ -48,11 +44,11 @@ const useColorPicker = () => {
4844
}
4945

5046
dispatch(setColorPickerColor({ r, g, b, a }));
51-
}, [canvasBaseLayer, dispatch, stage]);
47+
}, [dispatch]);
5248

5349
const commitColorUnderCursor = useCallback(() => {
5450
dispatch(commitColorPickerColor());
55-
$tool.set('brush')
51+
$tool.set('brush');
5652
}, [dispatch]);
5753

5854
return { updateColorUnderCursor, commitColorUnderCursor };

invokeai/frontend/web/src/features/canvas/store/canvasNanostore.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { CanvasTool } from 'features/canvas/store/canvasTypes';
2+
import type Konva from "konva";
23
import type { Vector2d } from 'konva/lib/types';
34
import { atom, computed } from 'nanostores';
45

@@ -38,4 +39,6 @@ export const resetToolInteractionState = () => {
3839

3940
export const setCanvasInteractionStateMouseOut = () => {
4041
$cursorPosition.set(null);
41-
};
42+
};export const $canvasBaseLayer = atom<Konva.Layer | null>(null);
43+
export const $canvasStage = atom<Konva.Stage | null>(null);
44+

invokeai/frontend/web/src/features/canvas/util/getBaseLayerBlob.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { RootState } from 'app/store/store';
2+
import { $canvasBaseLayer } from 'features/canvas/store/canvasNanostore';
23

3-
import { getCanvasBaseLayer } from './konvaInstanceProvider';
44
import { konvaNodeToBlob } from './konvaNodeToBlob';
55

66
/**
@@ -10,7 +10,7 @@ export const getBaseLayerBlob = async (
1010
state: RootState,
1111
alwaysUseBoundingBox: boolean = false
1212
) => {
13-
const canvasBaseLayer = getCanvasBaseLayer();
13+
const canvasBaseLayer = $canvasBaseLayer.get();
1414

1515
if (!canvasBaseLayer) {
1616
throw new Error('Problem getting base layer blob');

invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { logger } from 'app/logging/logger';
2+
import { $canvasBaseLayer , $canvasStage } from 'features/canvas/store/canvasNanostore';
23
import type {
34
CanvasLayerState,
45
Dimensions,
56
} from 'features/canvas/store/canvasTypes';
67
import { isCanvasMaskLine } from 'features/canvas/store/canvasTypes';
8+
import { konvaNodeToImageData } from 'features/canvas/util/konvaNodeToImageData';
79
import type { Vector2d } from 'konva/lib/types';
810

911
import createMaskStage from './createMaskStage';
10-
import { getCanvasBaseLayer, getCanvasStage } from './konvaInstanceProvider';
1112
import { konvaNodeToBlob } from './konvaNodeToBlob';
12-
import { konvaNodeToImageData } from './konvaNodeToImageData';
1313

1414
/**
1515
* Gets Blob and ImageData objects for the base and mask layers
@@ -23,8 +23,8 @@ export const getCanvasData = async (
2323
) => {
2424
const log = logger('canvas');
2525

26-
const canvasBaseLayer = getCanvasBaseLayer();
27-
const canvasStage = getCanvasStage();
26+
const canvasBaseLayer = $canvasBaseLayer.get();
27+
const canvasStage = $canvasStage.get();
2828

2929
if (!canvasBaseLayer || !canvasStage) {
3030
log.error('Unable to find canvas / stage');

invokeai/frontend/web/src/features/canvas/util/getFullBaseLayerBlob.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { getCanvasBaseLayer } from './konvaInstanceProvider';
1+
import { $canvasBaseLayer } from 'features/canvas/store/canvasNanostore';
2+
23
import { konvaNodeToBlob } from './konvaNodeToBlob';
34

45
/**
56
* Gets the canvas base layer blob, without bounding box
67
*/
78
export const getFullBaseLayerBlob = async () => {
8-
const canvasBaseLayer = getCanvasBaseLayer();
9+
const canvasBaseLayer = $canvasBaseLayer.get();
910

1011
if (!canvasBaseLayer) {
1112
return;

0 commit comments

Comments
 (0)