link rects with lines

This commit is contained in:
1ilit 2023-09-19 15:47:11 +03:00
parent 65a33e1fc3
commit 7dd588378b
3 changed files with 163 additions and 4 deletions

View File

@ -1,10 +1,12 @@
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(false);
const [offset, setOffset] = useState({ x: 0, y: 0 });
const [links, setLinks] = useState([]);
const canvas = useRef(null);
@ -23,11 +25,52 @@ export default function Canvas(props) {
const { clientX, clientY } = event;
const updatedRectangles = props.rectangles.map((rect) => {
if (rect.id === dragging) {
return {
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;
});
@ -84,9 +127,27 @@ export default function Canvas(props) {
label={rectangle.label}
width={rectangle.width}
height={rectangle.height}
links={links}
setLinks={setLinks}
onMouseDown={(event) => handleMouseDown(event, rectangle.id)}
/>
))}
{links.map(
(link, index) =>
links.length >= 2 &&
index % 2 === 0 &&
index + 1 < links.length && (
<line
key={index}
x1={links[index].x}
y1={links[index].y}
x2={links[index + 1].x}
y2={links[index + 1].y}
stroke="red"
strokeDasharray="5,5"
/>
)
)}
</svg>
</div>
</div>

9
src/components/node.js Normal file
View File

@ -0,0 +1,9 @@
const Node = {
NONE: "NONE",
TOP: "TOP",
LEFT: "LEFT",
RIGHT: "RIGHT",
BOTTOM: "BOTTOM",
};
export default Node;

View File

@ -1,7 +1,11 @@
import React from "react";
import { React, useState } from "react";
import Node from "./node";
import { Button } from "@arco-design/web-react";
const Rect = (props) => {
const [isHovered, setIsHovered] = useState(false);
const [node, setNode] = useState(Node.NONE);
return (
<g>
<foreignObject
@ -10,10 +14,19 @@ const Rect = (props) => {
y={props.y}
width={props.width}
height={props.height}
style={{ fill: "blue", cursor: "move" }}
style={{ cursor: "move" }}
onMouseDown={props.onMouseDown}
onMouseEnter={() => {
setIsHovered(true);
}}
onMouseLeave={() => {
setIsHovered(false);
}}
>
<div
xmlns="http://www.w3.org/1999/xhtml"
className={`${isHovered ? "bg-red-500" : "bg-blue"} p-3`}
>
<div xmlns="http://www.w3.org/1999/xhtml" className="bg-blue p-3">
<div className="text-white">{props.label}</div>
<form onSubmit={(e) => e.preventDefault()}>
<input type="text" className="w-full" />
@ -23,6 +36,82 @@ const Rect = (props) => {
</Button>
</div>
</foreignObject>
<circle
id="TOP"
cx={props.x + props.width / 2}
cy={props.y}
r={5}
onClick={(e) => {
setNode(Node.TOP);
props.setLinks([
...props.links,
{
rect: props.id,
node: Node.TOP,
x: props.x + props.width / 2,
y: props.y,
},
]);
}}
style={{ fill: node === Node.TOP ? "green" : "black" }}
/>
<circle
id="LEFT"
cx={props.x}
cy={props.y + props.height / 2}
r={5}
onClick={(e) => {
setNode(Node.LEFT);
props.setLinks([
...props.links,
{
rect: `${props.id}`,
node: Node.LEFT,
x: props.x,
y: props.y + props.height / 2,
},
]);
}}
style={{ fill: node === Node.LEFT ? "green" : "black" }}
/>
<circle
id="RIGHT"
cx={props.x + props.width}
cy={props.y + props.height / 2}
r={5}
onClick={(e) => {
setNode(Node.RIGHT);
props.setLinks([
...props.links,
{
rect: props.id,
node: Node.RIGHT,
x: props.x + props.width,
y: props.y + props.height / 2,
},
]);
}}
style={{ fill: node === Node.RIGHT ? "green" : "black" }}
/>
<circle
id="BOTTOM"
cx={props.x + props.width / 2}
cy={props.y + props.height}
r={5}
onClick={(e) => {
setNode(Node.BOTTOM);
props.setLinks([
...props.links,
{
rect: props.id,
node: Node.BOTTOM,
x: props.x + props.width / 2,
y: props.y + props.height,
},
]);
}}
style={{ fill: node === Node.BOTTOM ? "green" : "black" }}
/>
</g>
);
};