Parcourir la source

无自动布局

shaogen1995 il y a 2 jours
Parent
commit
584f5f1f63

+ 106 - 0
project/package-lock.json

@@ -19,6 +19,7 @@
         "@types/node": "^16.18.3",
         "@types/node": "^16.18.3",
         "@types/react": "^18.0.24",
         "@types/react": "^18.0.24",
         "@types/react-dom": "^18.0.8",
         "@types/react-dom": "^18.0.8",
+        "@xyflow/react": "^12.10.1",
         "antd": "^5.8.3",
         "antd": "^5.8.3",
         "antd-mobile": "^5.30.0",
         "antd-mobile": "^5.30.0",
         "axios": "^1.13.2",
         "axios": "^1.13.2",
@@ -5021,6 +5022,38 @@
       "resolved": "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz",
       "resolved": "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz",
       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
     },
     },
+    "node_modules/@xyflow/react": {
+      "version": "12.10.1",
+      "resolved": "https://registry.npmmirror.com/@xyflow/react/-/react-12.10.1.tgz",
+      "integrity": "sha512-5eSWtIK/+rkldOuFbOOz44CRgQRjtS9v5nufk77DV+XBnfCGL9HAQ8PG00o2ZYKqkEU/Ak6wrKC95Tu+2zuK3Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@xyflow/system": "0.0.75",
+        "classcat": "^5.0.3",
+        "zustand": "^4.4.0"
+      },
+      "peerDependencies": {
+        "react": ">=17",
+        "react-dom": ">=17"
+      }
+    },
+    "node_modules/@xyflow/system": {
+      "version": "0.0.75",
+      "resolved": "https://registry.npmmirror.com/@xyflow/system/-/system-0.0.75.tgz",
+      "integrity": "sha512-iXs+AGFLi8w/VlAoc/iSxk+CxfT6o64Uw/k0CKASOPqjqz6E0rb5jFZgJtXGZCpfQI6OQpu5EnumP5fGxQheaQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/d3-drag": "^3.0.7",
+        "@types/d3-interpolate": "^3.0.4",
+        "@types/d3-selection": "^3.0.10",
+        "@types/d3-transition": "^3.0.8",
+        "@types/d3-zoom": "^3.0.8",
+        "d3-drag": "^3.0.0",
+        "d3-interpolate": "^3.0.1",
+        "d3-selection": "^3.0.0",
+        "d3-zoom": "^3.0.0"
+      }
+    },
     "node_modules/abab": {
     "node_modules/abab": {
       "version": "2.0.6",
       "version": "2.0.6",
       "resolved": "https://registry.npmmirror.com/abab/-/abab-2.0.6.tgz",
       "resolved": "https://registry.npmmirror.com/abab/-/abab-2.0.6.tgz",
@@ -6288,6 +6321,12 @@
       "resolved": "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz",
       "resolved": "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz",
       "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA=="
       "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA=="
     },
     },
+    "node_modules/classcat": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmmirror.com/classcat/-/classcat-5.0.5.tgz",
+      "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==",
+      "license": "MIT"
+    },
     "node_modules/classnames": {
     "node_modules/classnames": {
       "version": "2.5.1",
       "version": "2.5.1",
       "resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz",
       "resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz",
@@ -18958,6 +18997,34 @@
       "engines": {
       "engines": {
         "node": ">=10"
         "node": ">=10"
       }
       }
+    },
+    "node_modules/zustand": {
+      "version": "4.5.7",
+      "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.7.tgz",
+      "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==",
+      "license": "MIT",
+      "dependencies": {
+        "use-sync-external-store": "^1.2.2"
+      },
+      "engines": {
+        "node": ">=12.7.0"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.8",
+        "immer": ">=9.0.6",
+        "react": ">=16.8"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "immer": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        }
+      }
     }
     }
   },
   },
   "dependencies": {
   "dependencies": {
@@ -22644,6 +22711,32 @@
       "resolved": "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz",
       "resolved": "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz",
       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
     },
     },
+    "@xyflow/react": {
+      "version": "12.10.1",
+      "resolved": "https://registry.npmmirror.com/@xyflow/react/-/react-12.10.1.tgz",
+      "integrity": "sha512-5eSWtIK/+rkldOuFbOOz44CRgQRjtS9v5nufk77DV+XBnfCGL9HAQ8PG00o2ZYKqkEU/Ak6wrKC95Tu+2zuK3Q==",
+      "requires": {
+        "@xyflow/system": "0.0.75",
+        "classcat": "^5.0.3",
+        "zustand": "^4.4.0"
+      }
+    },
+    "@xyflow/system": {
+      "version": "0.0.75",
+      "resolved": "https://registry.npmmirror.com/@xyflow/system/-/system-0.0.75.tgz",
+      "integrity": "sha512-iXs+AGFLi8w/VlAoc/iSxk+CxfT6o64Uw/k0CKASOPqjqz6E0rb5jFZgJtXGZCpfQI6OQpu5EnumP5fGxQheaQ==",
+      "requires": {
+        "@types/d3-drag": "^3.0.7",
+        "@types/d3-interpolate": "^3.0.4",
+        "@types/d3-selection": "^3.0.10",
+        "@types/d3-transition": "^3.0.8",
+        "@types/d3-zoom": "^3.0.8",
+        "d3-drag": "^3.0.0",
+        "d3-interpolate": "^3.0.1",
+        "d3-selection": "^3.0.0",
+        "d3-zoom": "^3.0.0"
+      }
+    },
     "abab": {
     "abab": {
       "version": "2.0.6",
       "version": "2.0.6",
       "resolved": "https://registry.npmmirror.com/abab/-/abab-2.0.6.tgz",
       "resolved": "https://registry.npmmirror.com/abab/-/abab-2.0.6.tgz",
@@ -23653,6 +23746,11 @@
       "resolved": "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz",
       "resolved": "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz",
       "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA=="
       "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA=="
     },
     },
+    "classcat": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmmirror.com/classcat/-/classcat-5.0.5.tgz",
+      "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w=="
+    },
     "classnames": {
     "classnames": {
       "version": "2.5.1",
       "version": "2.5.1",
       "resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz",
       "resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz",
@@ -33247,6 +33345,14 @@
       "version": "0.1.0",
       "version": "0.1.0",
       "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",
       "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",
       "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
       "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
+    },
+    "zustand": {
+      "version": "4.5.7",
+      "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.7.tgz",
+      "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==",
+      "requires": {
+        "use-sync-external-store": "^1.2.2"
+      }
     }
     }
   }
   }
 }
 }

+ 1 - 0
project/package.json

@@ -14,6 +14,7 @@
     "@types/node": "^16.18.3",
     "@types/node": "^16.18.3",
     "@types/react": "^18.0.24",
     "@types/react": "^18.0.24",
     "@types/react-dom": "^18.0.8",
     "@types/react-dom": "^18.0.8",
+    "@xyflow/react": "^12.10.1",
     "antd": "^5.8.3",
     "antd": "^5.8.3",
     "antd-mobile": "^5.30.0",
     "antd-mobile": "^5.30.0",
     "axios": "^1.13.2",
     "axios": "^1.13.2",

+ 10 - 0
project/public/three/data.js

@@ -8,6 +8,7 @@ const cardNames = [
     id: 1,
     id: 1,
     name: '文物的名称1',
     name: '文物的名称1',
     img: '1.png',
     img: '1.png',
+    position: { x: 0, y: 0 },
     obj: { 构件: '构件1', 位置: '位置1', 装饰: '装饰1', 材质: '材质1' },
     obj: { 构件: '构件1', 位置: '位置1', 装饰: '装饰1', 材质: '材质1' },
     type: '分类二',
     type: '分类二',
     lines: [
     lines: [
@@ -20,6 +21,7 @@ const cardNames = [
     id: 2,
     id: 2,
     name: '文物的名称2',
     name: '文物的名称2',
     img: '2.png',
     img: '2.png',
+    position: { x: 100, y: 100 },
     obj: { 构件: '构件2', 位置: '位置2', 装饰: '装饰2', 材质: '材质2' },
     obj: { 构件: '构件2', 位置: '位置2', 装饰: '装饰2', 材质: '材质2' },
     type: '分类二',
     type: '分类二',
     lines: [
     lines: [
@@ -32,6 +34,7 @@ const cardNames = [
     id: 3,
     id: 3,
     name: '文物的名称3',
     name: '文物的名称3',
     img: '3.png',
     img: '3.png',
+    position: { x: 200, y: 200 },
     obj: { 构件: '构件3', 位置: '位置3', 装饰: '装饰3', 材质: '材质3' },
     obj: { 构件: '构件3', 位置: '位置3', 装饰: '装饰3', 材质: '材质3' },
     type: '分类二'
     type: '分类二'
   },
   },
@@ -39,6 +42,7 @@ const cardNames = [
     id: 4,
     id: 4,
     name: '文物的名称4',
     name: '文物的名称4',
     img: '4.png',
     img: '4.png',
+    position: { x: 300, y: 300 },
     obj: { 构件: '构件4', 位置: '位置4', 装饰: '装饰4', 材质: '材质4' },
     obj: { 构件: '构件4', 位置: '位置4', 装饰: '装饰4', 材质: '材质4' },
     type: '分类二',
     type: '分类二',
     lines: [
     lines: [
@@ -51,6 +55,7 @@ const cardNames = [
     id: 5,
     id: 5,
     name: '文物的名称5',
     name: '文物的名称5',
     img: '5.png',
     img: '5.png',
+    position: { x: 400, y: 400 },
     obj: { 构件: '构件5', 位置: '位置5', 装饰: '装饰5', 材质: '材质5' },
     obj: { 构件: '构件5', 位置: '位置5', 装饰: '装饰5', 材质: '材质5' },
     type: '分类一'
     type: '分类一'
   },
   },
@@ -58,6 +63,7 @@ const cardNames = [
     id: 6,
     id: 6,
     name: '文物的名称6',
     name: '文物的名称6',
     img: '6.png',
     img: '6.png',
+    position: { x: 500, y: 500 },
     obj: { 构件: '构件6', 位置: '位置6', 装饰: '装饰6', 材质: '材质6' },
     obj: { 构件: '构件6', 位置: '位置6', 装饰: '装饰6', 材质: '材质6' },
     type: '分类一'
     type: '分类一'
   },
   },
@@ -65,6 +71,7 @@ const cardNames = [
     id: 7,
     id: 7,
     name: '文物的名称7',
     name: '文物的名称7',
     img: '7.png',
     img: '7.png',
+    position: { x: 600, y: 600 },
     obj: { 构件: '构件7', 位置: '位置7', 装饰: '装饰7', 材质: '材质7' },
     obj: { 构件: '构件7', 位置: '位置7', 装饰: '装饰7', 材质: '材质7' },
     type: '分类一'
     type: '分类一'
   },
   },
@@ -72,6 +79,7 @@ const cardNames = [
     id: 8,
     id: 8,
     name: '文物的名称8',
     name: '文物的名称8',
     img: '8.png',
     img: '8.png',
+    position: { x: 700, y: 700 },
     obj: { 构件: '构件8', 位置: '位置8', 装饰: '装饰8', 材质: '材质8' },
     obj: { 构件: '构件8', 位置: '位置8', 装饰: '装饰8', 材质: '材质8' },
     type: '分类一'
     type: '分类一'
   },
   },
@@ -79,6 +87,7 @@ const cardNames = [
     id: 9,
     id: 9,
     name: '文物的名称9',
     name: '文物的名称9',
     img: '9.png',
     img: '9.png',
+    position: { x: 800, y: 800 },
     obj: { 构件: '构件9', 位置: '位置9', 装饰: '装饰9', 材质: '材质9' },
     obj: { 构件: '构件9', 位置: '位置9', 装饰: '装饰9', 材质: '材质9' },
     type: '分类一'
     type: '分类一'
   },
   },
@@ -86,6 +95,7 @@ const cardNames = [
     id: 10,
     id: 10,
     name: '文物的名称10',
     name: '文物的名称10',
     img: '10.png',
     img: '10.png',
+    position: { x: 900, y: 900 },
     obj: { 构件: '构件10', 位置: '位置10', 装饰: '装饰10', 材质: '材质10' },
     obj: { 构件: '构件10', 位置: '位置10', 装饰: '装饰10', 材质: '材质10' },
     type: '分类一'
     type: '分类一'
   }
   }

+ 1 - 0
project/src/pages/A5view/PageSon/A5atlas/data.ts

@@ -1,6 +1,7 @@
 import { MessageFu } from '@/utils/message'
 import { MessageFu } from '@/utils/message'
 import { urlCanRes } from '@/utils/urlCan'
 import { urlCanRes } from '@/utils/urlCan'
 
 
+// ---------------这个版本只支持电脑端 弃用----------------
 const nodes: any[] = []
 const nodes: any[] = []
 
 
 const lines: any[] = []
 const lines: any[] = []

+ 50 - 79
project/src/pages/A5view/PageSon/A5atlas/index.module.scss

@@ -38,98 +38,69 @@
       width: 100%;
       width: 100%;
       height: 100%;
       height: 100%;
 
 
-      .relation-graph {
-        background-image: url('../../../../assets/three/background.jpg');
-        background-size: 100% 100%;
-      }
-
-      // 样式重置
-      .relation-graph .rel-map {
-        background-color: transparent;
-      }
-
-      .rel-node-peel {
-        width: 250px;
-        height: 295px;
-      }
-
-      .rel-node-type-node {
-        background-color: transparent !important;
+      .A5Arow {
         display: inline-block;
         display: inline-block;
-        width: 100%;
-        height: 100%;
-        box-shadow: none;
-
-        .A5Arow {
-          display: inline-block;
-          position: relative;
-          width: 200px;
-          height: 238px;
-          background-image: url('../../../../assets/three/bj.png');
-          background-size: 100% 100%;
-          transition: all 0.3s;
+        position: relative;
+        width: 200px;
+        height: 238px;
+        background-image: url('../../../../assets/three/bj.png');
+        background-size: 100% 100%;
+        transition: all 0.3s;
 
 
-          img {
-            pointer-events: none;
-          }
+        img {
+          pointer-events: none;
+        }
 
 
+        & > div {
+          position: absolute;
+          top: 9%;
+          left: 5%;
+          width: 90%;
+          height: 72%;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          align-items: center;
           & > div {
           & > div {
-            position: absolute;
-            top: 9%;
-            left: 5%;
-            width: 90%;
-            height: 72%;
-            display: flex;
-            flex-direction: column;
-            justify-content: center;
-            align-items: center;
-            & > div {
-              color: var(--themeColor2);
-              margin-bottom: 20px;
-              font-size: 18px;
-            }
-            & > img {
-              max-width: 70%;
-              max-height: 50%;
-            }
+            color: var(--themeColor2);
+            margin-bottom: 20px;
+            font-size: 18px;
+          }
+          & > img {
+            max-width: 70%;
+            max-height: 50%;
           }
           }
         }
         }
-        // .A5ArowAc {
-        //   transition: all 0.3s;
-        //   transform: scale(1.2);
-        // }
       }
       }
 
 
-      .rel-node-peel-checked {
-        .rel-node-checked {
-          box-shadow: none;
-          // transform: scale(1.2);
-          transition: all 0.3s;
-        }
-        /* 当父元素 .rel-node-checked 直接包含一个同时具有 A5ArowAc 和 checked 类的子元素时,匹配该父元素 */
-        .rel-node-checked:has(> .A5ArowAc) {
-          transform: scale(1.2);
-        }
-      }
-      .rel-node {
-        transition: all 0.3s;
+      .A5ArowAc {
+        transform: scale(1.2);
       }
       }
 
 
-      .c-rg-line-text {
-        font-size: 20px;
-        fill: #fff3c5 !important;
+      .react-flow__node {
+        width: 250px;
+        height: 295px;
+        background-color: transparent;
+        border: none;
+        box-shadow: none !important;
+        display: flex;
+        align-items: center;
+        // 隐藏所有连接点
+        .react-flow__handle {
+          opacity: 0;
+          pointer-events: none;
+        }
       }
       }
-
-      .rel-toolbar {
-        display: none;
-        // background-color: rgba(0, 0, 0, 0.6);
-        // .c-current-zoom {
-        //   color: #fff;
-        // }
+      .react-flow__edge-textbg {
+        fill: transparent;
+      }
+      .react-flow__edge-text {
+        font-size: 24px;
+        fill: var(--themeColor2);
       }
       }
     }
     }
-    .rel-link-peel {
-      pointer-events: none !important;
+    .react-flow__panel {
+      display: none !important;
     }
     }
   }
   }
 }
 }

+ 92 - 77
project/src/pages/A5view/PageSon/A5atlas/index.tsx

@@ -1,70 +1,90 @@
-import React, { useCallback, useEffect, useRef, useState } from 'react'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
 import styles from './index.module.scss'
 import styles from './index.module.scss'
 import { infoPageIDGet } from '@/utils/locStore'
 import { infoPageIDGet } from '@/utils/locStore'
 import history from '@/utils/history'
 import history from '@/utils/history'
 
 
-import RelationGraph from 'relation-graph-react'
-import { atlData } from './data'
 import { baseOssUrl } from '@/utils/http'
 import { baseOssUrl } from '@/utils/http'
 import { urlCanRes } from '@/utils/urlCan'
 import { urlCanRes } from '@/utils/urlCan'
 import classNames from 'classnames'
 import classNames from 'classnames'
 
 
-function A5atlas() {
-  // 通过id高亮线条
-  const liangXianFu = useCallback((id: string) => {
-    if (graphRef.current) {
-      setAcId(id)
-      const allLinks: any[] = graphRef.current.getInstance().getLinks()
-      allLinks.forEach(link => {
-        link.relations.forEach((c: any) => {
-          if (c.from === id || c.to === id) {
-            c.opacity = 1
-            c.lineWidth = 3
-          } else {
-            c.opacity = 0.3
-            c.lineWidth = 1
-          }
-        })
-      })
-
-      const arr = graphRef.current.getInstance().getNodes()
-
-      arr.forEach((v1: any) => {
-        // v1.width = 200
-        // v1.height = 238
-        v1.opacity = 0.3
-      })
-
-      const nowObj = graphRef.current.getInstance().getNodeById(id)
-      // console.log('--------', nowObj)
-      // nowObj.width = 250
-      // nowObj.height = 295
-      nowObj.opacity = 1
-      nowObj.targetNodes.forEach((v2: any) => {
-        v2.opacity = 1
-      })
-    }
+import {
+  ReactFlow,
+  Edge,
+  useNodesState,
+  useEdgesState,
+  useReactFlow, // 添加这个钩子,
+  MarkerType,
+  ReactFlowProvider // 添加这个
+} from '@xyflow/react'
+import '@xyflow/react/dist/style.css'
+
+function FlowChart() {
+  const { fitView } = useReactFlow() // 获取 fitView 方法
+
+  // 每个组件
+  const Row = useCallback((item: any) => {
+    return (
+      <div className={classNames('A5Arow')}>
+        <div>
+          <div>{item.name}</div>
+          <img src={`${baseOssUrl}modelSS/img/${item.img}`} alt='' />
+        </div>
+      </div>
+    )
   }, [])
   }, [])
 
 
-  const graphRef = useRef<any>(null)
+  const initnode: any[] = useMemo(() => {
+    return cardNames.map(v => ({
+      id: v.id + '',
+      position: v.position,
+      data: { label: Row(v) },
+      draggable: true
+    }))
+  }, [Row])
 
 
-  const showGraph = useCallback(() => {
-    if (graphRef.current) {
-      graphRef.current.setJsonData(atlData())
-      const id = urlCanRes()
-      if (id) {
-        setTimeout(() => {
-          liangXianFu(id + '')
-        }, 200)
+  // 初始边 - 添加箭头标记
+  const initialEdges: Edge[] = useMemo(() => {
+    const arr: any[] = []
+    cardNames.forEach(v1 => {
+      if (v1.lines) {
+        v1.lines.forEach((v2: any, index: any) => {
+          arr.push({
+            id: index + '' + v1.id,
+            source: v1.id + '',
+            target: v2.to + '',
+            label: v2.text,
+            // 设置箭头
+            markerEnd: {
+              type: MarkerType.ArrowClosed,
+              color: '#f7d56f'
+            },
+            // 设置边样式
+            style: { stroke: '#f7d56f', strokeWidth: 2 }
+          })
+        })
       }
       }
-    }
-  }, [liangXianFu])
+    })
+
+    return arr
+  }, [])
+
+  // 使用状态管理节点和边
+  const [nodes, setNodes, onNodesChange] = useNodesState(initnode)
+  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges)
 
 
-  useEffect(() => {
-    showGraph()
-  }, [showGraph])
+  // 重置功能
+  const handleReset = useCallback(() => {
+    // 重置节点和边
+    setNodes(initnode)
+    setEdges(initialEdges)
+    // 重置视图到初始大小和位置
+    setTimeout(() => {
+      fitView({ duration: 300 }) // 添加动画效果,300ms
+    }, 0)
+  }, [setNodes, initnode, setEdges, initialEdges, fitView])
 
 
-  const [acId, setAcId] = useState('0')
+  // 处理节点点击
+  const onNodeClick = useCallback((event: React.MouseEvent, node: any) => {}, [])
 
 
   return (
   return (
     <div className={styles.A5atlas}>
     <div className={styles.A5atlas}>
@@ -81,39 +101,34 @@ function A5atlas() {
       </div>
       </div>
 
 
       {/* 手动重置按钮 */}
       {/* 手动重置按钮 */}
-      <div className='A5Aback A5Aloding' onClick={showGraph}>
+      <div className='A5Aback A5Aloding' onClick={handleReset}>
         <img src={require('@/assets/three/Reset.png')} alt='' />
         <img src={require('@/assets/three/Reset.png')} alt='' />
         <div>重置</div>
         <div>重置</div>
       </div>
       </div>
 
 
-      <div className={classNames('A5Amain')}>
-        <RelationGraph
-          ref={graphRef}
-          options={{
-            disableDragCanvas: false,
-            defaultLineShape: 3,
-            allowSwitchLineShape: true,
-            allowSwitchJunctionPoint: true,
-            moveToCenterWhenRefresh: true, // 刷新时居中,可选
-            useAnimationWhenRefresh: true // 刷新时使用动画,可选
-          }}
-          nodeSlot={({ node }: any) => (
-            <div
-              className={classNames('A5Arow', acId === node.data.id + '' ? 'A5ArowAc' : '')}
-              onClick={() => liangXianFu(node.data.id + '')}
-            >
-              <div>
-                <div>{node.data.name}</div>
-                <img src={`${baseOssUrl}modelSS/img/${node.data.img}`} alt='' />
-              </div>
-            </div>
-          )}
-        ></RelationGraph>
+      <div className={classNames('A5Amain')} style={{ width: '100%', height: '100%' }}>
+        <ReactFlow
+          nodes={nodes}
+          edges={edges}
+          onNodesChange={onNodesChange}
+          onEdgesChange={onEdgesChange}
+          onNodeClick={onNodeClick} // 添加这行
+          fitView
+        ></ReactFlow>
       </div>
       </div>
     </div>
     </div>
   )
   )
 }
 }
 
 
+// 主组件,用 ReactFlowProvider 包裹
+function A5atlas() {
+  return (
+    <ReactFlowProvider>
+      <FlowChart />
+    </ReactFlowProvider>
+  )
+}
+
 const MemoA5atlas = React.memo(A5atlas)
 const MemoA5atlas = React.memo(A5atlas)
 
 
 export default MemoA5atlas
 export default MemoA5atlas

+ 135 - 0
project/src/pages/A5view/PageSon/A5atlas/index2.module.scss

@@ -0,0 +1,135 @@
+.A5atlas {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  :global {
+    .A5Aback {
+      position: absolute;
+      z-index: 5;
+      left: 1.5vw;
+      top: 50%;
+      transform: translateY(-50%);
+      width: 4vw;
+      height: auto;
+      cursor: pointer;
+      img {
+        width: 100%;
+        height: auto;
+      }
+      & > div {
+        position: absolute;
+        left: 0;
+        bottom: -22px;
+        width: 100%;
+        text-align: center;
+        color: var(--themeColor2);
+        letter-spacing: 2px;
+        font-size: 18px;
+      }
+    }
+
+    .A5Aloding {
+      left: auto;
+      right: 1.5vw;
+    }
+
+    .A5Amain {
+      width: 100%;
+      height: 100%;
+
+      .relation-graph {
+        background-image: url('../../../../assets/three/background.jpg');
+        background-size: 100% 100%;
+      }
+
+      // 样式重置
+      .relation-graph .rel-map {
+        background-color: transparent;
+      }
+
+      .rel-node-peel {
+        width: 250px;
+        height: 295px;
+      }
+
+      .rel-node-type-node {
+        background-color: transparent !important;
+        display: inline-block;
+        width: 100%;
+        height: 100%;
+        box-shadow: none;
+
+        .A5Arow {
+          display: inline-block;
+          position: relative;
+          width: 200px;
+          height: 238px;
+          background-image: url('../../../../assets/three/bj.png');
+          background-size: 100% 100%;
+          transition: all 0.3s;
+
+          img {
+            pointer-events: none;
+          }
+
+          & > div {
+            position: absolute;
+            top: 9%;
+            left: 5%;
+            width: 90%;
+            height: 72%;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            & > div {
+              color: var(--themeColor2);
+              margin-bottom: 20px;
+              font-size: 18px;
+            }
+            & > img {
+              max-width: 70%;
+              max-height: 50%;
+            }
+          }
+        }
+        // .A5ArowAc {
+        //   transition: all 0.3s;
+        //   transform: scale(1.2);
+        // }
+      }
+
+      .rel-node-peel-checked {
+        .rel-node-checked {
+          box-shadow: none;
+          // transform: scale(1.2);
+          transition: all 0.3s;
+        }
+        /* 当父元素 .rel-node-checked 直接包含一个同时具有 A5ArowAc 和 checked 类的子元素时,匹配该父元素 */
+        .rel-node-checked:has(> .A5ArowAc) {
+          transform: scale(1.2);
+        }
+      }
+      .rel-node {
+        transition: all 0.3s;
+      }
+
+      .c-rg-line-text {
+        font-size: 20px;
+        fill: #fff3c5 !important;
+      }
+
+      .rel-toolbar {
+        display: none;
+        // background-color: rgba(0, 0, 0, 0.6);
+        // .c-current-zoom {
+        //   color: #fff;
+        // }
+      }
+    }
+    .rel-link-peel {
+      pointer-events: none !important;
+    }
+  }
+}

+ 119 - 0
project/src/pages/A5view/PageSon/A5atlas/index2.tsx

@@ -0,0 +1,119 @@
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import { infoPageIDGet } from '@/utils/locStore'
+import history from '@/utils/history'
+
+import RelationGraph from 'relation-graph-react'
+import { atlData } from './data'
+import { baseOssUrl } from '@/utils/http'
+import { urlCanRes } from '@/utils/urlCan'
+import classNames from 'classnames'
+
+function A5atlas() {
+  // 通过id高亮线条
+  const liangXianFu = useCallback((id: string) => {
+    if (graphRef.current) {
+      setAcId(id)
+      const allLinks: any[] = graphRef.current.getInstance().getLinks()
+      allLinks.forEach(link => {
+        link.relations.forEach((c: any) => {
+          if (c.from === id || c.to === id) {
+            c.opacity = 1
+            c.lineWidth = 3
+          } else {
+            c.opacity = 0.3
+            c.lineWidth = 1
+          }
+        })
+      })
+
+      const arr = graphRef.current.getInstance().getNodes()
+
+      arr.forEach((v1: any) => {
+        // v1.width = 200
+        // v1.height = 238
+        v1.opacity = 0.3
+      })
+
+      const nowObj = graphRef.current.getInstance().getNodeById(id)
+      // console.log('--------', nowObj)
+      // nowObj.width = 250
+      // nowObj.height = 295
+      nowObj.opacity = 1
+      nowObj.targetNodes.forEach((v2: any) => {
+        v2.opacity = 1
+      })
+    }
+  }, [])
+
+  const graphRef = useRef<any>(null)
+
+  const showGraph = useCallback(() => {
+    if (graphRef.current) {
+      graphRef.current.setJsonData(atlData())
+      const id = urlCanRes()
+      if (id) {
+        setTimeout(() => {
+          liangXianFu(id + '')
+        }, 200)
+      }
+    }
+  }, [liangXianFu])
+
+  useEffect(() => {
+    showGraph()
+  }, [showGraph])
+
+  const [acId, setAcId] = useState('0')
+
+  return (
+    <div className={styles.A5atlas}>
+      {/* 返回按钮 */}
+      <div
+        className='A5Aback'
+        onClick={() => {
+          const key = infoPageIDGet()
+          history.replace(`/view/${key}`)
+        }}
+      >
+        <img src={require('@/assets/three/back.png')} alt='' />
+        <div>返回</div>
+      </div>
+
+      {/* 手动重置按钮 */}
+      <div className='A5Aback A5Aloding' onClick={showGraph}>
+        <img src={require('@/assets/three/Reset.png')} alt='' />
+        <div>重置</div>
+      </div>
+
+      <div className={classNames('A5Amain')}>
+        <RelationGraph
+          ref={graphRef}
+          options={{
+            disableDragCanvas: false,
+            defaultLineShape: 3,
+            allowSwitchLineShape: true,
+            allowSwitchJunctionPoint: true,
+            moveToCenterWhenRefresh: true, // 刷新时居中,可选
+            useAnimationWhenRefresh: true // 刷新时使用动画,可选
+          }}
+          nodeSlot={({ node }: any) => (
+            <div
+              className={classNames('A5Arow', acId === node.data.id + '' ? 'A5ArowAc' : '')}
+              onClick={() => liangXianFu(node.data.id + '')}
+            >
+              <div>
+                <div>{node.data.name}</div>
+                <img src={`${baseOssUrl}modelSS/img/${node.data.img}`} alt='' />
+              </div>
+            </div>
+          )}
+        ></RelationGraph>
+      </div>
+    </div>
+  )
+}
+
+const MemoA5atlas = React.memo(A5atlas)
+
+export default MemoA5atlas

+ 50 - 14
project/yarn.lock

@@ -2232,7 +2232,7 @@
   resolved "https://registry.npmmirror.com/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz"
   resolved "https://registry.npmmirror.com/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz"
   integrity sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==
   integrity sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==
 
 
-"@types/d3-drag@*":
+"@types/d3-drag@*", "@types/d3-drag@^3.0.7":
   version "3.0.7"
   version "3.0.7"
   resolved "https://registry.npmmirror.com/@types/d3-drag/-/d3-drag-3.0.7.tgz"
   resolved "https://registry.npmmirror.com/@types/d3-drag/-/d3-drag-3.0.7.tgz"
   integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==
   integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==
@@ -2278,7 +2278,7 @@
   resolved "https://registry.npmmirror.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz"
   resolved "https://registry.npmmirror.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz"
   integrity sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==
   integrity sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==
 
 
-"@types/d3-interpolate@*":
+"@types/d3-interpolate@*", "@types/d3-interpolate@^3.0.4":
   version "3.0.4"
   version "3.0.4"
   resolved "https://registry.npmmirror.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz"
   resolved "https://registry.npmmirror.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz"
   integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==
   integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==
@@ -2317,7 +2317,7 @@
   dependencies:
   dependencies:
     "@types/d3-time" "*"
     "@types/d3-time" "*"
 
 
-"@types/d3-selection@*":
+"@types/d3-selection@*", "@types/d3-selection@^3.0.10":
   version "3.0.11"
   version "3.0.11"
   resolved "https://registry.npmmirror.com/@types/d3-selection/-/d3-selection-3.0.11.tgz"
   resolved "https://registry.npmmirror.com/@types/d3-selection/-/d3-selection-3.0.11.tgz"
   integrity sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==
   integrity sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==
@@ -2344,14 +2344,14 @@
   resolved "https://registry.npmmirror.com/@types/d3-timer/-/d3-timer-3.0.2.tgz"
   resolved "https://registry.npmmirror.com/@types/d3-timer/-/d3-timer-3.0.2.tgz"
   integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==
   integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==
 
 
-"@types/d3-transition@*":
+"@types/d3-transition@*", "@types/d3-transition@^3.0.8":
   version "3.0.9"
   version "3.0.9"
   resolved "https://registry.npmmirror.com/@types/d3-transition/-/d3-transition-3.0.9.tgz"
   resolved "https://registry.npmmirror.com/@types/d3-transition/-/d3-transition-3.0.9.tgz"
   integrity sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==
   integrity sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==
   dependencies:
   dependencies:
     "@types/d3-selection" "*"
     "@types/d3-selection" "*"
 
 
-"@types/d3-zoom@*":
+"@types/d3-zoom@*", "@types/d3-zoom@^3.0.8":
   version "3.0.8"
   version "3.0.8"
   resolved "https://registry.npmmirror.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz"
   resolved "https://registry.npmmirror.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz"
   integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==
   integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==
@@ -2595,7 +2595,7 @@
     "@types/history" "^4.7.11"
     "@types/history" "^4.7.11"
     "@types/react" "*"
     "@types/react" "*"
 
 
-"@types/react@*", "@types/react@^16.8 || ^17.0 || ^18.0", "@types/react@^18.0.24":
+"@types/react@*", "@types/react@^16.8 || ^17.0 || ^18.0", "@types/react@^18.0.24", "@types/react@>=16.8":
   version "18.0.24"
   version "18.0.24"
   resolved "https://registry.npmmirror.com/@types/react/-/react-18.0.24.tgz"
   resolved "https://registry.npmmirror.com/@types/react/-/react-18.0.24.tgz"
   integrity sha512-wRJWT6ouziGUy+9uX0aW4YOJxAY0bG6/AOk5AW5QSvZqI7dk6VBIbXvcVgIw/W5Jrl24f77df98GEKTJGOLx7Q==
   integrity sha512-wRJWT6ouziGUy+9uX0aW4YOJxAY0bG6/AOk5AW5QSvZqI7dk6VBIbXvcVgIw/W5Jrl24f77df98GEKTJGOLx7Q==
@@ -2933,6 +2933,30 @@
   resolved "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz"
   resolved "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz"
   integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
   integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
 
 
+"@xyflow/react@^12.10.1":
+  version "12.10.1"
+  resolved "https://registry.npmmirror.com/@xyflow/react/-/react-12.10.1.tgz"
+  integrity sha512-5eSWtIK/+rkldOuFbOOz44CRgQRjtS9v5nufk77DV+XBnfCGL9HAQ8PG00o2ZYKqkEU/Ak6wrKC95Tu+2zuK3Q==
+  dependencies:
+    "@xyflow/system" "0.0.75"
+    classcat "^5.0.3"
+    zustand "^4.4.0"
+
+"@xyflow/system@0.0.75":
+  version "0.0.75"
+  resolved "https://registry.npmmirror.com/@xyflow/system/-/system-0.0.75.tgz"
+  integrity sha512-iXs+AGFLi8w/VlAoc/iSxk+CxfT6o64Uw/k0CKASOPqjqz6E0rb5jFZgJtXGZCpfQI6OQpu5EnumP5fGxQheaQ==
+  dependencies:
+    "@types/d3-drag" "^3.0.7"
+    "@types/d3-interpolate" "^3.0.4"
+    "@types/d3-selection" "^3.0.10"
+    "@types/d3-transition" "^3.0.8"
+    "@types/d3-zoom" "^3.0.8"
+    d3-drag "^3.0.0"
+    d3-interpolate "^3.0.1"
+    d3-selection "^3.0.0"
+    d3-zoom "^3.0.0"
+
 abab@^2.0.3, abab@^2.0.5:
 abab@^2.0.3, abab@^2.0.5:
   version "2.0.6"
   version "2.0.6"
   resolved "https://registry.npmmirror.com/abab/-/abab-2.0.6.tgz"
   resolved "https://registry.npmmirror.com/abab/-/abab-2.0.6.tgz"
@@ -3832,6 +3856,11 @@ cjs-module-lexer@^1.0.0:
   resolved "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz"
   resolved "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz"
   integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
   integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
 
 
+classcat@^5.0.3:
+  version "5.0.5"
+  resolved "https://registry.npmmirror.com/classcat/-/classcat-5.0.5.tgz"
+  integrity sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==
+
 classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2, classnames@^2.5.1, classnames@2.x:
 classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2, classnames@^2.5.1, classnames@2.x:
   version "2.5.1"
   version "2.5.1"
   resolved "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz"
   resolved "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz"
@@ -4376,7 +4405,7 @@ d3-delaunay@6:
   resolved "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz"
   resolved "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz"
   integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==
   integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==
 
 
-"d3-drag@2 - 3", d3-drag@3:
+d3-drag@^3.0.0, "d3-drag@2 - 3", d3-drag@3:
   version "3.0.0"
   version "3.0.0"
   resolved "https://registry.npmmirror.com/d3-drag/-/d3-drag-3.0.0.tgz"
   resolved "https://registry.npmmirror.com/d3-drag/-/d3-drag-3.0.0.tgz"
   integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==
   integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==
@@ -4431,7 +4460,7 @@ d3-hierarchy@3:
   resolved "https://registry.npmmirror.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz"
   resolved "https://registry.npmmirror.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz"
   integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==
   integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==
 
 
-"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3:
+d3-interpolate@^3.0.1, "d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3:
   version "3.0.1"
   version "3.0.1"
   resolved "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz"
   resolved "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz"
   integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
   integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
@@ -4477,7 +4506,7 @@ d3-scale@4:
     d3-time "2.1.1 - 3"
     d3-time "2.1.1 - 3"
     d3-time-format "2 - 4"
     d3-time-format "2 - 4"
 
 
-"d3-selection@2 - 3", d3-selection@3:
+d3-selection@^3.0.0, "d3-selection@2 - 3", d3-selection@3:
   version "3.0.0"
   version "3.0.0"
   resolved "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz"
   resolved "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz"
   integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==
   integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==
@@ -4519,7 +4548,7 @@ d3-shape@3:
     d3-interpolate "1 - 3"
     d3-interpolate "1 - 3"
     d3-timer "1 - 3"
     d3-timer "1 - 3"
 
 
-d3-zoom@3:
+d3-zoom@^3.0.0, d3-zoom@3:
   version "3.0.0"
   version "3.0.0"
   resolved "https://registry.npmmirror.com/d3-zoom/-/d3-zoom-3.0.0.tgz"
   resolved "https://registry.npmmirror.com/d3-zoom/-/d3-zoom-3.0.0.tgz"
   integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==
   integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==
@@ -6154,7 +6183,7 @@ ignore@^5.2.0:
   resolved "https://registry.npmmirror.com/ignore/-/ignore-5.2.0.tgz"
   resolved "https://registry.npmmirror.com/ignore/-/ignore-5.2.0.tgz"
   integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
   integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
 
 
-immer@^9.0.7:
+immer@^9.0.7, immer@>=9.0.6:
   version "9.0.16"
   version "9.0.16"
   resolved "https://registry.npmmirror.com/immer/-/immer-9.0.16.tgz"
   resolved "https://registry.npmmirror.com/immer/-/immer-9.0.16.tgz"
   integrity sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==
   integrity sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==
@@ -9048,7 +9077,7 @@ react-dev-utils@^12.0.1:
     strip-ansi "^6.0.1"
     strip-ansi "^6.0.1"
     text-table "^0.2.0"
     text-table "^0.2.0"
 
 
-react-dom@*, "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", react-dom@^18.0.0, react-dom@^18.2.0, "react-dom@>= 16.3", "react-dom@>= 16.3.0", react-dom@>=16.0.0, react-dom@>=16.11.0, react-dom@>=16.8.0, react-dom@>=16.9.0:
+react-dom@*, "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", react-dom@^18.0.0, react-dom@^18.2.0, "react-dom@>= 16.3", "react-dom@>= 16.3.0", react-dom@>=16.0.0, react-dom@>=16.11.0, react-dom@>=16.8.0, react-dom@>=16.9.0, react-dom@>=17:
   version "18.2.0"
   version "18.2.0"
   resolved "https://registry.npmmirror.com/react-dom/-/react-dom-18.2.0.tgz"
   resolved "https://registry.npmmirror.com/react-dom/-/react-dom-18.2.0.tgz"
   integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
   integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
@@ -9232,7 +9261,7 @@ react-sortablejs@^6.1.4:
     classnames "2.3.1"
     classnames "2.3.1"
     tiny-invariant "1.2.0"
     tiny-invariant "1.2.0"
 
 
-react@*, "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", react@^18.0.0, react@^18.2.0, "react@>= 16", "react@>= 16.3", "react@>= 16.3.0", "react@>= 16.8.0", react@>=15, react@>=16.0.0, react@>=16.11.0, react@>=16.8.0, react@>=16.9.0, react@>=17.0.0:
+react@*, "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", react@^18.0.0, react@^18.2.0, "react@>= 16", "react@>= 16.3", "react@>= 16.3.0", "react@>= 16.8.0", react@>=15, react@>=16.0.0, react@>=16.11.0, react@>=16.8, react@>=16.8.0, react@>=16.9.0, react@>=17, react@>=17.0.0:
   version "18.2.0"
   version "18.2.0"
   resolved "https://registry.npmmirror.com/react/-/react-18.2.0.tgz"
   resolved "https://registry.npmmirror.com/react/-/react-18.2.0.tgz"
   integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
   integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
@@ -10549,7 +10578,7 @@ url-parse@^1.5.3:
     querystringify "^2.1.1"
     querystringify "^2.1.1"
     requires-port "^1.0.0"
     requires-port "^1.0.0"
 
 
-use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0:
+use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0, use-sync-external-store@^1.2.2:
   version "1.6.0"
   version "1.6.0"
   resolved "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz"
   resolved "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz"
   integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==
   integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==
@@ -11137,3 +11166,10 @@ yocto-queue@^0.1.0:
   version "0.1.0"
   version "0.1.0"
   resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz"
   resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz"
   integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
   integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+
+zustand@^4.4.0:
+  version "4.5.7"
+  resolved "https://registry.npmmirror.com/zustand/-/zustand-4.5.7.tgz"
+  integrity sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==
+  dependencies:
+    use-sync-external-store "^1.2.2"