import React, { ChangeEvent, useEffect, useRef, useState } from "react"; import DragableBox from "./DragableBox"; import { Coordinates } from "~/types"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Label } from "@/components/ui/label"; import { useSearchParams } from "@remix-run/react"; type ContainerDimensions = { height: number; width: number; }; type FileDimensions = { x: number; y: number; }; type UnitType = "pixels" | "percentage"; interface ComponentProps { image?: string; } export default function CropSelector({ image }: ComponentProps) { 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({ height: 0, width: 0, }); const [pixelDimensions, setPixelDimensions] = useState({ height: 100, width: 100, }); const [unit, setUnit] = useState("pixels"); const [searchParams, setSearchParams] = useSearchParams(); const containerRef = useRef(null); useEffect(() => { setSelectorPosition({ x: Math.min(firstDragable.x, secondDragable.x), y: Math.min(firstDragable.y, secondDragable.y), }); const setUrlParams = setTimeout(() => { writeDimensionsToURL(); }, 500); return () => clearTimeout(setUrlParams); }, [firstDragable, secondDragable]); useEffect(() => { if (!containerRef.current) return; const resizeObserver = new ResizeObserver((entries) => { const entry = entries[0]; setContainerSize({ width: entry.contentRect.width, height: entry.contentRect.height, }); }); resizeObserver.observe(containerRef.current); return () => resizeObserver.disconnect(); }, [containerRef]); const selectorWidth = Math.abs(secondDragable.x - firstDragable.x); const selectorHeight = Math.abs(secondDragable.y - firstDragable.y); const handleSelectorDrag = (newPosition: Coordinates) => { const deltaX = newPosition.x - selectorPosition.x; const deltaY = newPosition.y - selectorPosition.y; const newFirstX = Math.min(firstDragable.x, secondDragable.x) + deltaX; const newFirstY = Math.min(firstDragable.y, secondDragable.y) + deltaY; const newSecondX = Math.max(firstDragable.x, secondDragable.x) + deltaX; const newSecondY = Math.max(firstDragable.y, secondDragable.y) + deltaY; if (newFirstX >= 0 && newSecondX <= 100 && newFirstY >= 0 && newSecondY <= 100) { setFirstDragable({ x: newFirstX, y: newFirstY, }); setSecondDragable({ x: newSecondX, y: newSecondY, }); } }; const pixelsToPercentage = (pixels: number, totalSize: number): number => { return totalSize > 0 ? (pixels / totalSize) * 100 : 0; }; const percentageToPixels = (percentage: number, totalSize: number): number => { return (percentage * totalSize) / 100; }; const getActualPixelDimensions = (): ContainerDimensions => { return { width: Math.round(percentageToPixels(selectorWidth, containerSize.width)), height: Math.round(percentageToPixels(selectorHeight, containerSize.height)), }; }; const writeDimensionsToURL = (): void => { setSearchParams((prev) => ({ ...prev, x1: ((firstDragable.x / 100) * containerSize.width).toFixed(), y1: ((firstDragable.y / 100) * containerSize.height).toFixed(), x2: ((secondDragable.x / 100) * containerSize.width).toFixed(), y2: ((secondDragable.y / 100) * containerSize.height).toFixed(), })); }; const getDisplayValue = (dimension: "width" | "height"): number => { const actualPixels = getActualPixelDimensions(); if (unit === "percentage") { return dimension === "width" ? selectorWidth : selectorHeight; } return dimension === "width" ? actualPixels.width : actualPixels.height; }; const handleDimensionChange = ( dimension: "width" | "height", event: React.ChangeEvent ) => { const inputValue = Math.max(0, parseFloat(event.target.value) || 0); let newPercentage: number; if (unit === "percentage") { newPercentage = Math.min(inputValue, 100); } else { // Convert pixel input to percentage const totalSize = dimension === "width" ? containerSize.width : containerSize.height; newPercentage = pixelsToPercentage(Math.min(inputValue, totalSize), totalSize); } if (dimension === "width") { const newX = Math.min(firstDragable.x, 100 - newPercentage); setFirstDragable((prev) => ({ ...prev, x: newX })); setSecondDragable((prev) => ({ ...prev, x: newX + newPercentage })); } else { const newY = Math.min(firstDragable.y, 100 - newPercentage); setFirstDragable((prev) => ({ ...prev, y: newY })); setSecondDragable((prev) => ({ ...prev, y: newY + newPercentage })); } }; return (
setUnit(value as UnitType)} className="flex gap-4 mb-2" >
) => handleDimensionChange("width", e)} className="w-24" />
handleDimensionChange("height", e)} className="w-24" />
); }