2022-11-27 03:35:49 +13:00

116 lines
3.0 KiB
TypeScript

// Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/
import { useColorMode } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store';
import _ from 'lodash';
import { ReactNode, useCallback, useLayoutEffect, useState } from 'react';
import { Group, Line as KonvaLine } from 'react-konva';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
const selector = createSelector(
[canvasSelector],
(canvas) => {
const { stageScale, stageCoordinates, stageDimensions } = canvas;
return { stageScale, stageCoordinates, stageDimensions };
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
},
}
);
const gridLinesColor = {
dark: 'rgba(255, 255, 255, 0.2)',
green: 'rgba(255, 255, 255, 0.2)',
light: 'rgba(0, 0, 0, 0.2)',
};
const IAICanvasGrid = () => {
const { colorMode } = useColorMode();
const { stageScale, stageCoordinates, stageDimensions } =
useAppSelector(selector);
const [gridLines, setGridLines] = useState<ReactNode[]>([]);
const unscale = useCallback(
(value: number) => {
return value / stageScale;
},
[stageScale]
);
useLayoutEffect(() => {
const gridLineColor = gridLinesColor[colorMode];
const { width, height } = stageDimensions;
const { x, y } = stageCoordinates;
const stageRect = {
x1: 0,
y1: 0,
x2: width,
y2: height,
offset: {
x: unscale(x),
y: unscale(y),
},
};
const gridOffset = {
x: Math.ceil(unscale(x) / 64) * 64,
y: Math.ceil(unscale(y) / 64) * 64,
};
const gridRect = {
x1: -gridOffset.x,
y1: -gridOffset.y,
x2: unscale(width) - gridOffset.x + 64,
y2: unscale(height) - gridOffset.y + 64,
};
const gridFullRect = {
x1: Math.min(stageRect.x1, gridRect.x1),
y1: Math.min(stageRect.y1, gridRect.y1),
x2: Math.max(stageRect.x2, gridRect.x2),
y2: Math.max(stageRect.y2, gridRect.y2),
};
const fullRect = gridFullRect;
const // find the x & y size of the grid
xSize = fullRect.x2 - fullRect.x1,
ySize = fullRect.y2 - fullRect.y1,
// compute the number of steps required on each axis.
xSteps = Math.round(xSize / 64) + 1,
ySteps = Math.round(ySize / 64) + 1;
const xLines = _.range(0, xSteps).map((i) => (
<KonvaLine
key={`x_${i}`}
x={fullRect.x1 + i * 64}
y={fullRect.y1}
points={[0, 0, 0, ySize]}
stroke={gridLineColor}
strokeWidth={1}
/>
));
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}
/>
));
setGridLines(xLines.concat(yLines));
}, [stageScale, stageCoordinates, stageDimensions, colorMode, unscale]);
return <Group>{gridLines}</Group>;
};
export default IAICanvasGrid;