Forráskód Böngészése

feat: 添加画布空白双击添加节点、自动布局功能开发

liaojiaxing 1 hete
szülő
commit
7d51353399

+ 1 - 1
apps/flowchart-designer/.umirc.ts

@@ -3,7 +3,7 @@ import { defineConfig } from "umi";
 export default defineConfig({
   base: '/',
   publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
-  outputPath: 'dataModel',
+  outputPath: 'flowchartDesigner',
   esbuildMinifyIIFE: true,
   favicons: [
     '/favicon.ico'

+ 25 - 20
apps/flowchart-designer/src/components/NodeMenu.tsx

@@ -12,21 +12,22 @@ import or from "@/assets/wf_icon_or.gif";
 import { Graph, Node } from "@antv/x6";
 
 const items = [
-  { key: NodeType.START, icon: start, text: "开始" },
-  { key: NodeType.PROCESS, icon: handle, text: "处理" },
-  { key: NodeType.AUTO_PROCESS, icon: autohandle, text: "自动处理" },
-  { key: NodeType.DECISION, icon: or, text: "判断" },
-  { key: NodeType.AND, icon: and, text: "与" },
-  { key: NodeType.LINK, icon: judge, text: "连接" },
-  { key: NodeType.END, icon: end, text: "结束" },
+  { key: NodeType.START, name: "start-node", icon: start, text: "开始" },
+  { key: NodeType.PROCESS, name: "process-node", icon: handle, text: "处理" },
+  { key: NodeType.AUTO_PROCESS, name: "auto-process-node", icon: autohandle, text: "自动处理" },
+  { key: NodeType.DECISION, name: "decision-node", icon: or, text: "判断" },
+  { key: NodeType.AND, name: "and-node", icon: and, text: "与" },
+  { key: NodeType.LINK, name: "link-node", icon: judge, text: "连接" },
+  { key: NodeType.END, name: "end-node", icon: end, text: "结束" },
 ];
 
 export default function NodeMenu(props: {
   graph?: Graph;
   onChange?: (n?: Node) => void;
   position?: { x: number; y: number };
+  hideNodes?: string[];
 }) {
-  const { graph } = props;
+  const { graph, hideNodes } = props;
   // 添加节点
   const handleAddNode = (type: NodeType) => {
     const node = nodes.find((item) => item.type === type);
@@ -73,18 +74,22 @@ export default function NodeMenu(props: {
 
   return (
     <div className="w-280px flex flex-wrap gap-[8px 12px]">
-      {items.map((item) => {
-        return (
-          <div
-            className="w-[38%] border-box h-40px px-12px rounded-8px flex items-center cursor-pointer hover:bg-#eff0f8"
-            key={item.key}
-            onClick={(e) => {handleAddNode(item.key)}}
-          >
-            <img src={item.icon} className="w-24px" />
-            <span>{item.text}</span>
-          </div>
-        );
-      })}
+      {items
+        .filter((item) => !hideNodes?.includes(item.name))
+        .map((item) => {
+          return (
+            <div
+              className="w-[38%] border-box h-40px px-12px rounded-8px flex items-center cursor-pointer hover:bg-#eff0f8"
+              key={item.key}
+              onClick={(e) => {
+                handleAddNode(item.key);
+              }}
+            >
+              <img src={item.icon} className="w-24px" />
+              <span>{item.text}</span>
+            </div>
+          );
+        })}
     </div>
   );
 }

+ 2 - 0
apps/flowchart-designer/src/components/nodes/PopoverNode.tsx

@@ -10,6 +10,7 @@ export default function PopoverNode({
   node: Node;
   graph: Graph;
 }) {
+  const { hideNodes = [] } = node.getData();
   const handleChange = (addNode?: Node) => {
     node.prop("addedNode", { addNode });
   };
@@ -33,6 +34,7 @@ export default function PopoverNode({
             graph={graph}
             onChange={handleChange}
             position={node.position()}
+            hideNodes={hideNodes}
           />
         }
         getPopupContainer={(n) => n}

+ 10 - 3
apps/flowchart-designer/src/components/nodes/Port.tsx

@@ -58,7 +58,9 @@ export default function Port(props: {
         if (!isMove.current && node) {
           isMove.current = true;
           const ports = node.getPorts();
-          const rightPort = ports.find((item) => type ? item.group === 'bottom' : item.group === "right");
+          const rightPort = ports.find((item) =>
+            type ? item.group === "bottom" : item.group === "right"
+          );
           newEdge.current = graph?.addEdge({
             source: { cell: node.id, port: rightPort?.id },
             router: {
@@ -140,6 +142,9 @@ export default function Port(props: {
           shape: "menu-popover",
           x: args.x,
           y: args.y,
+          data: {
+            hideNodes: ['start-node'], // 隐藏节点
+          },
         });
       }
     });
@@ -184,7 +189,9 @@ export default function Port(props: {
     setOpen(false);
     if (addNode && node) {
       const sourcePorts = node?.getPorts();
-      const sourcePort = sourcePorts?.find((item) => type ? item.group === 'bottom' : item.group === "right");
+      const sourcePort = sourcePorts?.find((item) =>
+        type ? item.group === "bottom" : item.group === "right"
+      );
       const targetPorts = addNode?.getPorts();
       const targetPort = targetPorts?.find((item) => item.group === "left");
 
@@ -242,7 +249,7 @@ export default function Port(props: {
               : "scale(1) translateY(-50%) rotate(45deg)",
             width: 16,
             height: 16,
-            border: 'none',
+            border: "none",
             borderRadius: 0,
             ...style,
           }}

+ 34 - 5
apps/flowchart-designer/src/pages/designer/components/Toolbar/index.tsx

@@ -2,8 +2,6 @@ import {
   FileAddOutlined,
   LayoutOutlined,
   PlusCircleFilled,
-  RedoOutlined,
-  UndoOutlined,
   ZoomInOutlined,
   ZoomOutOutlined,
 } from "@ant-design/icons";
@@ -13,6 +11,7 @@ import type { MenuProps } from "antd/lib";
 import { useRef, useEffect, useState } from "react";
 import { MiniMap } from "@antv/x6-plugin-minimap";
 import { useModel } from "umi";
+import { DagreLayout } from "@antv/layout";
 
 export default function index() {
   const minimapRef = useRef<HTMLDivElement>(null);
@@ -48,7 +47,7 @@ export default function index() {
     }
   }, [graph, minimapRef.current]);
 
-  // 添加备注
+  // 添加备注节点
   const handleAddNotice = () => {
     const { width = 100, height = 100 } = graph?.getGraphArea() || {};
     graph?.addNode({
@@ -79,11 +78,37 @@ export default function index() {
     graph?.zoomToFit({});
   };
 
+  // 设置缩放值
   const handleOnChange = (value: number) => {
     setScale(Math.round(value));
     handleZoom(value);
   };
 
+  // 自动布局
+  const handleAutoLayout = () => {
+    // 获取全部元素
+    const nodes = graph?.getNodes();
+    const edges = graph?.getEdges();
+
+    const dagreLayout = new DagreLayout({
+      type: "dagre",
+      rankdir: "LR",
+      align: "UR",
+      ranksep: 35,
+      nodesep: 15,
+      // begin: [0, 0]
+    });
+
+    const model = dagreLayout.layout({
+      nodes,
+      edges
+    });
+
+    // graph?.fromJSON(model);
+
+    console.log( nodes, edges, model);
+  };
+
   return (
     <div className="absolute left-32px bottom-32px z-2 flex gap-12px">
       <div className="w-120px h-40px rounded-12px bg-#fff box-shadow-sm flex items-center justify-between px-12px">
@@ -152,8 +177,12 @@ export default function index() {
           <Button type="text" icon={<i className="iconfont icon-shou1" />} />
         </Tooltip>
         <Divider type="vertical" />
-        <Tooltip title="调整布局">
-          <Button type="text" icon={<LayoutOutlined />} />
+        <Tooltip title="自动布局">
+          <Button
+            type="text"
+            icon={<LayoutOutlined />}
+            onClick={handleAutoLayout}
+          />
         </Tooltip>
       </div>
     </div>

+ 4 - 1
apps/flowchart-designer/src/pages/designer/index.tsx

@@ -2,16 +2,19 @@ import { useRef, useEffect } from 'react';
 import { useModel } from 'umi';
 import Header from "./components/Header";
 import ToolBar from "./components/Toolbar";
+import { useEvent } from "./useEvent";
 
 export default function index() {
   const ref = useRef<HTMLDivElement>(null);
-  const { init } = useModel('flowModel');
+  const { init, graph } = useModel('flowModel');
 
   useEffect(() => {
     if (!ref.current) return;
     init(ref.current);
   }, []);
 
+  useEvent(graph);
+
   return (
     <div className='w-100vw h-100vh flex flex-col overflow-hidden'>
       <div className="w-full h-60px bg-#ffffff border-b border-#eaeaea border-b-solid box-shadow-sm">

+ 9 - 0
apps/flowchart-designer/src/pages/designer/modals/index.tsx

@@ -0,0 +1,9 @@
+import React from 'react'
+
+export default function ConfigModal() {
+  return (
+    <div>
+      
+    </div>
+  )
+}

+ 17 - 0
apps/flowchart-designer/src/pages/designer/useEvent.ts

@@ -0,0 +1,17 @@
+import { Graph } from "@antv/x6";
+import { useEffect } from "react";
+
+export const useEvent = (graph?: Graph) => { 
+  useEffect(() => { 
+    // 空白双击-添加节点
+    graph?.on("blank:dblclick", args => {
+      graph.addNode({
+        shape: "menu-popover",
+        x: args.x,
+        y: args.y
+      });
+    });
+    
+  }, [graph]);
+
+}

+ 1 - 0
package.json

@@ -22,6 +22,7 @@
     "@ant-design/pro-components": "^2.8.7",
     "@ant-design/x": "^1.1.0",
     "@antv/hierarchy": "^0.6.14",
+    "@antv/layout": "0.3.25",
     "@antv/x6": "^2.18.1",
     "@antv/x6-plugin-clipboard": "^2.1.6",
     "@antv/x6-plugin-dnd": "^2.1.1",

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2577 - 2351
pnpm-lock.yaml