From bb70c32ad56439fdfe943cb5d2736e7e66155a5c Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 18 Nov 2022 16:18:07 +1100 Subject: [PATCH] Improves behaviour when setting init canvas image/reset view --- .../IAICanvasToolbar/IAICanvasToolbar.tsx | 1 + .../features/canvas/hooks/useCanvasZoom.ts | 35 +--- .../src/features/canvas/store/canvasSlice.ts | 173 +++++++++++------- .../src/features/gallery/HoverableImage.tsx | 6 +- 4 files changed, 118 insertions(+), 97 deletions(-) diff --git a/frontend/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx b/frontend/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx index f75b2236dc..1ed2195092 100644 --- a/frontend/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx +++ b/frontend/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx @@ -131,6 +131,7 @@ const IAICanvasOutpaintingControls = () => { const handleSelectMoveTool = () => dispatch(setTool('move')); const handleResetCanvasView = () => { + const canvasBaseLayer = getCanvasBaseLayer() if (!canvasBaseLayer) return; const clientRect = canvasBaseLayer.getClientRect({ skipTransform: true, diff --git a/frontend/src/features/canvas/hooks/useCanvasZoom.ts b/frontend/src/features/canvas/hooks/useCanvasZoom.ts index c553a1f5dc..af3284a0ab 100644 --- a/frontend/src/features/canvas/hooks/useCanvasZoom.ts +++ b/frontend/src/features/canvas/hooks/useCanvasZoom.ts @@ -1,14 +1,10 @@ import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store'; -import { activeTabNameSelector } from 'features/options/optionsSelectors'; import Konva from 'konva'; import { KonvaEventObject } from 'konva/lib/Node'; import _ from 'lodash'; import { MutableRefObject, useCallback } from 'react'; -import { - canvasSelector, - initialCanvasImageSelector, -} from 'features/canvas/store/canvasSelectors'; +import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { setStageCoordinates, setStageScale, @@ -20,21 +16,12 @@ import { } from '../util/constants'; const selector = createSelector( - [activeTabNameSelector, canvasSelector, initialCanvasImageSelector], - (activeTabName, canvas, initialCanvasImage) => { - const { - isMoveStageKeyHeld, - stageScale, - stageDimensions, - minimumStageScale, - } = canvas; + [canvasSelector], + (canvas) => { + const { isMoveStageKeyHeld, stageScale } = canvas; return { isMoveStageKeyHeld, stageScale, - activeTabName, - initialCanvasImage, - stageDimensions, - minimumStageScale, }; }, { memoizeOptions: { resultEqualityCheck: _.isEqual } } @@ -42,20 +29,12 @@ const selector = createSelector( const useCanvasWheel = (stageRef: MutableRefObject) => { const dispatch = useAppDispatch(); - const { - isMoveStageKeyHeld, - stageScale, - activeTabName, - initialCanvasImage, - stageDimensions, - minimumStageScale, - } = useAppSelector(selector); + const { isMoveStageKeyHeld, stageScale } = useAppSelector(selector); return useCallback( (e: KonvaEventObject) => { // stop default scrolling - if (!stageRef.current || isMoveStageKeyHeld || !initialCanvasImage) - return; + if (!stageRef.current || isMoveStageKeyHeld) return; e.evt.preventDefault(); @@ -90,7 +69,7 @@ const useCanvasWheel = (stageRef: MutableRefObject) => { dispatch(setStageScale(newScale)); dispatch(setStageCoordinates(newCoordinates)); }, - [stageRef, isMoveStageKeyHeld, initialCanvasImage, stageScale, dispatch] + [stageRef, isMoveStageKeyHeld, stageScale, dispatch] ); }; diff --git a/frontend/src/features/canvas/store/canvasSlice.ts b/frontend/src/features/canvas/store/canvasSlice.ts index ad4496de35..4794c8d32a 100644 --- a/frontend/src/features/canvas/store/canvasSlice.ts +++ b/frontend/src/features/canvas/store/canvasSlice.ts @@ -369,51 +369,6 @@ export const canvasSlice = createSlice({ const initialCanvasImage = state.layerState.objects.find(isCanvasBaseImage); - if (!initialCanvasImage) return; - - const { width: imageWidth, height: imageHeight } = initialCanvasImage; - - const padding = 0.95; - - const newScale = calculateScale( - containerWidth, - containerHeight, - imageWidth, - imageHeight, - padding - ); - - const newDimensions = { - width: Math.floor(containerWidth), - height: Math.floor(containerHeight), - }; - - const newCoordinates = calculateCoordinates( - newDimensions.width, - newDimensions.height, - 0, - 0, - imageWidth, - imageHeight, - newScale - ); - - if (!_.isEqual(state.stageDimensions, newDimensions)) { - state.minimumStageScale = newScale; - state.stageScale = newScale; - state.stageCoordinates = floorCoordinates(newCoordinates); - state.stageDimensions = newDimensions; - } - - state.isCanvasInitialized = true; - }, - resizeCanvas: (state) => { - const { width: containerWidth, height: containerHeight } = - state.canvasContainerDimensions; - - const initialCanvasImage = - state.layerState.objects.find(isCanvasBaseImage); - const newStageDimensions = { width: Math.floor(containerWidth), height: Math.floor(containerHeight), @@ -441,9 +396,72 @@ export const canvasSlice = createSlice({ state.stageScale = newScale; state.stageCoordinates = newCoordinates; + return; } + const { width: imageWidth, height: imageHeight } = initialCanvasImage; + + const padding = 0.95; + + const newScale = calculateScale( + containerWidth, + containerHeight, + imageWidth, + imageHeight, + padding + ); + + const newCoordinates = calculateCoordinates( + newStageDimensions.width, + newStageDimensions.height, + 0, + 0, + imageWidth, + imageHeight, + newScale + ); + + state.minimumStageScale = newScale; + state.stageScale = newScale; + state.stageCoordinates = floorCoordinates(newCoordinates); state.stageDimensions = newStageDimensions; + + state.isCanvasInitialized = true; + }, + resizeCanvas: (state) => { + const { width: containerWidth, height: containerHeight } = + state.canvasContainerDimensions; + + const newStageDimensions = { + width: Math.floor(containerWidth), + height: Math.floor(containerHeight), + }; + + state.stageDimensions = newStageDimensions; + + if (!state.layerState.objects.find(isCanvasBaseImage)) { + const newScale = calculateScale( + newStageDimensions.width, + newStageDimensions.height, + 512, + 512, + STAGE_PADDING_PERCENTAGE + ); + + const newCoordinates = calculateCoordinates( + newStageDimensions.width, + newStageDimensions.height, + 0, + 0, + 512, + 512, + newScale + ); + + state.stageScale = newScale; + + state.stageCoordinates = newCoordinates; + } }, resetCanvasView: ( state, @@ -452,38 +470,57 @@ export const canvasSlice = createSlice({ }> ) => { const { contentRect } = action.payload; - - const baseCanvasImage = state.layerState.objects.find(isCanvasBaseImage); - - if (!baseCanvasImage) return; - const { stageDimensions: { width: stageWidth, height: stageHeight }, } = state; const { x, y, width, height } = contentRect; - const newScale = calculateScale( - stageWidth, - stageHeight, - width, - height, - STAGE_PADDING_PERCENTAGE - ); + if (width !== 0 && height !== 0) { + const newScale = calculateScale( + stageWidth, + stageHeight, + width, + height, + STAGE_PADDING_PERCENTAGE + ); - const newCoordinates = calculateCoordinates( - stageWidth, - stageHeight, - x, - y, - width, - height, - newScale - ); + const newCoordinates = calculateCoordinates( + stageWidth, + stageHeight, + x, + y, + width, + height, + newScale + ); - state.stageScale = newScale; + state.stageScale = newScale; - state.stageCoordinates = newCoordinates; + state.stageCoordinates = newCoordinates; + } else { + const newScale = calculateScale( + stageWidth, + stageHeight, + 512, + 512, + STAGE_PADDING_PERCENTAGE + ); + + const newCoordinates = calculateCoordinates( + stageWidth, + stageHeight, + 0, + 0, + 512, + 512, + newScale + ); + + state.stageScale = newScale; + + state.stageCoordinates = newCoordinates; + } }, nextStagingAreaImage: (state) => { const currentIndex = state.layerState.stagingArea.selectedImageIndex; diff --git a/frontend/src/features/gallery/HoverableImage.tsx b/frontend/src/features/gallery/HoverableImage.tsx index ddf66448a0..de09fd8f58 100644 --- a/frontend/src/features/gallery/HoverableImage.tsx +++ b/frontend/src/features/gallery/HoverableImage.tsx @@ -23,10 +23,13 @@ import { import * as InvokeAI from 'app/invokeai'; import * as ContextMenu from '@radix-ui/react-context-menu'; import { + resetCanvasView, + resizeAndScaleCanvas, setDoesCanvasNeedScaling, setInitialCanvasImage, } from 'features/canvas/store/canvasSlice'; import { hoverableImageSelector } from './gallerySliceSelectors'; +import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider'; interface HoverableImageProps { image: InvokeAI.Image; @@ -99,7 +102,8 @@ const HoverableImage = memo((props: HoverableImageProps) => { if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false)); dispatch(setInitialCanvasImage(image)); - dispatch(setDoesCanvasNeedScaling(true)); + + dispatch(resizeAndScaleCanvas()); if (activeTabName !== 'unifiedCanvas') { dispatch(setActiveTab('unifiedCanvas'));