Newer
Older
import React, { useState } from "react";
import { Node } from "../../common/graph/node";
import { Coordinate2D } from "../../common/graph/graph";
interface SelectLayerProps {
children: React.ReactNode | React.ReactNode[];
nodes: Node[];
isEnabled: boolean;
screen2GraphCoords: (x: number, y: number) => Coordinate2D;
interface Box {
bottom: number;
top: number;
left: number;
right: number;
}
function SelectLayer({
children,
nodes,
onBoxSelect,
isEnabled,
screen2GraphCoords,
}: SelectLayerProps) {
const [selectionStart, setSelectionStart] =
useState<Coordinate2D>(undefined);
const [selectionEnd, setSelectionEnd] = useState<Coordinate2D>(undefined);
// Calculate the nodes included in the bounding box
const makeSelection = (bb: Box) => {
// Filter out selected nodes
const hitNodes: Node[] = [];
const tl = screen2GraphCoords(bb.left, bb.top);
const br = screen2GraphCoords(bb.right, bb.bottom);
nodes.forEach((node: Node) => {
if (
tl.x < node.x &&
node.x < br.x &&
br.y > node.y &&
node.y > tl.y
) {
// Add node if in box area
hitNodes.push(node);
}
});
const getBoundingBox = (p1: Coordinate2D, p2: Coordinate2D): Box => {
return {
left: Math.min(p1.x, p2.x),
top: Math.min(p1.y, p2.y),
right: Math.max(p1.x, p2.x),
const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {
if (
!isEnabled ||
selectionStart == undefined ||
selectionEnd == undefined
) {
e.preventDefault();
makeSelection(getBoundingBox(selectionStart, selectionEnd));
setSelectionStart(undefined);
setSelectionEnd(undefined);
};
const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
setSelectionStart({
x: e.nativeEvent.offsetX,
y: e.nativeEvent.offsetY,
});
setSelectionEnd({ x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY });
const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {
if (!isEnabled) {
return;
}
setSelectionEnd({ x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY });
let width = 0;
let height = 0;
let left = 0;
let top = 0;
if (selectionStart && selectionEnd) {
const box = getBoundingBox(selectionStart, selectionEnd);
width = box.right - box.left;
height = box.bottom - box.top;
left = box.left;
top = box.top;
return (
<div
onPointerDown={handlePointerDown}
onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp}
id="select-layer"
>
<div
id="box-select"
className={selectionStart ? "visible" : ""}
></div>
{children}
</div>
);