panning :D

This commit is contained in:
1ilit 2023-09-19 15:47:13 +03:00
parent 45963eafdb
commit 5c62a71ebd
2 changed files with 98 additions and 60 deletions

View File

@ -4,14 +4,18 @@ import Rect from "./rect";
import Node from "./node"; import Node from "./node";
export default function Canvas(props) { export default function Canvas(props) {
const [dragging, setDragging] = useState(false); const [dragging, setDragging] = useState(-1);
const [offset, setOffset] = useState({ x: 0, y: 0 }); const [offset, setOffset] = useState({ x: 0, y: 0 });
const [links, setLinks] = useState([]); const [links, setLinks] = useState([]);
const [onRect, setOnRect] = useState(false);
const [panning, setPanning] = useState(false);
const [panOffset, setPanOffset] = useState({ x: 0, y: 0 });
const [cursor, setCursor] = useState("default");
const canvas = useRef(null); const canvas = useRef(null);
const handleMouseDown = (event, id) => { const handleMouseDownRect = (e, id) => {
const { clientX, clientY } = event; const { clientX, clientY } = e;
const rectangle = props.rectangles.find((rect) => rect.id === id); const rectangle = props.rectangles.find((rect) => rect.id === id);
setOffset({ setOffset({
x: clientX - rectangle.x, x: clientX - rectangle.x,
@ -20,65 +24,96 @@ export default function Canvas(props) {
setDragging(id); setDragging(id);
}; };
const handleMouseMove = (event) => { const handleMouseMove = (e) => {
if (dragging === false) return; if (dragging < 0 && panning) {
const { clientX, clientY } = event; const dx = e.clientX - panOffset.x;
const updatedRectangles = props.rectangles.map((rect) => { const dy = e.clientY - panOffset.y;
if (rect.id === dragging) { setPanOffset({ x: e.clientX, y: e.clientY });
const updatedRect = {
...rect,
x: clientX - offset.x,
y: clientY - offset.y,
};
const updatedLinks = links.map((link) => {
let updatedLink = link;
if (link.rect === updatedRect.id) {
switch (link.node) {
case Node.TOP:
updatedLink = {
...link,
x: updatedRect.x + updatedRect.width / 2,
y: updatedRect.y,
};
break;
case Node.BOTTOM:
updatedLink = {
...link,
x: updatedRect.x + updatedRect.width / 2,
y: updatedRect.y + updatedRect.height,
};
break;
case Node.LEFT:
updatedLink = {
...link,
x: updatedRect.x,
y: updatedRect.y + updatedRect.height / 2,
};
break;
case Node.RIGHT:
updatedLink = {
...link,
x: updatedRect.x + updatedRect.width,
y: updatedRect.y + updatedRect.height / 2,
};
break;
default:
break;
}
}
return updatedLink;
});
setLinks(updatedLinks); const updatedRectangles = props.rectangles.map((rect) => ({
return updatedRect; ...rect,
x: rect.x + dx,
y: rect.y + dy,
}));
props.setRectangles(updatedRectangles);
const updatedLinks = links.map((link) => ({
...link,
x: link.x + dx,
y: link.y + dy,
}));
setLinks(updatedLinks);
} else if (dragging >= 0) {
const { clientX, clientY } = e;
const updatedRectangles = props.rectangles.map((rect) => {
if (rect.id === dragging) {
const updatedRect = {
...rect,
x: clientX - offset.x,
y: clientY - offset.y,
};
const updatedLinks = links.map((link) => {
let updatedLink = link;
if (link.rect === updatedRect.id) {
switch (link.node) {
case Node.TOP:
updatedLink = {
...link,
x: updatedRect.x + updatedRect.width / 2,
y: updatedRect.y,
};
break;
case Node.BOTTOM:
updatedLink = {
...link,
x: updatedRect.x + updatedRect.width / 2,
y: updatedRect.y + updatedRect.height,
};
break;
case Node.LEFT:
updatedLink = {
...link,
x: updatedRect.x,
y: updatedRect.y + updatedRect.height / 2,
};
break;
case Node.RIGHT:
updatedLink = {
...link,
x: updatedRect.x + updatedRect.width,
y: updatedRect.y + updatedRect.height / 2,
};
break;
default:
break;
}
}
return updatedLink;
});
setLinks(updatedLinks);
return updatedRect;
}
return rect;
});
props.setRectangles(updatedRectangles);
}
};
const handleMouseDown = (e) => {
if (dragging < 0) {
if (!onRect) {
setPanning(true);
setPanOffset({ x: e.clientX, y: e.clientY });
setCursor("grabbing");
} }
return rect; }
});
props.setRectangles(updatedRectangles);
}; };
const handleMouseUp = () => { const handleMouseUp = () => {
setDragging(false); setDragging(-1);
setPanning(false);
setCursor("default");
}; };
const [, drop] = useDrop( const [, drop] = useDrop(
@ -110,14 +145,14 @@ export default function Canvas(props) {
}), }),
[props.rectangles] [props.rectangles]
); );
return ( return (
<div ref={drop} className="flex-grow" id="canvas"> <div ref={drop} className="flex-grow" id="canvas">
<div ref={canvas} className="w-full h-screen"> <div ref={canvas} className="w-full h-screen">
<svg <svg
onMouseMove={handleMouseMove} onMouseMove={handleMouseMove}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp} onMouseUp={handleMouseUp}
style={{ width: "100%", height: "100%" }} style={{ width: "100%", height: "100%", cursor: cursor }}
> >
{props.rectangles.map((rectangle) => ( {props.rectangles.map((rectangle) => (
<Rect <Rect
@ -128,9 +163,10 @@ export default function Canvas(props) {
label={rectangle.label} label={rectangle.label}
width={rectangle.width} width={rectangle.width}
height={rectangle.height} height={rectangle.height}
setOnRect={setOnRect}
links={links} links={links}
setLinks={setLinks} setLinks={setLinks}
onMouseDown={(event) => handleMouseDown(event, rectangle.id)} onMouseDown={(e) => handleMouseDownRect(e, rectangle.id)}
/> />
))} ))}
{links.map( {links.map(

View File

@ -18,9 +18,11 @@ const Rect = (props) => {
onMouseDown={props.onMouseDown} onMouseDown={props.onMouseDown}
onMouseEnter={() => { onMouseEnter={() => {
setIsHovered(true); setIsHovered(true);
props.setOnRect(true);
}} }}
onMouseLeave={() => { onMouseLeave={() => {
setIsHovered(false); setIsHovered(false);
props.setOnRect(false);
}} }}
> >
<div <div