fix(ui): fix canvas scaling

This commit is contained in:
psychedelicious 2023-08-23 21:53:20 +10:00
parent 06ac16a77d
commit 6efa953172
3 changed files with 99 additions and 45 deletions

View File

@ -1,6 +1,6 @@
import { Box, chakra, Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import {
canvasSelector,
@ -9,7 +9,7 @@ import {
import Konva from 'konva';
import { KonvaEventObject } from 'konva/lib/Node';
import { Vector2d } from 'konva/lib/types';
import { memo, useCallback, useRef } from 'react';
import { memo, useCallback, useEffect, useRef } from 'react';
import { Layer, Stage } from 'react-konva';
import useCanvasDragMove from '../hooks/useCanvasDragMove';
import useCanvasHotkeys from '../hooks/useCanvasHotkeys';
@ -18,6 +18,7 @@ import useCanvasMouseMove from '../hooks/useCanvasMouseMove';
import useCanvasMouseOut from '../hooks/useCanvasMouseOut';
import useCanvasMouseUp from '../hooks/useCanvasMouseUp';
import useCanvasWheel from '../hooks/useCanvasZoom';
import { canvasResized } from '../store/canvasSlice';
import {
setCanvasBaseLayer,
setCanvasStage,
@ -106,7 +107,8 @@ const IAICanvas = () => {
shouldAntialias,
} = useAppSelector(selector);
useCanvasHotkeys();
const dispatch = useAppDispatch();
const containerRef = useRef<HTMLDivElement>(null);
const stageRef = useRef<Konva.Stage | null>(null);
const canvasBaseLayerRef = useRef<Konva.Layer | null>(null);
@ -137,8 +139,30 @@ const IAICanvas = () => {
const { handleDragStart, handleDragMove, handleDragEnd } =
useCanvasDragMove();
useEffect(() => {
if (!containerRef.current) {
return;
}
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
if (entry.contentBoxSize) {
const { width, height } = entry.contentRect;
dispatch(canvasResized({ width, height }));
}
}
});
resizeObserver.observe(containerRef.current);
return () => {
resizeObserver.disconnect();
};
}, [dispatch]);
return (
<Flex
id="canvas-container"
ref={containerRef}
sx={{
position: 'relative',
height: '100%',
@ -146,13 +170,18 @@ const IAICanvas = () => {
borderRadius: 'base',
}}
>
<Box sx={{ position: 'relative' }}>
<Box
sx={{
position: 'absolute',
// top: 0,
// insetInlineStart: 0,
}}
>
<ChakraStage
tabIndex={-1}
ref={canvasStageRefCallback}
sx={{
outline: 'none',
// boxShadow: '0px 0px 0px 1px var(--border-color-light)',
overflow: 'hidden',
cursor: stageCursor ? stageCursor : undefined,
canvas: {
@ -213,9 +242,9 @@ const IAICanvas = () => {
/>
</Layer>
</ChakraStage>
<IAICanvasStatusText />
<IAICanvasStagingAreaToolbar />
</Box>
<IAICanvasStatusText />
<IAICanvasStagingAreaToolbar />
</Flex>
);
};

View File

@ -623,6 +623,53 @@ export const canvasSlice = createSlice({
}
}
},
canvasResized: (
state,
action: PayloadAction<{ width: number; height: number }>
) => {
const { width, height } = action.payload;
const newStageDimensions = {
width: Math.floor(width),
height: Math.floor(height),
};
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
);
const newBoundingBoxDimensions = { width: 512, height: 512 };
state.stageScale = newScale;
state.stageCoordinates = newCoordinates;
state.boundingBoxCoordinates = { x: 0, y: 0 };
state.boundingBoxDimensions = newBoundingBoxDimensions;
if (state.boundingBoxScaleMethod === 'auto') {
const scaledDimensions = getScaledBoundingBoxDimensions(
newBoundingBoxDimensions
);
state.scaledBoundingBoxDimensions = scaledDimensions;
}
}
},
resetCanvasView: (
state,
action: PayloadAction<{
@ -966,6 +1013,7 @@ export const {
stagingAreaInitialized,
canvasSessionIdChanged,
setShouldAntialias,
canvasResized,
} = canvasSlice.actions;
export default canvasSlice.reducer;

View File

@ -1,11 +1,10 @@
import { Box, Flex } from '@chakra-ui/react';
import { Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIDropOverlay from 'common/components/IAIDropOverlay';
import IAICanvas from 'features/canvas/components/IAICanvas';
import IAICanvasResizer from 'features/canvas/components/IAICanvasResizer';
import IAICanvasToolbar from 'features/canvas/components/IAICanvasToolbar/IAICanvasToolbar';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import { useDroppableTypesafe } from 'features/dnd/hooks/typesafeHooks';
@ -54,49 +53,27 @@ const UnifiedCanvasContent = () => {
}, [dispatch]);
return (
<Box
<Flex
layerStyle="first"
ref={setDroppableRef}
tabIndex={-1}
sx={{
layerStyle: 'first',
flexDirection: 'column',
alignItems: 'center',
gap: 4,
p: 2,
borderRadius: 'base',
w: 'full',
h: 'full',
p: 4,
borderRadius: 'base',
}}
>
<Flex
sx={{
flexDirection: 'column',
alignItems: 'center',
gap: 4,
w: 'full',
h: 'full',
}}
>
<IAICanvasToolbar />
<Flex
sx={{
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
gap: 4,
w: 'full',
h: 'full',
}}
>
<Box sx={{ w: 'full', h: 'full', position: 'relative' }}>
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
{isValidDrop(droppableData, active) && (
<IAIDropOverlay
isOver={isOver}
label="Set Canvas Initial Image"
/>
)}
</Box>
</Flex>
</Flex>
</Box>
<IAICanvasToolbar />
<IAICanvas />
{/* {doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />} */}
{isValidDrop(droppableData, active) && (
<IAIDropOverlay isOver={isOver} label="Set Canvas Initial Image" />
)}
</Flex>
);
};