diff --git a/app/routes/CropSelector.tsx b/app/routes/CropSelector.tsx index 2f77de2..12c3325 100644 --- a/app/routes/CropSelector.tsx +++ b/app/routes/CropSelector.tsx @@ -1,7 +1,6 @@ +import { Suspense, useEffect, useRef, useState } from "react"; import DragableBox from "./DragableBox"; -import { ChangeEvent, Suspense, useEffect, useRef, useState } from "react"; import { PhAngle } from "./PhAngle"; -import { parse } from "postcss"; type Coordinates = { x: number; @@ -9,140 +8,69 @@ type Coordinates = { } export default function CropSelector() { - const [selectorHeight, setSelectorHeight] = useState(0); - const [selectorWidth, setSelectorWidth] = useState(0); - const [selectorTop, setSelectorTop] = useState(0); - const [selectorLeft, setSelectorLeft] = useState(0); const [firstDragable, setFirstDragable] = useState({ x: 0, y: 0 - }) + }); const [secondDragable, setSecondDragable] = useState({ + x: 100, + y: 100 + }); + const [selectorPosition, setSelectorPosition] = 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); + const containerRef = useRef(null); + // Update selector position and dimensions based on handle positions useEffect(() => { - const updateContainerSize = () => { - 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(); - - // 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]: valueInt, - })) - } - if (id === 'second') { - setSecondDragable(prev => ({ - ...prev, - [name]: valueInt, - })) - } - } - - useEffect(() => { - const width = Math.abs(secondDragable.x - firstDragable.x); - setSelectorWidth(width); - const height = Math.abs(secondDragable.y - firstDragable.y); - setSelectorHeight(height); - setSelectorTop(Math.min(firstDragable.y, secondDragable.y)); - setSelectorLeft(Math.min(firstDragable.x, secondDragable.x)); + setSelectorPosition({ + x: Math.min(firstDragable.x, secondDragable.x), + y: Math.min(firstDragable.y, secondDragable.y) + }); }, [firstDragable, secondDragable]); + // Calculate selector dimensions + const selectorWidth = Math.abs(secondDragable.x - firstDragable.x); + const selectorHeight = Math.abs(secondDragable.y - firstDragable.y); + + // Handle selector drag + const handleSelectorDrag = (newPosition: Coordinates) => { + const deltaX = newPosition.x - selectorPosition.x; + const deltaY = newPosition.y - selectorPosition.y; + + setFirstDragable(prev => ({ + x: Math.min(firstDragable.x, secondDragable.x) + deltaX, + y: Math.min(firstDragable.y, secondDragable.y) + deltaY + })); + + setSecondDragable(prev => ({ + x: Math.max(firstDragable.x, secondDragable.x) + deltaX, + y: Math.max(firstDragable.y, secondDragable.y) + deltaY + })); + }; + return (
- Loading...

}> + 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 8057484..1881281 100644 --- a/app/routes/DragableBox.tsx +++ b/app/routes/DragableBox.tsx @@ -1,10 +1,5 @@ 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; @@ -15,13 +10,21 @@ interface DraggableBoxProps { className?: string; children?: React.ReactNode; coordSetter: Dispatch>; + mode?: 'handle' | 'box'; + width?: number; + height?: number; + onDrag?: (delta: Coordinates) => void; } const DraggableBox = ({ position, className = "", children = "", - coordSetter + coordSetter, + mode = 'handle', + width = 0, + height = 0, + onDrag }: DraggableBoxProps) => { const [isDragging, setIsDragging] = useState(false); const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 }); @@ -36,19 +39,34 @@ const DraggableBox = ({ const parent = dragRef.current.parentElement; const parentRect = parent.getBoundingClientRect(); - const relativeX = e.clientX - parentRect.left - dragOffset.x; - const relativeY = e.clientY - parentRect.top - dragOffset.y; + if (mode === 'handle') { + const x = ((e.clientX - parentRect.left - dragOffset.x) / parentRect.width) * 100; + const y = ((e.clientY - parentRect.top - dragOffset.y) / parentRect.height) * 100; - const maxX = parentRect.width; - const maxY = parentRect.height; + const newX = Math.min(Math.max(0, x), 100); + const newY = Math.min(Math.max(0, y), 100); - let newX = (Math.max(0, Math.min(relativeX, maxX))); - let newY = (Math.max(0, Math.min(relativeY, maxY))); + coordSetter({ + x: Number(newX.toFixed(1)), + y: Number(newY.toFixed(1)) + }); + } else { + const x = ((e.clientX - parentRect.left - dragOffset.x) / parentRect.width) * 100; + const y = ((e.clientY - parentRect.top - dragOffset.y) / parentRect.height) * 100; - coordSetter({ - x: newX, - y: newY - }) + const maxX = 100 - width; + const maxY = 100 - height; + + const newX = Math.min(Math.max(0, x), maxX); + const newY = Math.min(Math.max(0, y), maxY); + + coordSetter({ + x: Number(newX.toFixed(1)), + y: Number(newY.toFixed(1)) + }); + + onDrag?.({ x: newX, y: newY }); + } }; const handleMouseUp = () => setIsDragging(false); @@ -60,26 +78,46 @@ const DraggableBox = ({ window.removeEventListener('mousemove', handleMouseMove); window.removeEventListener('mouseup', handleMouseUp); }; - }, [isDragging, dragOffset, position.x, position.y]); + }, [isDragging, dragOffset, mode, width, height, onDrag]); const handleMouseDown = (e: MouseEvent) => { if (!dragRef.current?.parentElement) return; const parentRect = dragRef.current.parentElement.getBoundingClientRect(); + const elementRect = dragRef.current.getBoundingClientRect(); + + if (mode === 'handle') { + setDragOffset({ + x: e.clientX - elementRect.left, + y: e.clientY - elementRect.top + }); + } else { + setDragOffset({ + x: e.clientX - parentRect.left - (position.x * parentRect.width / 100), + y: e.clientY - parentRect.top - (position.y * parentRect.height / 100) + }); + } - setDragOffset({ - x: e.clientX - parentRect.left - position.x, - y: e.clientY - parentRect.top - position.y - }); setIsDragging(true); }; + const style = mode === 'handle' ? { + left: `${position.x}%`, + top: `${position.y}%`, + transform: 'translate(-50%, -50%)', // Center the handle + } : { + left: `${position.x}%`, + top: `${position.y}%`, + width: `${width}%`, + height: `${height}%`, + }; + return (