feat(ui): canvas perf improvements

This commit is contained in:
psychedelicious 2023-12-31 13:46:20 +11:00 committed by Kent Keirsey
parent e108a2302e
commit 6f354f16ba
6 changed files with 36 additions and 61 deletions

View File

@ -21,12 +21,11 @@ type InpaintingCanvasLinesProps = GroupConfig;
* Uses globalCompositeOperation to handle the brush and eraser tools. * Uses globalCompositeOperation to handle the brush and eraser tools.
*/ */
const IAICanvasLines = (props: InpaintingCanvasLinesProps) => { const IAICanvasLines = (props: InpaintingCanvasLinesProps) => {
const { ...rest } = props; const objects = useAppSelector((state) => state.canvas.layerState.objects);
const lines = useAppSelector(canvasLinesSelector);
return ( return (
<Group listening={false} {...rest}> <Group listening={false} {...props}>
{lines.map((line, i) => ( {objects.filter(isCanvasMaskLine).map((line, i) => (
<Line <Line
key={i} key={i}
points={line.points} points={line.points}

View File

@ -1,5 +1,3 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { import {
isCanvasBaseImage, isCanvasBaseImage,
@ -13,21 +11,8 @@ import { Group, Line, Rect } from 'react-konva';
import IAICanvasImage from './IAICanvasImage'; import IAICanvasImage from './IAICanvasImage';
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
const {
layerState: { objects },
} = canvas;
return {
objects,
};
});
const IAICanvasObjectRenderer = () => { const IAICanvasObjectRenderer = () => {
const { objects } = useAppSelector(selector); const objects = useAppSelector((state) => state.canvas.layerState.objects);
if (!objects) {
return null;
}
return ( return (
<Group name="outpainting-objects" listening={false}> <Group name="outpainting-objects" listening={false}>

View File

@ -39,7 +39,6 @@ const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
type Props = GroupConfig; type Props = GroupConfig;
const IAICanvasStagingArea = (props: Props) => { const IAICanvasStagingArea = (props: Props) => {
const { ...rest } = props;
const { const {
currentStagingAreaImage, currentStagingAreaImage,
shouldShowStagingImage, shouldShowStagingImage,
@ -51,7 +50,7 @@ const IAICanvasStagingArea = (props: Props) => {
} = useAppSelector(selector); } = useAppSelector(selector);
return ( return (
<Group {...rest}> <Group {...props}>
{shouldShowStagingImage && currentStagingAreaImage && ( {shouldShowStagingImage && currentStagingAreaImage && (
<IAICanvasImage canvasImage={currentStagingAreaImage} /> <IAICanvasImage canvasImage={currentStagingAreaImage} />
)} )}

View File

@ -110,7 +110,6 @@ const canvasBrushPreviewSelector = createMemoizedSelector(
* Draws a black circle around the canvas brush preview. * Draws a black circle around the canvas brush preview.
*/ */
const IAICanvasToolPreview = (props: GroupConfig) => { const IAICanvasToolPreview = (props: GroupConfig) => {
const { ...rest } = props;
const { const {
brushX, brushX,
brushY, brushY,
@ -133,7 +132,7 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
} }
return ( return (
<Group listening={false} {...clip} {...rest}> <Group listening={false} {...clip} {...props}>
{tool === 'colorPicker' ? ( {tool === 'colorPicker' ? (
<> <>
<Circle <Circle
@ -143,6 +142,7 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
stroke={brushColorString} stroke={brushColorString}
strokeWidth={COLOR_PICKER_STROKE_RADIUS} strokeWidth={COLOR_PICKER_STROKE_RADIUS}
strokeScaleEnabled={false} strokeScaleEnabled={false}
listening={false}
/> />
<Circle <Circle
x={brushX} x={brushX}
@ -151,6 +151,7 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
stroke={colorPickerColorString} stroke={colorPickerColorString}
strokeWidth={COLOR_PICKER_STROKE_RADIUS} strokeWidth={COLOR_PICKER_STROKE_RADIUS}
strokeScaleEnabled={false} strokeScaleEnabled={false}
listening={false}
/> />
</> </>
) : ( ) : (
@ -163,6 +164,7 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
globalCompositeOperation={ globalCompositeOperation={
tool === 'eraser' ? 'destination-out' : 'source-out' tool === 'eraser' ? 'destination-out' : 'source-out'
} }
listening={false}
/> />
<Circle <Circle
x={brushX} x={brushX}

View File

@ -125,7 +125,7 @@ const IAICanvasMaskOptions = () => {
); );
return ( return (
<InvPopover> <InvPopover isLazy>
<InvPopoverTrigger> <InvPopoverTrigger>
<InvIconButton <InvIconButton
aria-label={t('unifiedCanvas.maskingOptions')} aria-label={t('unifiedCanvas.maskingOptions')}

View File

@ -1,5 +1,3 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { import {
@ -9,50 +7,42 @@ import {
import type { KonvaEventObject } from 'konva/lib/Node'; import type { KonvaEventObject } from 'konva/lib/Node';
import { useCallback } from 'react'; import { useCallback } from 'react';
const selector = createMemoizedSelector(
[stateSelector, isStagingSelector],
({ canvas }, isStaging) => {
const { tool, isMovingBoundingBox } = canvas;
return {
tool,
isStaging,
isMovingBoundingBox,
};
}
);
const useCanvasDrag = () => { const useCanvasDrag = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { tool, isStaging, isMovingBoundingBox } = useAppSelector(selector); const tool = useAppSelector((state) => state.canvas.tool);
const isMovingBoundingBox = useAppSelector(
(state) => state.canvas.isMovingBoundingBox
);
const isStaging = useAppSelector(isStagingSelector);
return { const handleDragStart = useCallback(() => {
handleDragStart: useCallback(() => { if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
return;
}
dispatch(setIsMovingStage(true));
}, [dispatch, isMovingBoundingBox, isStaging, tool]);
const handleDragMove = useCallback(
(e: KonvaEventObject<MouseEvent>) => {
if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) { if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
return; return;
} }
dispatch(setIsMovingStage(true));
}, [dispatch, isMovingBoundingBox, isStaging, tool]),
handleDragMove: useCallback( const newCoordinates = { x: e.target.x(), y: e.target.y() };
(e: KonvaEventObject<MouseEvent>) => {
if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
return;
}
const newCoordinates = { x: e.target.x(), y: e.target.y() }; dispatch(setStageCoordinates(newCoordinates));
},
[dispatch, isMovingBoundingBox, isStaging, tool]
);
dispatch(setStageCoordinates(newCoordinates)); const handleDragEnd = useCallback(() => {
}, if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
[dispatch, isMovingBoundingBox, isStaging, tool] return;
), }
dispatch(setIsMovingStage(false));
}, [dispatch, isMovingBoundingBox, isStaging, tool]);
handleDragEnd: useCallback(() => { return { handleDragStart, handleDragMove, handleDragEnd };
if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
return;
}
dispatch(setIsMovingStage(false));
}, [dispatch, isMovingBoundingBox, isStaging, tool]),
};
}; };
export default useCanvasDrag; export default useCanvasDrag;