Created
January 29, 2024 06:28
-
-
Save lazzyms/636ddd725837dd95e1e27980de6f5d81 to your computer and use it in GitHub Desktop.
SelectionArea component in react to drag and select the area of canvas.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, useState } from "react"; | |
import { RhButton } from "@rhythm-ui/react"; | |
const SelectionArea = ({ onCancel, onCapture }) => { | |
const [startPosition, setStartPosition] = useState({ x: 0, y: 0 }); | |
const [endPosition, setEndPosition] = useState({ x: 0, y: 0 }); | |
const [selectState, setSelectState] = useState("init"); | |
const handleMouseDown = (e) => { | |
if (selectState == "init") { | |
const { clientX, clientY } = e; | |
setStartPosition({ x: clientX, y: clientY }); | |
setSelectState("selecting"); | |
} | |
}; | |
const handleMouseMove = (e) => { | |
if (selectState == "selecting") { | |
const { clientX, clientY } = e; | |
setEndPosition({ x: clientX, y: clientY }); | |
} | |
}; | |
const handleMouseUp = (e) => { | |
if (selectState == "selecting") { | |
const { clientX, clientY } = e; | |
setEndPosition({ x: clientX, y: clientY }); | |
} | |
setSelectState("stopped"); | |
}; | |
const handleCancel = (e) => { | |
e.stopPropagation(); | |
e.preventDefault(); | |
onCancel(); | |
setSelectState("init"); | |
}; | |
const handleCapture = (e) => { | |
e.stopPropagation(); | |
e.preventDefault(); | |
onCapture( | |
Math.abs(endPosition.x - startPosition.x), | |
Math.abs(endPosition.y - startPosition.y), | |
startPosition.x, | |
startPosition.y, | |
endPosition.x, | |
endPosition.y | |
); | |
setSelectState("finished"); | |
}; | |
// Function to update the position of the div | |
const updatePopupPosition = () => { | |
const popupDiv = document.querySelector(".popup-container"); | |
const popup = document.querySelector(".popup"); | |
if (popupDiv) { | |
const rect = popupDiv.getBoundingClientRect(); | |
const isOutOfViewport = rect.bottom + 45 > window.innerHeight; | |
// Update the style based on the position | |
if (isOutOfViewport) { | |
const newBottom = window.innerHeight - rect.top; | |
popup.style.bottom = `${newBottom}px`; | |
} else { | |
// Reset the style if it's within the viewport | |
popup.style.bottom = "-2.55rem"; | |
} | |
} | |
}; | |
// Call the function initially and whenever the window is resized | |
useEffect(() => { | |
if (selectState == "stopped") { | |
updatePopupPosition(); | |
} | |
}, [selectState]); | |
return ( | |
<div | |
className="fixed inset-0 cursor-crosshair" | |
style={{ | |
zIndex: 999, | |
}} | |
onMouseDown={handleMouseDown} | |
onMouseMove={handleMouseMove} | |
onMouseUp={handleMouseUp} | |
> | |
<div | |
id="selection" | |
className="absolute border border-dashed border-white bg-black/30 w-max h-full z-50 shadow-md popup-container" | |
style={{ | |
left: Math.min(startPosition.x, endPosition.x), | |
top: Math.min(startPosition.y, endPosition.y), | |
width: Math.abs(endPosition.x - startPosition.x), | |
height: Math.abs(endPosition.y - startPosition.y), | |
}} | |
> | |
{selectState == "stopped" && ( | |
<div | |
className="absolute inset-x-0 flex gap-2 z-50 w-max justify-center items-center p-1.5 rounded-md bg-neutral-700 popup" | |
style={{ bottom: "-2.50rem" }} | |
> | |
<RhButton | |
size="xs" | |
layout="outline" | |
variant="white" | |
iconLeft="material-symbols:pageshot-region" | |
className="mr-1 w-full font-sm" | |
onClick={(e) => handleCapture(e)} | |
> | |
Capture | |
</RhButton> | |
<RhButton | |
size="xs" | |
layout="outline" | |
variant="white" | |
className="mr-1 w-full font-sm" | |
onClick={() => { | |
setSelectState("init"); | |
setStartPosition({ x: 0, y: 0 }); | |
setEndPosition({ x: 0, y: 0 }); | |
}} | |
> | |
Reset | |
</RhButton> | |
<RhButton | |
size="xs" | |
layout="outline" | |
variant="white" | |
className="mr-1 w-full font-sm" | |
onClick={(e) => handleCancel(e)} | |
> | |
Cancel | |
</RhButton> | |
</div> | |
)} | |
</div> | |
</div> | |
); | |
}; | |
export default SelectionArea; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment