From 6d8620b402d44604a73386aa70385db795262e5b Mon Sep 17 00:00:00 2001 From: christian Date: Sun, 3 Nov 2024 21:56:34 +0100 Subject: [PATCH] now with scaling --- app/routes/CropSelector.tsx | 144 +++++++++++++++++++++++------------- app/routes/DragableBox.tsx | 5 ++ 2 files changed, 99 insertions(+), 50 deletions(-) diff --git a/app/routes/CropSelector.tsx b/app/routes/CropSelector.tsx index c240e2b..2f77de2 100644 --- a/app/routes/CropSelector.tsx +++ b/app/routes/CropSelector.tsx @@ -1,6 +1,7 @@ import DragableBox from "./DragableBox"; -import { ChangeEvent, useEffect, useRef, useState } from "react"; +import { ChangeEvent, Suspense, useEffect, useRef, useState } from "react"; import { PhAngle } from "./PhAngle"; +import { parse } from "postcss"; type Coordinates = { x: number; @@ -16,49 +17,92 @@ export default function CropSelector() { x: 0, y: 0 }) - const [containerWidth, setContainerWidth] = useState(null) - const [containerHeight, setContainerHeight] = useState(null) const [secondDragable, setSecondDragable] = useState({ x: 0, y: 0 }) + const [containerSize, setContainerSize] = useState({ width: 0, height: 0 }); + const [scaleRatio, setScaleRatio] = useState({ width: 1, height: 1 }); const containerRef = useRef(null) + const prevSize = useRef({ width: 0, height: 0 }); + + // Helper function to round pixel values + const roundPixel = (value: number) => Math.round(value); + useEffect(() => { const updateContainerSize = () => { - if (containerRef.current) { - setContainerWidth(containerRef.current.offsetWidth); - setContainerHeight(containerRef.current.offsetHeight); + if (!containerRef.current) return; + + const newWidth = roundPixel(containerRef.current.offsetWidth); + const newHeight = roundPixel(containerRef.current.offsetHeight); + + // Only calculate ratios if we have previous sizes + if (prevSize.current.width && prevSize.current.height) { + const widthRatio = newWidth / prevSize.current.width; + const heightRatio = newHeight / prevSize.current.height; + + setScaleRatio({ width: widthRatio, height: heightRatio }); + + // Update dragable positions with new ratios and round the results + setFirstDragable(prev => ({ + x: roundPixel(prev.x * widthRatio), + y: roundPixel(prev.y * heightRatio) + })); + setSecondDragable(prev => ({ + x: roundPixel(prev.x * widthRatio), + y: roundPixel(prev.y * heightRatio) + })); } - } + + // Update container size and store as previous for next resize + setContainerSize({ width: newWidth, height: newHeight }); + prevSize.current = { width: newWidth, height: newHeight }; + }; + + // Initial size setup updateContainerSize(); - window.addEventListener('resize', updateContainerSize); - return () => window.removeEventListener('resize', updateContainerSize); - }, []) + + // Add resize listener with debounce to prevent too frequent updates + let resizeTimeout: any; + const handleResize = () => { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(updateContainerSize, 16); // roughly 60fps + }; + + window.addEventListener('resize', handleResize); + + // Cleanup + return () => { + window.removeEventListener('resize', handleResize); + clearTimeout(resizeTimeout); + }; + }, []); // Empty dependency array since we're using refs const handleChange = (event: ChangeEvent) => { event.preventDefault() const { value, name, id } = event.target + let valueInt = parseInt(value) + if (name === 'x' && containerSize.width !== null && valueInt > containerSize.width) { + valueInt = containerSize.width + } + if (name === 'y' && containerSize.height !== null && valueInt > containerSize.height) { + valueInt = containerSize.height + } if (id === 'first') { setFirstDragable(prev => ({ ...prev, - [name]: value, - } - ) - ) + [name]: valueInt, + })) } if (id === 'second') { setSecondDragable(prev => ({ ...prev, - [name]: value, - } - ) - ) + [name]: valueInt, + })) } } - - useEffect(() => { const width = Math.abs(secondDragable.x - firstDragable.x); setSelectorWidth(width); @@ -70,36 +114,36 @@ export default function CropSelector() { return (
-
- {containerHeight !== null && containerWidth !== null && ( - <> -
- - - - - - - - )} -
- - - - -
-

{containerWidth} - {containerHeight}

-

firstDragable: x: {firstDragable.x.toFixed(2)} y: {firstDragable.y.toFixed(2)}

-

secondDragable: x: {secondDragable.x.toFixed(2)} y: {secondDragable.y.toFixed(2)}

-
+ Loading...

}> +
+
+ + + + + + +
+ + + + +
+

{containerSize.width} - {containerSize.height}

+

firstDragable: x: {firstDragable.x} y: {firstDragable.y}

+

secondDragable: x: {secondDragable.x} y: {secondDragable.y}

+

Scale height: {scaleRatio.height}

+

Scale width: {scaleRatio.width}

+
+
); } diff --git a/app/routes/DragableBox.tsx b/app/routes/DragableBox.tsx index 62b0d9e..8057484 100644 --- a/app/routes/DragableBox.tsx +++ b/app/routes/DragableBox.tsx @@ -1,5 +1,10 @@ import { useState, useEffect, MouseEvent, useRef, Dispatch, SetStateAction } from 'react'; +// Todo +// Have selector start at full width and height +// dragable icons rotation +// drag selector + type Coordinates = { x: number; y: number;