import React, { useRef, useState } from "react"; import { useDrop } from "react-dnd"; import Rect from "./rect"; import Node from "./node"; export default function Canvas(props) { const [dragging, setDragging] = useState(-1); const [offset, setOffset] = useState({ x: 0, y: 0 }); 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 handleMouseDownRect = (e, id) => { const { clientX, clientY } = e; const rectangle = props.rectangles.find((rect) => rect.id === id); setOffset({ x: clientX - rectangle.x, y: clientY - rectangle.y, }); setDragging(id); }; const handleMouseMove = (e) => { if (dragging < 0 && panning) { const dx = e.clientX - panOffset.x; const dy = e.clientY - panOffset.y; setPanOffset({ x: e.clientX, y: e.clientY }); const updatedRectangles = props.rectangles.map((rect) => ({ ...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"); } } }; const handleMouseUp = () => { setDragging(-1); setPanning(false); setCursor("default"); }; const deleteTable = (id) => { const updatedTables = [...props.rectangles]; updatedTables.splice(id, 1); props.setRectangles(updatedTables); }; const [, drop] = useDrop( () => ({ accept: "CARD", drop: (item, monitor) => { const offset = monitor.getClientOffset(); const canvasRect = canvas.current.getBoundingClientRect(); const x = offset.x - canvasRect.left - 100 * 0.5; const y = offset.y - canvasRect.top - 100 * 0.5; const newRectangle = { id: props.rectangles.length + 1, x, y, width: 240, height: 100, label: `rect ${props.rectangles.length + 1}`, }; props.setRectangles([...props.rectangles, newRectangle]); props.setCode((prev) => prev === "" ? `CREATE TABLE \`${newRectangle.label}\`;` : `${prev}\n\nCREATE TABLE \`${newRectangle.label}\`;` ); }, collect: (monitor) => ({ isOver: !!monitor.isOver(), }), }), [props.rectangles] ); return (
{props.rectangles.map((rectangle, i) => ( handleMouseDownRect(e, rectangle.id)} onDelete={deleteTable} /> ))} {links.map( (link, index) => links.length >= 2 && index % 2 === 0 && index + 1 < links.length && ( ) )}
); }