mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): support grid size of 8 on canvas
- Support grid size of 8 on canvas - Internal canvas math works on 8 - Update gridlines rendering to show 64 spaced lines and 32/16/8 when zoomed in - Bbox manipulation defaults to grid of 64 - hold shift to get grid of 8 Besides being something we support internally, supporting 8 on canvas avoids a lot of hacky logic needed to work well with aspect ratios.
This commit is contained in:
committed by
Kent Keirsey
parent
4f43eda09b
commit
cecee33bc0
@ -1,21 +1,36 @@
|
|||||||
// Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/
|
// Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/
|
||||||
import { useToken } from '@chakra-ui/react';
|
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
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 type { ReactElement } from 'react';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { Group, Line as KonvaLine } from 'react-konva';
|
import { Group, Line as KonvaLine } from 'react-konva';
|
||||||
|
import { getArbitraryBaseColor } from 'theme/colors';
|
||||||
|
|
||||||
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
||||||
const { stageScale, stageCoordinates, stageDimensions } = canvas;
|
const { stageScale, stageCoordinates, stageDimensions } = canvas;
|
||||||
return { stageScale, stageCoordinates, stageDimensions };
|
return { stageScale, stageCoordinates, stageDimensions };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const baseGridLineColor = getArbitraryBaseColor(27);
|
||||||
|
const fineGridLineColor = getArbitraryBaseColor(18);
|
||||||
|
|
||||||
const IAICanvasGrid = () => {
|
const IAICanvasGrid = () => {
|
||||||
const { stageScale, stageCoordinates, stageDimensions } =
|
const { stageScale, stageCoordinates, stageDimensions } =
|
||||||
useAppSelector(selector);
|
useAppSelector(selector);
|
||||||
const [gridLineColor] = useToken('colors', ['base.800']);
|
|
||||||
|
const gridSpacing = useMemo(() => {
|
||||||
|
if (stageScale >= 2) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
if (stageScale >= 1 && stageScale < 2) {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
if (stageScale >= 0.5 && stageScale < 1) {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
return 64;
|
||||||
|
}, [stageScale]);
|
||||||
|
|
||||||
const unscale = useCallback(
|
const unscale = useCallback(
|
||||||
(value: number) => {
|
(value: number) => {
|
||||||
@ -40,15 +55,15 @@ const IAICanvasGrid = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const gridOffset = {
|
const gridOffset = {
|
||||||
x: Math.ceil(unscale(x) / 64) * 64,
|
x: Math.ceil(unscale(x) / gridSpacing) * gridSpacing,
|
||||||
y: Math.ceil(unscale(y) / 64) * 64,
|
y: Math.ceil(unscale(y) / gridSpacing) * gridSpacing,
|
||||||
};
|
};
|
||||||
|
|
||||||
const gridRect = {
|
const gridRect = {
|
||||||
x1: -gridOffset.x,
|
x1: -gridOffset.x,
|
||||||
y1: -gridOffset.y,
|
y1: -gridOffset.y,
|
||||||
x2: unscale(width) - gridOffset.x + 64,
|
x2: unscale(width) - gridOffset.x + gridSpacing,
|
||||||
y2: unscale(height) - gridOffset.y + 64,
|
y2: unscale(height) - gridOffset.y + gridSpacing,
|
||||||
};
|
};
|
||||||
|
|
||||||
const gridFullRect = {
|
const gridFullRect = {
|
||||||
@ -58,40 +73,50 @@ const IAICanvasGrid = () => {
|
|||||||
y2: Math.max(stageRect.y2, gridRect.y2),
|
y2: Math.max(stageRect.y2, gridRect.y2),
|
||||||
};
|
};
|
||||||
|
|
||||||
const fullRect = gridFullRect;
|
|
||||||
|
|
||||||
const // find the x & y size of the grid
|
const // find the x & y size of the grid
|
||||||
xSize = fullRect.x2 - fullRect.x1,
|
xSize = gridFullRect.x2 - gridFullRect.x1,
|
||||||
ySize = fullRect.y2 - fullRect.y1,
|
ySize = gridFullRect.y2 - gridFullRect.y1,
|
||||||
// compute the number of steps required on each axis.
|
// compute the number of steps required on each axis.
|
||||||
xSteps = Math.round(xSize / 64) + 1,
|
xSteps = Math.round(xSize / gridSpacing) + 1,
|
||||||
ySteps = Math.round(ySize / 64) + 1;
|
ySteps = Math.round(ySize / gridSpacing) + 1;
|
||||||
|
|
||||||
const xLines = range(0, xSteps).map((i) => (
|
const strokeWidth = unscale(1);
|
||||||
<KonvaLine
|
|
||||||
key={`x_${i}`}
|
|
||||||
x={fullRect.x1 + i * 64}
|
|
||||||
y={fullRect.y1}
|
|
||||||
points={[0, 0, 0, ySize]}
|
|
||||||
stroke={gridLineColor}
|
|
||||||
strokeWidth={1}
|
|
||||||
listening={false}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
const yLines = range(0, ySteps).map((i) => (
|
|
||||||
<KonvaLine
|
|
||||||
key={`y_${i}`}
|
|
||||||
x={fullRect.x1}
|
|
||||||
y={fullRect.y1 + i * 64}
|
|
||||||
points={[0, 0, xSize, 0]}
|
|
||||||
stroke={gridLineColor}
|
|
||||||
strokeWidth={1}
|
|
||||||
listening={false}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
|
|
||||||
return xLines.concat(yLines);
|
const gridLines: ReactElement[] = new Array(xSteps + ySteps);
|
||||||
}, [stageCoordinates, stageDimensions, unscale, gridLineColor]);
|
let _x = 0;
|
||||||
|
let _y = 0;
|
||||||
|
for (let i = 0; i < xSteps; i++) {
|
||||||
|
_x = gridFullRect.x1 + i * gridSpacing;
|
||||||
|
gridLines.push(
|
||||||
|
<KonvaLine
|
||||||
|
key={`x_${i}`}
|
||||||
|
x={_x}
|
||||||
|
y={gridFullRect.y1}
|
||||||
|
points={[0, 0, 0, ySize]}
|
||||||
|
stroke={_x % 64 ? fineGridLineColor : baseGridLineColor}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
listening={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < ySteps; i++) {
|
||||||
|
_y = gridFullRect.y1 + i * gridSpacing;
|
||||||
|
gridLines.push(
|
||||||
|
<KonvaLine
|
||||||
|
key={`y_${i}`}
|
||||||
|
x={gridFullRect.x1}
|
||||||
|
y={_y}
|
||||||
|
points={[0, 0, xSize, 0]}
|
||||||
|
stroke={_y % 64 ? fineGridLineColor : baseGridLineColor}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
listening={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gridLines;
|
||||||
|
}, [stageDimensions, stageCoordinates, unscale, gridSpacing]);
|
||||||
|
|
||||||
return <Group listening={false}>{gridLines}</Group>;
|
return <Group listening={false}>{gridLines}</Group>;
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@ import { useStore } from '@nanostores/react';
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { $shift } from 'common/hooks/useGlobalModifiers';
|
||||||
import {
|
import {
|
||||||
roundDownToMultiple,
|
roundDownToMultiple,
|
||||||
roundToMultiple,
|
roundToMultiple,
|
||||||
@ -15,6 +16,8 @@ import {
|
|||||||
setIsTransformingBoundingBox,
|
setIsTransformingBoundingBox,
|
||||||
} from 'features/canvas/store/canvasNanostore';
|
} from 'features/canvas/store/canvasNanostore';
|
||||||
import {
|
import {
|
||||||
|
CANVAS_GRID_SIZE_COARSE,
|
||||||
|
CANVAS_GRID_SIZE_FINE,
|
||||||
setBoundingBoxCoordinates,
|
setBoundingBoxCoordinates,
|
||||||
setBoundingBoxDimensions,
|
setBoundingBoxDimensions,
|
||||||
setShouldSnapToGrid,
|
setShouldSnapToGrid,
|
||||||
@ -23,7 +26,7 @@ import type Konva from 'konva';
|
|||||||
import type { GroupConfig } from 'konva/lib/Group';
|
import type { GroupConfig } from 'konva/lib/Group';
|
||||||
import type { KonvaEventObject } from 'konva/lib/Node';
|
import type { KonvaEventObject } from 'konva/lib/Node';
|
||||||
import type { Vector2d } from 'konva/lib/types';
|
import type { Vector2d } from 'konva/lib/types';
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { Group, Rect, Transformer } from 'react-konva';
|
import { Group, Rect, Transformer } from 'react-konva';
|
||||||
|
|
||||||
@ -58,12 +61,10 @@ type IAICanvasBoundingBoxPreviewProps = GroupConfig;
|
|||||||
|
|
||||||
const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
||||||
const { ...rest } = props;
|
const { ...rest } = props;
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const {
|
const {
|
||||||
boundingBoxCoordinates,
|
boundingBoxCoordinates,
|
||||||
boundingBoxDimensions,
|
boundingBoxDimensions,
|
||||||
|
|
||||||
stageScale,
|
stageScale,
|
||||||
shouldSnapToGrid,
|
shouldSnapToGrid,
|
||||||
tool,
|
tool,
|
||||||
@ -73,6 +74,7 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
|||||||
|
|
||||||
const transformerRef = useRef<Konva.Transformer>(null);
|
const transformerRef = useRef<Konva.Transformer>(null);
|
||||||
const shapeRef = useRef<Konva.Rect>(null);
|
const shapeRef = useRef<Konva.Rect>(null);
|
||||||
|
const shift = useStore($shift);
|
||||||
const isDrawing = useStore($isDrawing);
|
const isDrawing = useStore($isDrawing);
|
||||||
const isMovingBoundingBox = useStore($isMovingBoundingBox);
|
const isMovingBoundingBox = useStore($isMovingBoundingBox);
|
||||||
const isTransformingBoundingBox = useStore($isTransformingBoundingBox);
|
const isTransformingBoundingBox = useStore($isTransformingBoundingBox);
|
||||||
@ -87,7 +89,14 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
|||||||
transformerRef.current.getLayer()?.batchDraw();
|
transformerRef.current.getLayer()?.batchDraw();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const scaledStep = 64 * stageScale;
|
const gridSize = useMemo(
|
||||||
|
() => (shift ? CANVAS_GRID_SIZE_FINE : CANVAS_GRID_SIZE_COARSE),
|
||||||
|
[shift]
|
||||||
|
);
|
||||||
|
const scaledStep = useMemo(
|
||||||
|
() => gridSize * stageScale,
|
||||||
|
[gridSize, stageScale]
|
||||||
|
);
|
||||||
|
|
||||||
useHotkeys('N', () => {
|
useHotkeys('N', () => {
|
||||||
dispatch(setShouldSnapToGrid(!shouldSnapToGrid));
|
dispatch(setShouldSnapToGrid(!shouldSnapToGrid));
|
||||||
@ -108,8 +117,8 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
|||||||
const dragX = e.target.x();
|
const dragX = e.target.x();
|
||||||
const dragY = e.target.y();
|
const dragY = e.target.y();
|
||||||
|
|
||||||
const newX = roundToMultiple(dragX, 64);
|
const newX = roundToMultiple(dragX, gridSize);
|
||||||
const newY = roundToMultiple(dragY, 64);
|
const newY = roundToMultiple(dragY, gridSize);
|
||||||
|
|
||||||
e.target.x(newX);
|
e.target.x(newX);
|
||||||
e.target.y(newY);
|
e.target.y(newY);
|
||||||
@ -121,7 +130,7 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[dispatch, shouldSnapToGrid]
|
[dispatch, gridSize, shouldSnapToGrid]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleOnTransform = useCallback(() => {
|
const handleOnTransform = useCallback(() => {
|
||||||
@ -147,7 +156,7 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
|||||||
const y = Math.round(rect.y());
|
const y = Math.round(rect.y());
|
||||||
|
|
||||||
if (aspectRatio) {
|
if (aspectRatio) {
|
||||||
const newHeight = roundToMultiple(width / aspectRatio.value, 64);
|
const newHeight = roundToMultiple(width / aspectRatio.value, gridSize);
|
||||||
dispatch(
|
dispatch(
|
||||||
setBoundingBoxDimensions({
|
setBoundingBoxDimensions({
|
||||||
width: width,
|
width: width,
|
||||||
@ -165,15 +174,15 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
|||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
setBoundingBoxCoordinates({
|
setBoundingBoxCoordinates({
|
||||||
x: shouldSnapToGrid ? roundDownToMultiple(x, 64) : x,
|
x: shouldSnapToGrid ? roundDownToMultiple(x, gridSize) : x,
|
||||||
y: shouldSnapToGrid ? roundDownToMultiple(y, 64) : y,
|
y: shouldSnapToGrid ? roundDownToMultiple(y, gridSize) : y,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reset the scale now that the coords/dimensions have been un-scaled
|
// Reset the scale now that the coords/dimensions have been un-scaled
|
||||||
rect.scaleX(1);
|
rect.scaleX(1);
|
||||||
rect.scaleY(1);
|
rect.scaleY(1);
|
||||||
}, [dispatch, shouldSnapToGrid, aspectRatio]);
|
}, [aspectRatio, dispatch, shouldSnapToGrid, gridSize]);
|
||||||
|
|
||||||
const anchorDragBoundFunc = useCallback(
|
const anchorDragBoundFunc = useCallback(
|
||||||
(
|
(
|
||||||
|
@ -9,7 +9,7 @@ import calculateScale from 'features/canvas/util/calculateScale';
|
|||||||
import { STAGE_PADDING_PERCENTAGE } from 'features/canvas/util/constants';
|
import { STAGE_PADDING_PERCENTAGE } from 'features/canvas/util/constants';
|
||||||
import floorCoordinates from 'features/canvas/util/floorCoordinates';
|
import floorCoordinates from 'features/canvas/util/floorCoordinates';
|
||||||
import getScaledBoundingBoxDimensions from 'features/canvas/util/getScaledBoundingBoxDimensions';
|
import getScaledBoundingBoxDimensions from 'features/canvas/util/getScaledBoundingBoxDimensions';
|
||||||
import roundDimensionsTo64 from 'features/canvas/util/roundDimensionsTo64';
|
import roundDimensionsToMultiple from 'features/canvas/util/roundDimensionsToMultiple';
|
||||||
import type { AspectRatioState } from 'features/parameters/components/ImageSize/types';
|
import type { AspectRatioState } from 'features/parameters/components/ImageSize/types';
|
||||||
import type { IRect, Vector2d } from 'konva/lib/types';
|
import type { IRect, Vector2d } from 'konva/lib/types';
|
||||||
import { clamp, cloneDeep } from 'lodash-es';
|
import { clamp, cloneDeep } from 'lodash-es';
|
||||||
@ -40,6 +40,9 @@ import {
|
|||||||
*/
|
*/
|
||||||
const MAX_HISTORY = 128;
|
const MAX_HISTORY = 128;
|
||||||
|
|
||||||
|
export const CANVAS_GRID_SIZE_FINE = 8;
|
||||||
|
export const CANVAS_GRID_SIZE_COARSE = 64;
|
||||||
|
|
||||||
export const initialLayerState: CanvasLayerState = {
|
export const initialLayerState: CanvasLayerState = {
|
||||||
objects: [],
|
objects: [],
|
||||||
stagingArea: {
|
stagingArea: {
|
||||||
@ -141,15 +144,24 @@ export const canvasSlice = createSlice({
|
|||||||
const { stageDimensions } = state;
|
const { stageDimensions } = state;
|
||||||
|
|
||||||
const newBoundingBoxDimensions = {
|
const newBoundingBoxDimensions = {
|
||||||
width: roundDownToMultiple(clamp(width, 64, 512), 64),
|
width: roundDownToMultiple(
|
||||||
height: roundDownToMultiple(clamp(height, 64, 512), 64),
|
clamp(width, CANVAS_GRID_SIZE_FINE, 512),
|
||||||
|
CANVAS_GRID_SIZE_FINE
|
||||||
|
),
|
||||||
|
height: roundDownToMultiple(
|
||||||
|
clamp(height, CANVAS_GRID_SIZE_FINE, 512),
|
||||||
|
CANVAS_GRID_SIZE_FINE
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const newBoundingBoxCoordinates = {
|
const newBoundingBoxCoordinates = {
|
||||||
x: roundToMultiple(width / 2 - newBoundingBoxDimensions.width / 2, 64),
|
x: roundToMultiple(
|
||||||
|
width / 2 - newBoundingBoxDimensions.width / 2,
|
||||||
|
CANVAS_GRID_SIZE_FINE
|
||||||
|
),
|
||||||
y: roundToMultiple(
|
y: roundToMultiple(
|
||||||
height / 2 - newBoundingBoxDimensions.height / 2,
|
height / 2 - newBoundingBoxDimensions.height / 2,
|
||||||
64
|
CANVAS_GRID_SIZE_FINE
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -206,10 +218,13 @@ export const canvasSlice = createSlice({
|
|||||||
state,
|
state,
|
||||||
action: PayloadAction<Partial<Dimensions>>
|
action: PayloadAction<Partial<Dimensions>>
|
||||||
) => {
|
) => {
|
||||||
const newDimensions = roundDimensionsTo64({
|
const newDimensions = roundDimensionsToMultiple(
|
||||||
...state.boundingBoxDimensions,
|
{
|
||||||
...action.payload,
|
...state.boundingBoxDimensions,
|
||||||
});
|
...action.payload,
|
||||||
|
},
|
||||||
|
CANVAS_GRID_SIZE_FINE
|
||||||
|
);
|
||||||
state.boundingBoxDimensions = newDimensions;
|
state.boundingBoxDimensions = newDimensions;
|
||||||
|
|
||||||
if (state.boundingBoxScaleMethod === 'auto') {
|
if (state.boundingBoxScaleMethod === 'auto') {
|
||||||
@ -649,18 +664,24 @@ export const canvasSlice = createSlice({
|
|||||||
scaledStageHeight
|
scaledStageHeight
|
||||||
) {
|
) {
|
||||||
const newBoundingBoxDimensions = {
|
const newBoundingBoxDimensions = {
|
||||||
width: roundDownToMultiple(clamp(scaledStageWidth, 64, 512), 64),
|
width: roundDownToMultiple(
|
||||||
height: roundDownToMultiple(clamp(scaledStageHeight, 64, 512), 64),
|
clamp(scaledStageWidth, CANVAS_GRID_SIZE_FINE, 512),
|
||||||
|
CANVAS_GRID_SIZE_FINE
|
||||||
|
),
|
||||||
|
height: roundDownToMultiple(
|
||||||
|
clamp(scaledStageHeight, CANVAS_GRID_SIZE_FINE, 512),
|
||||||
|
CANVAS_GRID_SIZE_FINE
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const newBoundingBoxCoordinates = {
|
const newBoundingBoxCoordinates = {
|
||||||
x: roundToMultiple(
|
x: roundToMultiple(
|
||||||
scaledStageWidth / 2 - newBoundingBoxDimensions.width / 2,
|
scaledStageWidth / 2 - newBoundingBoxDimensions.width / 2,
|
||||||
64
|
CANVAS_GRID_SIZE_FINE
|
||||||
),
|
),
|
||||||
y: roundToMultiple(
|
y: roundToMultiple(
|
||||||
scaledStageHeight / 2 - newBoundingBoxDimensions.height / 2,
|
scaledStageHeight / 2 - newBoundingBoxDimensions.height / 2,
|
||||||
64
|
CANVAS_GRID_SIZE_FINE
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
|
import { CANVAS_GRID_SIZE_FINE } from 'features/canvas/store/canvasSlice';
|
||||||
import type { Dimensions } from 'features/canvas/store/canvasTypes';
|
import type { Dimensions } from 'features/canvas/store/canvasTypes';
|
||||||
|
|
||||||
const getScaledBoundingBoxDimensions = (dimensions: Dimensions) => {
|
const getScaledBoundingBoxDimensions = (dimensions: Dimensions) => {
|
||||||
@ -10,7 +11,7 @@ const getScaledBoundingBoxDimensions = (dimensions: Dimensions) => {
|
|||||||
let currentArea = width * height;
|
let currentArea = width * height;
|
||||||
let maxDimension = 448;
|
let maxDimension = 448;
|
||||||
while (currentArea < targetArea) {
|
while (currentArea < targetArea) {
|
||||||
maxDimension += 64;
|
maxDimension += CANVAS_GRID_SIZE_FINE;
|
||||||
if (width === height) {
|
if (width === height) {
|
||||||
scaledDimensions.width = 512;
|
scaledDimensions.width = 512;
|
||||||
scaledDimensions.height = 512;
|
scaledDimensions.height = 512;
|
||||||
@ -20,13 +21,13 @@ const getScaledBoundingBoxDimensions = (dimensions: Dimensions) => {
|
|||||||
scaledDimensions.width = maxDimension;
|
scaledDimensions.width = maxDimension;
|
||||||
scaledDimensions.height = roundToMultiple(
|
scaledDimensions.height = roundToMultiple(
|
||||||
maxDimension / aspectRatio,
|
maxDimension / aspectRatio,
|
||||||
64
|
CANVAS_GRID_SIZE_FINE
|
||||||
);
|
);
|
||||||
} else if (aspectRatio < 1) {
|
} else if (aspectRatio < 1) {
|
||||||
scaledDimensions.height = maxDimension;
|
scaledDimensions.height = maxDimension;
|
||||||
scaledDimensions.width = roundToMultiple(
|
scaledDimensions.width = roundToMultiple(
|
||||||
maxDimension * aspectRatio,
|
maxDimension * aspectRatio,
|
||||||
64
|
CANVAS_GRID_SIZE_FINE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
currentArea = scaledDimensions.width * scaledDimensions.height;
|
currentArea = scaledDimensions.width * scaledDimensions.height;
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
|
||||||
import type { Dimensions } from 'features/canvas/store/canvasTypes';
|
|
||||||
|
|
||||||
const roundDimensionsTo64 = (dimensions: Dimensions): Dimensions => {
|
|
||||||
return {
|
|
||||||
width: roundToMultiple(dimensions.width, 64),
|
|
||||||
height: roundToMultiple(dimensions.height, 64),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default roundDimensionsTo64;
|
|
@ -0,0 +1,11 @@
|
|||||||
|
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
|
import type { Dimensions } from 'features/canvas/store/canvasTypes';
|
||||||
|
|
||||||
|
const roundDimensionsToMultiple = (dimensions: Dimensions, multiple: number): Dimensions => {
|
||||||
|
return {
|
||||||
|
width: roundToMultiple(dimensions.width, multiple),
|
||||||
|
height: roundToMultiple(dimensions.height, multiple),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default roundDimensionsToMultiple;
|
@ -4,6 +4,7 @@ import { useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { InvControl } from 'common/components/InvControl/InvControl';
|
import { InvControl } from 'common/components/InvControl/InvControl';
|
||||||
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
|
import { CANVAS_GRID_SIZE_COARSE, CANVAS_GRID_SIZE_FINE } from 'features/canvas/store/canvasSlice';
|
||||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -46,7 +47,8 @@ const ParamBoundingBoxWidth = () => {
|
|||||||
<InvSlider
|
<InvSlider
|
||||||
min={64}
|
min={64}
|
||||||
max={1536}
|
max={1536}
|
||||||
step={64}
|
step={CANVAS_GRID_SIZE_COARSE}
|
||||||
|
fineStep={CANVAS_GRID_SIZE_FINE}
|
||||||
value={ctx.height}
|
value={ctx.height}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onReset={onReset}
|
onReset={onReset}
|
||||||
|
@ -4,6 +4,7 @@ import { useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { InvControl } from 'common/components/InvControl/InvControl';
|
import { InvControl } from 'common/components/InvControl/InvControl';
|
||||||
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
|
import { CANVAS_GRID_SIZE_COARSE, CANVAS_GRID_SIZE_FINE } from 'features/canvas/store/canvasSlice';
|
||||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -46,7 +47,8 @@ const ParamBoundingBoxWidth = () => {
|
|||||||
<InvSlider
|
<InvSlider
|
||||||
min={64}
|
min={64}
|
||||||
max={1536}
|
max={1536}
|
||||||
step={64}
|
step={CANVAS_GRID_SIZE_COARSE}
|
||||||
|
fineStep={CANVAS_GRID_SIZE_FINE}
|
||||||
value={ctx.width}
|
value={ctx.width}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onReset={onReset}
|
onReset={onReset}
|
||||||
|
@ -13,6 +13,9 @@ const BLUE = { H: 200, S: 76 };
|
|||||||
const GREEN = { H: 110, S: 69 };
|
const GREEN = { H: 110, S: 69 };
|
||||||
const RED = { H: 16, S: 92 };
|
const RED = { H: 16, S: 92 };
|
||||||
|
|
||||||
|
export const getArbitraryBaseColor = (lightness: number) =>
|
||||||
|
`hsl(${BASE.H} ${BASE.S}% ${lightness}%)`;
|
||||||
|
|
||||||
export const InvokeAIColors: InvokeAIThemeColors = {
|
export const InvokeAIColors: InvokeAIThemeColors = {
|
||||||
base: generateColorPalette(BASE.H, BASE.S),
|
base: generateColorPalette(BASE.H, BASE.S),
|
||||||
baseAlpha: generateColorPalette(BASE.H, BASE.S, true),
|
baseAlpha: generateColorPalette(BASE.H, BASE.S, true),
|
||||||
|
Reference in New Issue
Block a user