feat(ui): misc canvas perf improvements

- disable listening when not needed
- use useMemo for gridlines
This commit is contained in:
psychedelicious 2023-12-31 00:40:32 +11:00 committed by Kent Keirsey
parent 8d2ef5afc3
commit 2663a07e94
7 changed files with 28 additions and 17 deletions

View File

@ -210,7 +210,7 @@ const IAICanvas = () => {
onWheel={handleWheel} onWheel={handleWheel}
draggable={(tool === 'move' || isStaging) && !isModifyingBoundingBox} draggable={(tool === 'move' || isStaging) && !isModifyingBoundingBox}
> >
<Layer id="grid" visible={shouldShowGrid}> <Layer id="grid" visible={shouldShowGrid} listening={false}>
<IAICanvasGrid /> <IAICanvasGrid />
</Layer> </Layer>
@ -230,17 +230,21 @@ const IAICanvas = () => {
<IAICanvasMaskLines visible={true} listening={false} /> <IAICanvasMaskLines visible={true} listening={false} />
<IAICanvasMaskCompositer listening={false} /> <IAICanvasMaskCompositer listening={false} />
</Layer> </Layer>
<Layer> <Layer listening={false}>
<IAICanvasBoundingBoxOverlay /> <IAICanvasBoundingBoxOverlay />
</Layer> </Layer>
<Layer id="preview" imageSmoothingEnabled={shouldAntialias}> <Layer
id="preview"
listening={false}
imageSmoothingEnabled={shouldAntialias}
>
{!isStaging && ( {!isStaging && (
<IAICanvasToolPreview <IAICanvasToolPreview
visible={tool !== 'move'} visible={tool !== 'move'}
listening={false} listening={false}
/> />
)} )}
<IAICanvasStagingArea visible={isStaging} /> <IAICanvasStagingArea listening={false} visible={isStaging} />
{shouldShowIntermediates && <IAICanvasIntermediateImage />} {shouldShowIntermediates && <IAICanvasIntermediateImage />}
<IAICanvasBoundingBox <IAICanvasBoundingBox
visible={shouldShowBoundingBox && !isStaging} visible={shouldShowBoundingBox && !isStaging}

View File

@ -34,7 +34,7 @@ const IAICanvasBoundingBoxOverlay = () => {
} = useAppSelector(selector); } = useAppSelector(selector);
return ( return (
<Group> <Group listening={false}>
<Rect <Rect
offsetX={stageCoordinates.x / stageScale} offsetX={stageCoordinates.x / stageScale}
offsetY={stageCoordinates.y / stageScale} offsetY={stageCoordinates.y / stageScale}

View File

@ -4,8 +4,7 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { range } from 'lodash-es'; import { range } from 'lodash-es';
import type { ReactNode } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { memo, useCallback, useLayoutEffect, useState } from 'react';
import { Group, Line as KonvaLine } from 'react-konva'; import { Group, Line as KonvaLine } from 'react-konva';
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => { const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
@ -16,7 +15,6 @@ const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
const IAICanvasGrid = () => { const IAICanvasGrid = () => {
const { stageScale, stageCoordinates, stageDimensions } = const { stageScale, stageCoordinates, stageDimensions } =
useAppSelector(selector); useAppSelector(selector);
const [gridLines, setGridLines] = useState<ReactNode[]>([]);
const [gridLineColor] = useToken('colors', ['base.800']); const [gridLineColor] = useToken('colors', ['base.800']);
const unscale = useCallback( const unscale = useCallback(
@ -26,7 +24,7 @@ const IAICanvasGrid = () => {
[stageScale] [stageScale]
); );
useLayoutEffect(() => { const gridLines = useMemo(() => {
const { width, height } = stageDimensions; const { width, height } = stageDimensions;
const { x, y } = stageCoordinates; const { x, y } = stageCoordinates;
@ -77,6 +75,7 @@ const IAICanvasGrid = () => {
points={[0, 0, 0, ySize]} points={[0, 0, 0, ySize]}
stroke={gridLineColor} stroke={gridLineColor}
strokeWidth={1} strokeWidth={1}
listening={false}
/> />
)); ));
const yLines = range(0, ySteps).map((i) => ( const yLines = range(0, ySteps).map((i) => (
@ -87,13 +86,14 @@ const IAICanvasGrid = () => {
points={[0, 0, xSize, 0]} points={[0, 0, xSize, 0]}
stroke={gridLineColor} stroke={gridLineColor}
strokeWidth={1} strokeWidth={1}
listening={false}
/> />
)); ));
setGridLines(xLines.concat(yLines)); return xLines.concat(yLines);
}, [stageScale, stageCoordinates, stageDimensions, unscale, gridLineColor]); }, [stageCoordinates, stageDimensions, unscale, gridLineColor]);
return <Group>{gridLines}</Group>; return <Group listening={false}>{gridLines}</Group>;
}; };
export default memo(IAICanvasGrid); export default memo(IAICanvasGrid);

View File

@ -13,13 +13,14 @@ const IAICanvasImageErrorFallback = ({
const [rectFill, textFill] = useToken('colors', ['base.500', 'base.900']); const [rectFill, textFill] = useToken('colors', ['base.500', 'base.900']);
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Group> <Group listening={false}>
<Rect <Rect
x={canvasImage.x} x={canvasImage.x}
y={canvasImage.y} y={canvasImage.y}
width={canvasImage.width} width={canvasImage.width}
height={canvasImage.height} height={canvasImage.height}
fill={rectFill} fill={rectFill}
listening={false}
/> />
<Text <Text
x={canvasImage.x} x={canvasImage.x}
@ -33,6 +34,7 @@ const IAICanvasImageErrorFallback = ({
fontStyle="600" fontStyle="600"
text={t('common.imageFailedToLoad')} text={t('common.imageFailedToLoad')}
fill={textFill} fill={textFill}
listening={false}
/> />
</Group> </Group>
); );

View File

@ -9,7 +9,7 @@ import { Group, Line } from 'react-konva';
export const canvasLinesSelector = createMemoizedSelector( export const canvasLinesSelector = createMemoizedSelector(
[stateSelector], [stateSelector],
({ canvas }) => { ({ canvas }) => {
return { objects: canvas.layerState.objects }; return canvas.layerState.objects.filter(isCanvasMaskLine);
} }
); );
@ -22,11 +22,11 @@ type InpaintingCanvasLinesProps = GroupConfig;
*/ */
const IAICanvasLines = (props: InpaintingCanvasLinesProps) => { const IAICanvasLines = (props: InpaintingCanvasLinesProps) => {
const { ...rest } = props; const { ...rest } = props;
const { objects } = useAppSelector(canvasLinesSelector); const lines = useAppSelector(canvasLinesSelector);
return ( return (
<Group listening={false} {...rest}> <Group listening={false} {...rest}>
{objects.filter(isCanvasMaskLine).map((line, i) => ( {lines.map((line, i) => (
<Line <Line
key={i} key={i}
points={line.points} points={line.points}

View File

@ -59,6 +59,7 @@ const IAICanvasObjectRenderer = () => {
clipY={obj.clip.y} clipY={obj.clip.y}
clipWidth={obj.clip.width} clipWidth={obj.clip.width}
clipHeight={obj.clip.height} clipHeight={obj.clip.height}
listening={false}
> >
{line} {line}
</Group> </Group>
@ -75,6 +76,7 @@ const IAICanvasObjectRenderer = () => {
width={obj.width} width={obj.width}
height={obj.height} height={obj.height}
fill={rgbaColorToString(obj.color)} fill={rgbaColorToString(obj.color)}
listening={false}
/> />
); );
} else if (isCanvasEraseRect(obj)) { } else if (isCanvasEraseRect(obj)) {
@ -87,6 +89,7 @@ const IAICanvasObjectRenderer = () => {
height={obj.height} height={obj.height}
fill="rgb(255, 255, 255)" fill="rgb(255, 255, 255)"
globalCompositeOperation="destination-out" globalCompositeOperation="destination-out"
listening={false}
/> />
); );
} }

View File

@ -56,7 +56,7 @@ const IAICanvasStagingArea = (props: Props) => {
<IAICanvasImage canvasImage={currentStagingAreaImage} /> <IAICanvasImage canvasImage={currentStagingAreaImage} />
)} )}
{shouldShowStagingOutline && ( {shouldShowStagingOutline && (
<Group> <Group listening={false}>
<Rect <Rect
x={x} x={x}
y={y} y={y}
@ -65,6 +65,7 @@ const IAICanvasStagingArea = (props: Props) => {
strokeWidth={1} strokeWidth={1}
stroke="white" stroke="white"
strokeScaleEnabled={false} strokeScaleEnabled={false}
listening={false}
/> />
<Rect <Rect
x={x} x={x}
@ -75,6 +76,7 @@ const IAICanvasStagingArea = (props: Props) => {
strokeWidth={1} strokeWidth={1}
stroke="black" stroke="black"
strokeScaleEnabled={false} strokeScaleEnabled={false}
listening={false}
/> />
</Group> </Group>
)} )}