|
@@ -1,6 +1,6 @@
|
|
|
import { PlusOutlined } from "@ant-design/icons";
|
|
|
-import { Graph, Node } from "@antv/x6";
|
|
|
-import React from "react";
|
|
|
+import { Edge, EventArgs, Graph, Node } from "@antv/x6";
|
|
|
+import React, { useEffect, useRef } from "react";
|
|
|
import { Dropdown, Popover } from "antd";
|
|
|
import NodeMenu from "../NodeMenu";
|
|
|
|
|
@@ -13,6 +13,10 @@ export default function Port(props: {
|
|
|
}) {
|
|
|
const { hovered, style = {}, out = true, node, graph } = props;
|
|
|
const [canAdd, setCanAdd] = React.useState(false);
|
|
|
+ const [open, setOpen] = React.useState(false);
|
|
|
+ const isDown = useRef(false);
|
|
|
+ const isMove = useRef(false);
|
|
|
+ const newEdge = React.useRef<Edge>();
|
|
|
|
|
|
const extraStyle = React.useMemo(() => {
|
|
|
if (out && canAdd) {
|
|
@@ -29,28 +33,152 @@ export default function Port(props: {
|
|
|
graph?.togglePanning(!value);
|
|
|
};
|
|
|
|
|
|
- const handleClickPort = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
|
+ const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
|
+ isDown.current = true;
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
|
|
|
|
+ }
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ graph?.on("node:mouseup", (args) => {
|
|
|
+ console.log("node:mouseup");
|
|
|
+ isDown.current = false;
|
|
|
+ isMove.current = false;
|
|
|
+ // 拖拽过程中释放鼠标 检测当前是否有节点
|
|
|
+ if(newEdge.current) {
|
|
|
+ // 检测当前位置是否有元素
|
|
|
+ const nodes = graph.getNodesInArea(args.x, args.y, 5, 5);
|
|
|
+ if(!nodes.length) {
|
|
|
+ console.log('展示添加菜单')
|
|
|
+ graph.addNode({
|
|
|
+ shape: 'menu-popover',
|
|
|
+ x: args.x,
|
|
|
+ y: args.y,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 检测移动 添加边 设置边目标位置
|
|
|
+ graph?.on("node:mousemove", (args) => {
|
|
|
+ if(isDown.current) {
|
|
|
+ // 按下还没移动时创建边
|
|
|
+ if(!isMove.current && node) {
|
|
|
+ isMove.current = true;
|
|
|
+ const ports = node.getPorts();
|
|
|
+ const rightPort = ports.find(item => item.group === 'right');
|
|
|
+ newEdge.current = graph?.addEdge({
|
|
|
+ source: { cell: node.id, port: rightPort?.id},
|
|
|
+ connector: { name: 'smooth' },
|
|
|
+ target: {
|
|
|
+ x: args.x,
|
|
|
+ y: args.y
|
|
|
+ },
|
|
|
+ attrs: {
|
|
|
+ line: {
|
|
|
+ stroke: "#37d0ff",
|
|
|
+ strokeWidth: 2,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 否则修改边的终点
|
|
|
+ newEdge.current?.setTarget({
|
|
|
+ x: args.x,
|
|
|
+ y: args.y
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 连续添加节点完成
|
|
|
+ graph?.on("node:change:addedNode", (args: EventArgs["cell:change:*"]) => {
|
|
|
+ const { current } = args;
|
|
|
+ if(newEdge.current && current) {
|
|
|
+ const addNode = current?.addNode as Node;
|
|
|
+ const ports = addNode.getPorts();
|
|
|
+ const leftPort = ports?.find(item => item.group === 'left');
|
|
|
+ newEdge.current.setTarget({
|
|
|
+ cell: addNode.id,
|
|
|
+ port: leftPort?.id
|
|
|
+ });
|
|
|
+ newEdge.current.setAttrs({
|
|
|
+ line: {
|
|
|
+ stroke: '#1b5cdf',
|
|
|
+ },
|
|
|
+ });
|
|
|
+ newEdge.current = undefined;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 连续添加popver关闭
|
|
|
+ graph?.on("node:change:closedPopover", () => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if(Object.hasOwn(newEdge.current?.target || {}, 'x')) {
|
|
|
+ graph?.removeCells([newEdge.current!]);
|
|
|
+ newEdge.current = undefined;
|
|
|
+ }
|
|
|
+ }, 100);
|
|
|
+ });
|
|
|
+ }, [graph]);
|
|
|
+
|
|
|
+ const {x, y} = node?.position() || {x: 0, y: 0};
|
|
|
+ const x1 = (node?.getBBox()?.width || 0) + x + 50;
|
|
|
+
|
|
|
+ const handleAddChange = (addNode?: Node) => {
|
|
|
+ setOpen(false);
|
|
|
+ if(addNode && node) {
|
|
|
+
|
|
|
+ const sourcePorts = node?.getPorts();
|
|
|
+ const sourcePort = sourcePorts?.find(item => item.group === 'right');
|
|
|
+ const targetPorts = addNode?.getPorts();
|
|
|
+ const targetPort = targetPorts?.find(item => item.group === 'left');
|
|
|
+
|
|
|
+ graph?.addEdge({
|
|
|
+ source: {
|
|
|
+ cell: node.id,
|
|
|
+ port: sourcePort?.id
|
|
|
+ },
|
|
|
+ target: {
|
|
|
+ cell: addNode.id,
|
|
|
+ port: targetPort?.id
|
|
|
+ },
|
|
|
+ connector: { name: 'smooth' },
|
|
|
+ attrs: {
|
|
|
+ line: {
|
|
|
+ stroke: '#1b5cdf',
|
|
|
+ strokeWidth: 2,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
return (
|
|
|
<Popover
|
|
|
- content={<NodeMenu graph={graph} />}
|
|
|
- trigger="click"
|
|
|
+ content={<NodeMenu graph={graph} onChange={handleAddChange} position={{ x: x1, y}} />}
|
|
|
+ trigger={"click"}
|
|
|
placement="right"
|
|
|
arrow={false}
|
|
|
+ open={open}
|
|
|
+ onOpenChange={(open) => {
|
|
|
+ setOpen(open);
|
|
|
+ }}
|
|
|
>
|
|
|
<div
|
|
|
className="node-port flex items-center justify-center"
|
|
|
style={{
|
|
|
- transform: hovered ? "scale(1.5) translateY(-50%)" : "scale(1) translateY(-50%)",
|
|
|
+ transform: hovered ? "scale(1.2) translateY(-50%)" : "scale(1) translateY(-50%)",
|
|
|
opacity: hovered ? 1 : 0.5,
|
|
|
...style,
|
|
|
...extraStyle
|
|
|
}}
|
|
|
onMouseEnter={() => handleSetCanAdd(true)}
|
|
|
onMouseLeave={() => handleSetCanAdd(false)}
|
|
|
- onClick={handleClickPort}
|
|
|
+ onMouseDown={handleMouseDown}
|
|
|
+ onMouseMove={handleMouseMove}
|
|
|
>
|
|
|
{ out && <PlusOutlined
|
|
|
className="transform scale-0 transition duration-300 color-#fff text-8px"
|