Improves behaviour when setting init canvas image/reset view

This commit is contained in:
psychedelicious 2022-11-18 16:18:07 +11:00 committed by blessedcoolant
parent 425a1713ab
commit bb70c32ad5
4 changed files with 118 additions and 97 deletions

View File

@ -131,6 +131,7 @@ const IAICanvasOutpaintingControls = () => {
const handleSelectMoveTool = () => dispatch(setTool('move')); const handleSelectMoveTool = () => dispatch(setTool('move'));
const handleResetCanvasView = () => { const handleResetCanvasView = () => {
const canvasBaseLayer = getCanvasBaseLayer()
if (!canvasBaseLayer) return; if (!canvasBaseLayer) return;
const clientRect = canvasBaseLayer.getClientRect({ const clientRect = canvasBaseLayer.getClientRect({
skipTransform: true, skipTransform: true,

View File

@ -1,14 +1,10 @@
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store'; import { useAppDispatch, useAppSelector } from 'app/store';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import Konva from 'konva'; import Konva from 'konva';
import { KonvaEventObject } from 'konva/lib/Node'; import { KonvaEventObject } from 'konva/lib/Node';
import _ from 'lodash'; import _ from 'lodash';
import { MutableRefObject, useCallback } from 'react'; import { MutableRefObject, useCallback } from 'react';
import { import { canvasSelector } from 'features/canvas/store/canvasSelectors';
canvasSelector,
initialCanvasImageSelector,
} from 'features/canvas/store/canvasSelectors';
import { import {
setStageCoordinates, setStageCoordinates,
setStageScale, setStageScale,
@ -20,21 +16,12 @@ import {
} from '../util/constants'; } from '../util/constants';
const selector = createSelector( const selector = createSelector(
[activeTabNameSelector, canvasSelector, initialCanvasImageSelector], [canvasSelector],
(activeTabName, canvas, initialCanvasImage) => { (canvas) => {
const { const { isMoveStageKeyHeld, stageScale } = canvas;
isMoveStageKeyHeld,
stageScale,
stageDimensions,
minimumStageScale,
} = canvas;
return { return {
isMoveStageKeyHeld, isMoveStageKeyHeld,
stageScale, stageScale,
activeTabName,
initialCanvasImage,
stageDimensions,
minimumStageScale,
}; };
}, },
{ memoizeOptions: { resultEqualityCheck: _.isEqual } } { memoizeOptions: { resultEqualityCheck: _.isEqual } }
@ -42,20 +29,12 @@ const selector = createSelector(
const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => { const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { const { isMoveStageKeyHeld, stageScale } = useAppSelector(selector);
isMoveStageKeyHeld,
stageScale,
activeTabName,
initialCanvasImage,
stageDimensions,
minimumStageScale,
} = useAppSelector(selector);
return useCallback( return useCallback(
(e: KonvaEventObject<WheelEvent>) => { (e: KonvaEventObject<WheelEvent>) => {
// stop default scrolling // stop default scrolling
if (!stageRef.current || isMoveStageKeyHeld || !initialCanvasImage) if (!stageRef.current || isMoveStageKeyHeld) return;
return;
e.evt.preventDefault(); e.evt.preventDefault();
@ -90,7 +69,7 @@ const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
dispatch(setStageScale(newScale)); dispatch(setStageScale(newScale));
dispatch(setStageCoordinates(newCoordinates)); dispatch(setStageCoordinates(newCoordinates));
}, },
[stageRef, isMoveStageKeyHeld, initialCanvasImage, stageScale, dispatch] [stageRef, isMoveStageKeyHeld, stageScale, dispatch]
); );
}; };

View File

@ -369,51 +369,6 @@ export const canvasSlice = createSlice({
const initialCanvasImage = const initialCanvasImage =
state.layerState.objects.find(isCanvasBaseImage); 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 = { const newStageDimensions = {
width: Math.floor(containerWidth), width: Math.floor(containerWidth),
height: Math.floor(containerHeight), height: Math.floor(containerHeight),
@ -441,9 +396,72 @@ export const canvasSlice = createSlice({
state.stageScale = newScale; state.stageScale = newScale;
state.stageCoordinates = newCoordinates; 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.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: ( resetCanvasView: (
state, state,
@ -452,38 +470,57 @@ export const canvasSlice = createSlice({
}> }>
) => { ) => {
const { contentRect } = action.payload; const { contentRect } = action.payload;
const baseCanvasImage = state.layerState.objects.find(isCanvasBaseImage);
if (!baseCanvasImage) return;
const { const {
stageDimensions: { width: stageWidth, height: stageHeight }, stageDimensions: { width: stageWidth, height: stageHeight },
} = state; } = state;
const { x, y, width, height } = contentRect; const { x, y, width, height } = contentRect;
const newScale = calculateScale( if (width !== 0 && height !== 0) {
stageWidth, const newScale = calculateScale(
stageHeight, stageWidth,
width, stageHeight,
height, width,
STAGE_PADDING_PERCENTAGE height,
); STAGE_PADDING_PERCENTAGE
);
const newCoordinates = calculateCoordinates( const newCoordinates = calculateCoordinates(
stageWidth, stageWidth,
stageHeight, stageHeight,
x, x,
y, y,
width, width,
height, height,
newScale 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) => { nextStagingAreaImage: (state) => {
const currentIndex = state.layerState.stagingArea.selectedImageIndex; const currentIndex = state.layerState.stagingArea.selectedImageIndex;

View File

@ -23,10 +23,13 @@ import {
import * as InvokeAI from 'app/invokeai'; import * as InvokeAI from 'app/invokeai';
import * as ContextMenu from '@radix-ui/react-context-menu'; import * as ContextMenu from '@radix-ui/react-context-menu';
import { import {
resetCanvasView,
resizeAndScaleCanvas,
setDoesCanvasNeedScaling, setDoesCanvasNeedScaling,
setInitialCanvasImage, setInitialCanvasImage,
} from 'features/canvas/store/canvasSlice'; } from 'features/canvas/store/canvasSlice';
import { hoverableImageSelector } from './gallerySliceSelectors'; import { hoverableImageSelector } from './gallerySliceSelectors';
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
interface HoverableImageProps { interface HoverableImageProps {
image: InvokeAI.Image; image: InvokeAI.Image;
@ -99,7 +102,8 @@ const HoverableImage = memo((props: HoverableImageProps) => {
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false)); if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
dispatch(setInitialCanvasImage(image)); dispatch(setInitialCanvasImage(image));
dispatch(setDoesCanvasNeedScaling(true));
dispatch(resizeAndScaleCanvas());
if (activeTabName !== 'unifiedCanvas') { if (activeTabName !== 'unifiedCanvas') {
dispatch(setActiveTab('unifiedCanvas')); dispatch(setActiveTab('unifiedCanvas'));