Skip to content

Instantly share code, notes, and snippets.

@lazzyms
Created January 29, 2024 06:28
Show Gist options
  • Save lazzyms/636ddd725837dd95e1e27980de6f5d81 to your computer and use it in GitHub Desktop.
Save lazzyms/636ddd725837dd95e1e27980de6f5d81 to your computer and use it in GitHub Desktop.
SelectionArea component in react to drag and select the area of canvas.
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