feat: center canvas on image open

This commit is contained in:
trafficlunar 2025-01-25 23:15:32 +00:00
parent e82a0ef158
commit e22d51947a
2 changed files with 39 additions and 3 deletions

View file

@ -24,7 +24,7 @@ import VersionCombobox from "../VersionCombobox";
import { findBlockFromRgb } from "@/utils/findBlockFromRgb"; import { findBlockFromRgb } from "@/utils/findBlockFromRgb";
function OpenImage({ close }: DialogProps) { function OpenImage({ close }: DialogProps) {
const { version, setVersion, setBlocks } = useContext(CanvasContext); const { version, setBlocks, setVersion, centerCanvas } = useContext(CanvasContext);
const { setLoading } = useContext(LoadingContext); const { setLoading } = useContext(LoadingContext);
const { acceptedFiles, getRootProps, getInputProps } = useDropzone({ const { acceptedFiles, getRootProps, getInputProps } = useDropzone({
@ -52,6 +52,8 @@ function OpenImage({ close }: DialogProps) {
falling: false, falling: false,
}); });
const [isFinished, setIsFinished] = useState(false);
useEffect(() => { useEffect(() => {
if (acceptedFiles[0]) { if (acceptedFiles[0]) {
const img = new Image(); const img = new Image();
@ -96,6 +98,7 @@ function OpenImage({ close }: DialogProps) {
const onSubmit = async () => { const onSubmit = async () => {
if (image) { if (image) {
setIsFinished(false);
setLoading(true); setLoading(true);
// Wait for loading indicator to appear // Wait for loading indicator to appear
await new Promise((resolve) => setTimeout(resolve, 100)); await new Promise((resolve) => setTimeout(resolve, 100));
@ -131,10 +134,18 @@ function OpenImage({ close }: DialogProps) {
} }
setLoading(false); setLoading(false);
close(); setIsFinished(true);
} }
}; };
useEffect(() => {
if (!isFinished) return;
centerCanvas();
close();
return () => setIsFinished(false);
}, [isFinished, centerCanvas, close]);
useEffect(() => { useEffect(() => {
Object.keys(blockTypeCheckboxesChecked).forEach((property) => { Object.keys(blockTypeCheckboxesChecked).forEach((property) => {
const blocksWithProperty = Object.entries(blockData) const blocksWithProperty = Object.entries(blockData)

View file

@ -14,6 +14,7 @@ interface Context {
setCoords: React.Dispatch<React.SetStateAction<Position>>; setCoords: React.Dispatch<React.SetStateAction<Position>>;
setScale: React.Dispatch<React.SetStateAction<number>>; setScale: React.Dispatch<React.SetStateAction<number>>;
setVersion: React.Dispatch<React.SetStateAction<number>>; setVersion: React.Dispatch<React.SetStateAction<number>>;
centerCanvas: () => void;
} }
interface Props { interface Props {
@ -29,6 +30,7 @@ export const CanvasProvider = ({ children }: Props) => {
const [scale, setScale] = useState(1); const [scale, setScale] = useState(1);
const [version, setVersion] = useState(1214); const [version, setVersion] = useState(1214);
// Get the farthest away blocks in each direction
const canvasSize = useMemo(() => { const canvasSize = useMemo(() => {
let minX = Infinity, let minX = Infinity,
maxX = -Infinity; maxX = -Infinity;
@ -50,9 +52,32 @@ export const CanvasProvider = ({ children }: Props) => {
}; };
}, [blocks]); }, [blocks]);
const centerCanvas = () => {
// Margin of 8 blocks on each side
const margin = 8 * 16;
// Calculate the total width and height of the blocks, including margin
const blocksWidth = (canvasSize.maxX - canvasSize.minX) * 16 + margin * 2;
const blocksHeight = (canvasSize.maxY - canvasSize.minY) * 16 + margin * 2;
// Calculate the scale to fit the blocks (with margin) within the stage
const scaleX = stageSize.width / blocksWidth;
const scaleY = stageSize.height / blocksHeight;
// Use the smaller scale to fit the blocks inside the entire screen
const newScale = Math.min(scaleX, scaleY);
// Calculate the coordinates to center the blocks in the middle of the stage
const newX = stageSize.width / 2 - ((blocksWidth - margin * 2) * newScale) / 2 - canvasSize.minX * 16 * newScale;
const newY = stageSize.height / 2 - ((blocksHeight - margin * 2) * newScale) / 2 - canvasSize.minY * 16 * newScale;
setScale(newScale);
setCoords({ x: newX, y: newY });
};
return ( return (
<CanvasContext.Provider <CanvasContext.Provider
value={{ stageSize, canvasSize, blocks, coords, scale, version, setStageSize, setBlocks, setCoords, setScale, setVersion }} value={{ stageSize, canvasSize, blocks, coords, scale, version, setStageSize, setBlocks, setCoords, setScale, setVersion, centerCanvas }}
> >
{children} {children}
</CanvasContext.Provider> </CanvasContext.Provider>