shaogen1995 2 ngày trước cách đây
mục cha
commit
540cd488ce

+ 90 - 24
project/public/three/data.js

@@ -8,33 +8,104 @@ const cardNames = [
     id: 1,
     name: '文物的名称1',
     img: '1.png',
-    position: { x: 0, y: 0 },
     obj: { 构件: '构件1', 位置: '位置1', 装饰: '装饰1', 材质: '材质1' },
     type: '分类二',
-    lines: [
-      { to: 2, text: '1-2' },
-      { to: 3, text: '1-3' },
-      { to: 4, text: '1-4' }
+    // 关系图
+    son: [
+      //  第二级
+      [
+        {
+          source: 1,
+          target: 2,
+          value: '关系1-2'
+        },
+        {
+          source: 1,
+          target: 3,
+          value: '关系1-3'
+        },
+        {
+          source: 1,
+          target: 4,
+          value: '关系1-4'
+        }
+      ],
+      // 第三级
+      [
+        {
+          source: 2,
+          target: 5,
+          value: '关系2-5'
+        },
+        {
+          source: 2,
+          target: 6,
+          value: '关系2-6'
+        },
+        {
+          source: 2,
+          target: 7,
+          value: '关系2-7'
+        },
+        {
+          source: 4,
+          target: 8,
+          value: '关系4-8'
+        },
+        {
+          source: 4,
+          target: 9,
+          value: '关系4-9'
+        },
+        {
+          source: 4,
+          target: 10,
+          value: '关系4-10'
+        }
+      ]
     ]
   },
   {
     id: 2,
     name: '文物的名称2',
     img: '2.png',
-    position: { x: 100, y: 100 },
     obj: { 构件: '构件2', 位置: '位置2', 装饰: '装饰2', 材质: '材质2' },
     type: '分类二',
-    lines: [
-      { to: 5, text: '2-5' },
-      { to: 6, text: '2-6' },
-      { to: 7, text: '2-7' }
+    // 关系图
+    son: [
+      //  第二级
+      [
+        {
+          source: 2,
+          target: 8,
+          value: '关系1-2'
+        },
+        {
+          source: 2,
+          target: 9,
+          value: '关系1-3'
+        },
+        {
+          source: 2,
+          target: 10,
+          value: '关系1-4'
+        }
+      ],
+      // 第三级
+      [
+        {
+          source: 9,
+          target: 1,
+          value: '关系2-5'
+        }
+      ]
     ]
   },
   {
     id: 3,
     name: '文物的名称3',
     img: '3.png',
-    position: { x: 200, y: 200 },
+
     obj: { 构件: '构件3', 位置: '位置3', 装饰: '装饰3', 材质: '材质3' },
     type: '分类二'
   },
@@ -42,20 +113,15 @@ const cardNames = [
     id: 4,
     name: '文物的名称4',
     img: '4.png',
-    position: { x: 300, y: 300 },
+
     obj: { 构件: '构件4', 位置: '位置4', 装饰: '装饰4', 材质: '材质4' },
-    type: '分类二',
-    lines: [
-      { to: 8, text: '4-8' },
-      { to: 9, text: '4-9' },
-      { to: 10, text: '4-10' }
-    ]
+    type: '分类二'
   },
   {
     id: 5,
     name: '文物的名称5',
     img: '5.png',
-    position: { x: 400, y: 400 },
+
     obj: { 构件: '构件5', 位置: '位置5', 装饰: '装饰5', 材质: '材质5' },
     type: '分类一'
   },
@@ -63,7 +129,7 @@ const cardNames = [
     id: 6,
     name: '文物的名称6',
     img: '6.png',
-    position: { x: 500, y: 500 },
+
     obj: { 构件: '构件6', 位置: '位置6', 装饰: '装饰6', 材质: '材质6' },
     type: '分类一'
   },
@@ -71,7 +137,7 @@ const cardNames = [
     id: 7,
     name: '文物的名称7',
     img: '7.png',
-    position: { x: 600, y: 600 },
+
     obj: { 构件: '构件7', 位置: '位置7', 装饰: '装饰7', 材质: '材质7' },
     type: '分类一'
   },
@@ -79,7 +145,7 @@ const cardNames = [
     id: 8,
     name: '文物的名称8',
     img: '8.png',
-    position: { x: 700, y: 700 },
+
     obj: { 构件: '构件8', 位置: '位置8', 装饰: '装饰8', 材质: '材质8' },
     type: '分类一'
   },
@@ -87,7 +153,7 @@ const cardNames = [
     id: 9,
     name: '文物的名称9',
     img: '9.png',
-    position: { x: 800, y: 800 },
+
     obj: { 构件: '构件9', 位置: '位置9', 装饰: '装饰9', 材质: '材质9' },
     type: '分类一'
   },
@@ -95,7 +161,7 @@ const cardNames = [
     id: 10,
     name: '文物的名称10',
     img: '10.png',
-    position: { x: 900, y: 900 },
+
     obj: { 构件: '构件10', 位置: '位置10', 装饰: '装饰10', 材质: '材质10' },
     type: '分类一'
   }

+ 17 - 0
project/public/tuPu/index.html

@@ -0,0 +1,17 @@
+<!doctype html>
+<html lang="zh" style="height: 100%">
+  <head>
+    <meta charset="utf-8" />
+    <link rel="stylesheet" href="./css/reset.css" />
+    <title>tu</title>
+  </head>
+
+  <body style="height: 100%; margin: 0; background: none">
+    <div id="container" style="height: 100%"></div>
+
+    <script src="../three/data.js"></script>
+
+    <script type="text/javascript" src="./js/echarts.min.js"></script>
+    <script src="./js/index.js"></script>
+  </body>
+</html>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 60402 - 0
project/public/tuPu/js/echarts.min.js


+ 288 - 0
project/public/tuPu/js/index.js

@@ -0,0 +1,288 @@
+function anonymous() {
+  const urlAll = window.location.href
+
+  if (!urlAll.includes('?id=')) return alert('参数错误')
+
+  const id = urlAll.split('?id=')[1]
+
+  const obj = cardNames.find(v => v.id == id)
+
+  if (!obj) return alert('参数错误')
+
+  let dom = document.getElementById('container')
+  let myChart = echarts.init(dom, null, {
+    renderer: 'canvas',
+    useDirtyRect: false
+  })
+
+  let option
+
+  const data1 = []
+  const data2 = []
+
+  if (obj.son) {
+    const ids = []
+
+    obj.son.forEach((c1, i) => {
+      c1.forEach(c2 => {
+        data2.push({
+          source: c2.source + '',
+          target: c2.target + '',
+          value: c2.value
+        })
+
+        if (!ids.map(a => a.id).includes(c2.source + '')) {
+          ids.push({
+            id: c2.source + '',
+            symbolSize: 200 - (i + 1) * 50,
+            tit: i === obj.son.length - 1,
+            value: c2.value
+          })
+        }
+        if (!ids.map(a => a.id).includes(c2.target + '')) {
+          ids.push({
+            id: c2.target + '',
+            symbolSize: 200 - (i + 1) * 50,
+            tit: i === obj.son.length - 1,
+            value: c2.value
+          })
+        }
+      })
+    })
+
+    ids.forEach(v => {
+      const isCenter = id == v.id
+      const centerX = window.innerWidth / 2 // 中心坐标x
+      const centerY = window.innerHeight / 2 // 中心坐标y
+
+      const obj = cardNames.find(c => c.id == v.id)
+
+      data1.push({
+        fixed: isCenter, // 固定中心节点位置
+        x: isCenter ? centerX : null, // 设置中心节点坐标
+        y: isCenter ? centerY : null,
+        // category: id == v.id ? '中心' : '',
+        symbolSize: id == v.id ? 200 : v.symbolSize,
+        id: v.id,
+        name: obj.name,
+        symbol: `image://../../three/assets/out/${v.id}.png`
+        //  tit:v.tit
+      })
+    })
+  }
+
+  option = {
+    tooltip: {
+      show: true, // 默认显示
+      showContent: true, // 是否显示提示框浮层
+      trigger: 'item', // 触发类型,默认数据项触发
+      triggerOn: 'mousemove', // 提示触发条件,mousemove鼠标移至触发,还有click点击触发
+      alwaysShowContent: false, // 默认离开提示框区域隐藏,true为一直显示
+      showDelay: 100, // 浮层显示的延迟,单位为 ms,默认没有延迟,也不建议设置。在 triggerOn 为 'mousemove' 时有效。
+      hideDelay: 2000, // 浮层隐藏的延迟,单位为 ms,在 alwaysShowContent 为 true 的时候无效。
+      enterable: false, // 鼠标是否可进入提示框浮层中,默认为false,如需详情内交互,如添加链接,按钮,可设置为 true。
+      position: 'right', // 提示框浮层的位置,默认不设置时位置会跟随鼠标的位置。只在 trigger 为'item'的时候有效。
+      confine: true, // 是否将 tooltip 框限制在图表的区域内。
+      // 外层的 dom 被设置为 'overflow: hidden',或者移动端窄屏,导致 tooltip 超出外界被截断时,此配置比较有用。
+      transitionDuration: 0.2, // 提示框浮层的移动动画过渡时间,单位是秒,设置为 0 的时候会紧跟着鼠标移动。
+      formatter: function (params) {
+        // 判断当前节点是否为第三级节点
+        // 假设层级信息可以通过 params.data.tit 获取,或者通过其他逻辑判断
+        if (params.data.tit) {
+          // 如果是第三级节点,返回自定义的悬浮框内容
+          return params.name
+        } else {
+          // 如果不是第三级节点,返回默认的悬浮框内容或不显示
+          return '' // 不显示悬浮框
+        }
+      },
+      // 自定义提示框的样式
+      borderColor: '#896a43',
+      backgroundColor: 'rgba(0,0,0,0.5)',
+      textStyle: {
+        color: '#dfd5c5',
+        fontFamily: 'sk'
+      },
+      blur: {
+        itemStyle: {
+          opacity: 0.2 // 非突出节点的透明度
+        },
+        label: {
+          show: false // 非突出节点隐藏标签
+        }
+      }
+    },
+
+    series: [
+      {
+        type: 'graph', // 关系图
+        symbolKeepAspect: true, // 保持图片宽高比
+        // name: "Name:", // 系列名称,用于tooltip的显示,legend 的图例筛选,在 setOption 更新数据和配置项时用于指定对应的系列。
+        layout: 'force', // 图的布局,类型为力导图,'circular' 采用环形布局,见示例 Les Miserables
+        legendHoverLink: true, // 是否启用图例 hover(悬停) 时的联动高亮。
+        hoverAnimation: false, // 是否开启鼠标悬停节点的显示动画
+        coordinateSystem: null, // 坐标系可选
+        // xAxisIndex: 0, // x轴坐标 有多种坐标系轴坐标选项
+        // yAxisIndex: 0, // y轴坐标
+        force: {
+          // 力引导图基本配置
+          // initLayout: 'circular',
+          // initLayout: , // 力引导的初始化布局,默认使用xy轴的标点
+          repulsion: 600, //节点之间的斥力因子。支持数组表达斥力范围,值越大斥力越大。
+          gravity: 0.01, //节点受到的向中心的引力因子。该值越大节点越往中心点靠拢。
+          edgeLength: 240, //边的两个节点之间的距离,这个距离也会受 repulsion。[10, 50] 。值越小则长度越长
+          layoutAnimation: true, // 因为力引导布局会在多次迭代后才会稳定,这个参数决定是否显示布局的迭代动画
+          // 在浏览器端节点数据较多(>100)的时候不建议关闭,布局过程会造成浏览器假死。
+          // 防止节点重叠
+          friction: 0.8, // 增加摩擦力
+          // 增加防止重叠的参数
+          nodeOverlap: 20, // 防止节点重叠的参数
+          // 优化布局迭代
+          coolingFactor: 0.99, // 冷却因子,使布局逐渐稳定
+          minMovement: 0.5, // 最小移动距离
+          maxIteration: 2000 // 增加最大迭代次数
+        },
+        roam: true, // 是否开启鼠标缩放和平移漫游。默认不开启,true 为都开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'
+        // zoom: 1,
+        scaleLimit: {
+          // 缩放限制,只在使用 force 布局时有效。
+          min: 0.8 ? 0.8 : 0.5, // 最小缩放比例
+          max: 3 // 最大缩放比例
+        },
+        nodeScaleRatio: 0.6, // 鼠标漫游缩放时节点的相应缩放比例,当设为0时节点不随着鼠标的缩放而缩放
+        draggable: true, // 节点是否可拖拽,只在使用力引导布局的时候有用。
+        focusNodeAdjacency: !window.isMobile ? true : false, // 是否在鼠标移到节点上的时候突出显示节点以及节点的边和邻接节点。
+        emphasis: {
+          itemStyle: {
+            opacity: 1 // 突出节点的透明度
+          }
+        },
+        blur: {
+          itemStyle: {
+            opacity: 0.3 // 非突出节点的透明度
+          },
+          lineStyle: {
+            opacity: 0.3 // 非突出节点的透明度
+          },
+          label: {
+            opacity: 0.3 // 非突出节点的透明度
+          }
+        },
+        // symbol:'roundRect', // 关系图节点标记的图形。
+        // ECharts 提供的标记类型包括:'circle'(圆形), 'rect'(矩形), 'roundRect'(圆角矩形),
+        // 'triangle'(三角形), 'diamond'(菱形), 'pin'(大头针), 'arrow'(箭头)
+        // 也可以通过 'image://url' 设置为图片,其中 url 为图片的链接。'path:// 这种方式可以任意改变颜色并且抗锯齿
+        // symbolSize: 10 , // 也可以用数组分开表示宽和高,例如 [20, 10] 如果需要每个数据的图形大小不一样,
+        // 可以设置为如下格式的回调函数:(value: Array|number, params: Object) => number|Array
+        // symbolRotate:, // 关系图节点标记的旋转角度。注意在 markLine 中当 symbol 为 'arrow' 时会忽略 symbolRotate 强制设置为切线的角度。
+        // symbolOffset:[0,0], // 关系图节点标记相对于原本位置的偏移。[0, '50%']
+        edgeSymbol: ['circle', 'circle'], // 边两端的标记类型,可以是一个数组分别指定两端,也可以是单个统一指定。
+        // 默认不显示标记,常见的可以设置为箭头,如下:edgeSymbol: ['circle', 'arrow']
+        edgeSymbolSize: [0, 10], // 边两端的标记大小,可以是一个数组分别指定两端,也可以是单个统一指定。
+
+        symbolSize: 120, // 关系图节点标记的大小,可以是一个数组分别指定两端,也可以是单个统一指定。
+        itemStyle: {
+          // ========图形样式,有 normal 和 emphasis 两个状态。
+          // normal 是图形在默认状态下的样式;
+          // emphasis 是图形在高亮状态下的样式,比如在鼠标悬浮或者图例联动高亮时。
+          normal: {
+            // 默认样式
+            label: {
+              show: true
+            },
+            borderType: 'solid', // 图形描边类型,默认为实线,支持 'solid'(实线), 'dashed'(虚线), 'dotted'(点线)。
+            borderColor: '#fad166', // 设置图形边框为淡金色,透明度为0.4
+            borderWidth: 2, // 图形的描边线宽。为 0 时无描边。
+            opacity: 1 // 图形透明度。支持从 0 到 1 的数字,为 0 时不绘制该图形。默认0.5
+          },
+          emphasis: {
+            // 高亮状态
+            // lineStyle: {
+            //   width: 10,
+            // },
+          }
+        },
+        lineStyle: {
+          // ========关系边的公用线条样式。
+          normal: {
+            color: '#fad166',
+            width: '1', //线的粗细
+            type: 'dashed', // 线的类型 'solid'(实线)'dashed'(虚线)'dotted'(点线)
+            curveness: 0.3, // 线条的曲线程度,从0到1
+            opacity: 0.5 // 图形透明度。支持从 0 到 1 的数字,为 0 时不绘制该图形。默认0.5
+          },
+          emphasis: {
+            // 高亮状态
+          }
+        },
+        label: {
+          // ========结点图形上的文本标签
+          normal: {
+            show: true, // 是否显示标签。
+            position: 'bottom', // 标签的位置。['50%', '50%'] [x,y]
+            textStyle: {
+              // 标签的字体样式
+              color: '#fad166', // 字体颜色
+              fontStyle: 'normal', // 文字字体的风格 'normal'标准 'italic'斜体 'oblique' 倾斜
+              fontWeight: 'normal', // 'normal'标准,'bold'粗的,'bolder'更粗的,'lighter'更细的,或100 | 200 | 300 | 400...
+              fontFamily: 'sk', // 文字的字体系列
+              fontSize: 16
+            }
+          }
+        },
+        edgeLabel: {
+          // ========连接线上的文本标签
+          normal: {
+            show: true, // 不显示连接线上的文字,如果显示只能显示结点的value值,而不是连接线的值
+            // position: "middle", // 标签的位置。['50%', '50%'] [x,y]
+            textStyle: {
+              color: '#f4e6bf',
+              fontSize: 16
+            },
+            formatter: '{c}'
+          }
+        },
+
+        data: data1,
+        // 设置连线edges的数据,
+
+        links: data2, // 设置连线edges的数据
+        // 添加节点布局优化
+        circular: {
+          rotateLabel: false
+        },
+        // 优化节点间距
+        categories: [
+          {
+            name: '中心',
+            itemStyle: {
+              color: '#ff6b6b'
+            }
+          }
+        ]
+      }
+    ]
+  }
+
+  if (myChart) {
+    if (option && typeof option === 'object') {
+      setTimeout(function () {
+        myChart.setOption(option)
+      }, 500)
+    }
+  } else {
+    console.error('ECharts 初始化失败')
+  }
+
+  // 点击节点跳转链接
+  myChart.on('click', function (params, e) {
+    // if (params.componentType === "series" && params.dataType === "node") {
+    //   const nodeData = params.data;
+    //   openDetail(nodeData.idinfo, e);
+    // }
+  })
+
+  window.addEventListener('resize', myChart.resize)
+}
+
+anonymous()

+ 1 - 72
project/src/pages/A5view/PageSon/A5atlas/index.module.scss

@@ -2,7 +2,6 @@
   position: relative;
   width: 100%;
   height: 100%;
-
   :global {
     .A5Aback {
       position: absolute;
@@ -28,79 +27,9 @@
         font-size: 18px;
       }
     }
-
-    .A5Aloding {
-      left: auto;
-      right: 1.5vw;
-    }
-
-    .A5Amain {
+    iframe {
       width: 100%;
       height: 100%;
-
-      .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 {
-        transform: scale(1.2);
-      }
-
-      .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;
-        }
-      }
-      .react-flow__edge-textbg {
-        fill: transparent;
-      }
-      .react-flow__edge-text {
-        font-size: 24px;
-        fill: var(--themeColor2);
-      }
-    }
-    .react-flow__panel {
-      display: none !important;
     }
   }
 }

+ 3 - 179
project/src/pages/A5view/PageSon/A5atlas/index.tsx

@@ -1,161 +1,9 @@
-import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import React from 'react'
 import styles from './index.module.scss'
 import { infoPageIDGet } from '@/utils/locStore'
 import history from '@/utils/history'
-import { baseOssUrl } from '@/utils/http'
 import { urlCanRes } from '@/utils/urlCan'
-import classNames from 'classnames'
-import dagre from 'dagre'
-
-import {
-  ReactFlow,
-  Edge,
-  useNodesState,
-  useEdgesState,
-  useReactFlow, // 添加这个钩子,
-  MarkerType,
-  ReactFlowProvider // 添加这个
-} from '@xyflow/react'
-import '@xyflow/react/dist/style.css'
-
-const layoutDirection = 'TB'
-
-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 initialNodesWithoutPosition: any[] = useMemo(() => {
-    return cardNames.map(v => ({
-      id: v.id + '',
-      // position: v.position,
-      data: { label: Row(v) },
-      draggable: true
-    }))
-  }, [Row])
-
-  // 初始边 - 添加箭头标记
-  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 }
-          })
-        })
-      }
-    })
-
-    return arr
-  }, [])
-
-  // 使用状态管理节点和边
-  const [nodes, setNodes, onNodesChange] = useNodesState([] as any[])
-  const [edges, setEdges, onEdgesChange] = useEdgesState([] as any[])
-
-  // 自动布局函数
-  const applyAutoLayout = useCallback((nodes: any[], edges: any[], direction: string = 'TB') => {
-    // 创建 dagre 图
-    const dagreGraph = new dagre.graphlib.Graph()
-    dagreGraph.setDefaultEdgeLabel(() => ({}))
-
-    // 设置布局选项
-    const nodeWidth = 250
-    const nodeHeight = 295
-
-    // 根据方向设置布局参数
-    const isHorizontal = direction === 'LR' || direction === 'RL'
-    dagreGraph.setGraph({
-      rankdir: direction,
-      nodesep: 100, // 节点间距
-      ranksep: 100, // 层级间距
-      marginx: 20,
-      marginy: 20
-    })
-
-    // 添加节点到 dagre 图
-    nodes.forEach(node => {
-      dagreGraph.setNode(node.id, {
-        width: nodeWidth,
-        height: nodeHeight
-      })
-    })
-
-    // 添加边到 dagre 图
-    edges.forEach(edge => {
-      if (edge.source && edge.target) {
-        dagreGraph.setEdge(edge.source, edge.target)
-      }
-    })
-
-    // 计算布局
-    dagre.layout(dagreGraph)
-
-    // 转换节点位置
-    const layoutedNodes = nodes.map(node => {
-      const nodeWithPosition = dagreGraph.node(node.id)
-
-      return {
-        ...node,
-        targetPosition: isHorizontal ? 'left' : 'top',
-        sourcePosition: isHorizontal ? 'right' : 'bottom',
-        position: {
-          x: nodeWithPosition.x - nodeWidth / 2 + Math.random() * 10,
-          y: nodeWithPosition.y - nodeHeight / 2 + Math.random() * 10
-        }
-      }
-    })
-
-    return layoutedNodes
-  }, [])
-
-  // 初始化布局
-
-  const initFu = useCallback(() => {
-    if (initialNodesWithoutPosition.length > 0) {
-      const layoutedNodes = applyAutoLayout(
-        initialNodesWithoutPosition,
-        initialEdges,
-        layoutDirection
-      )
-      setNodes(layoutedNodes)
-      setEdges(initialEdges)
-
-      // 自适应视图
-      setTimeout(() => {
-        fitView({ duration: 300, padding: 0.1 })
-      }, 100)
-    }
-  }, [applyAutoLayout, fitView, initialEdges, initialNodesWithoutPosition, setEdges, setNodes])
-
-  useEffect(() => {
-    initFu()
-  }, [initFu])
-
-  // 处理节点点击
-  const onNodeClick = useCallback((event: React.MouseEvent, node: any) => {}, [])
-
+function A5atlas() {
   return (
     <div className={styles.A5atlas}>
       {/* 返回按钮 */}
@@ -170,35 +18,11 @@ function FlowChart() {
         <div>返回</div>
       </div>
 
-      {/* 手动重置按钮 */}
-      <div className='A5Aback A5Aloding' onClick={initFu}>
-        <img src={require('@/assets/three/Reset.png')} alt='' />
-        <div>重置</div>
-      </div>
-
-      <div className={classNames('A5Amain')} style={{ width: '100%', height: '100%' }}>
-        <ReactFlow
-          nodes={nodes}
-          edges={edges}
-          onNodesChange={onNodesChange}
-          onEdgesChange={onEdgesChange}
-          onNodeClick={onNodeClick} // 添加这行
-          fitView
-        ></ReactFlow>
-      </div>
+      <iframe src={`./tuPu/index.html?id=${urlCanRes()}`} title='tuPu' frameBorder='0'></iframe>
     </div>
   )
 }
 
-// 主组件,用 ReactFlowProvider 包裹
-function A5atlas() {
-  return (
-    <ReactFlowProvider>
-      <FlowChart />
-    </ReactFlowProvider>
-  )
-}
-
 const MemoA5atlas = React.memo(A5atlas)
 
 export default MemoA5atlas

project/src/pages/A5view/PageSon/A5atlas/data.tsx → project/src/pages/A5view/PageSon/A5atlas2/data.tsx


+ 107 - 0
project/src/pages/A5view/PageSon/A5atlas2/index.module.scss

@@ -0,0 +1,107 @@
+.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%;
+
+      .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 {
+        transform: scale(1.2);
+      }
+
+      .react-flow__node {
+        width: 250px;
+        height: 295px;
+        background-color: transparent;
+        border: none;
+        box-shadow: none !important;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        // 隐藏所有连接点
+        .react-flow__handle {
+          opacity: 0;
+          pointer-events: none;
+        }
+      }
+      .react-flow__edge-textbg {
+        fill: transparent;
+      }
+      .react-flow__edge-text {
+        font-size: 24px;
+        fill: var(--themeColor2);
+      }
+    }
+    .react-flow__panel {
+      display: none !important;
+    }
+  }
+}

+ 205 - 0
project/src/pages/A5view/PageSon/A5atlas2/index.tsx

@@ -0,0 +1,205 @@
+import React, { useCallback, useEffect, useMemo } from 'react'
+import styles from './index.module.scss'
+import { infoPageIDGet } from '@/utils/locStore'
+import history from '@/utils/history'
+import { baseOssUrl } from '@/utils/http'
+import classNames from 'classnames'
+import dagre from 'dagre'
+
+import {
+  ReactFlow,
+  Edge,
+  useNodesState,
+  useEdgesState,
+  useReactFlow,
+  MarkerType,
+  ReactFlowProvider
+} from '@xyflow/react'
+import '@xyflow/react/dist/style.css'
+
+const layoutDirection = 'TB'
+
+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 initialNodesWithoutPosition: any[] = useMemo(() => {
+    return cardNames.map(v => ({
+      id: v.id + '',
+      // position: v.position,
+      data: { label: Row(v) },
+      draggable: true
+    }))
+  }, [Row])
+
+  // 初始边 - 添加箭头标记
+  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 }
+          })
+        })
+      }
+    })
+
+    return arr
+  }, [])
+
+  // 使用状态管理节点和边
+  const [nodes, setNodes, onNodesChange] = useNodesState([] as any[])
+  const [edges, setEdges, onEdgesChange] = useEdgesState([] as any[])
+
+  // 自动布局函数
+  const applyAutoLayout = useCallback((nodes: any[], edges: any[], direction: string = 'TB') => {
+    // 创建 dagre 图
+    const dagreGraph = new dagre.graphlib.Graph()
+    dagreGraph.setDefaultEdgeLabel(() => ({}))
+
+    // 设置布局选项
+    const nodeWidth = 250
+    const nodeHeight = 295
+
+    // 根据方向设置布局参数
+    const isHorizontal = direction === 'LR' || direction === 'RL'
+    dagreGraph.setGraph({
+      rankdir: direction,
+      nodesep: 100, // 节点间距
+      ranksep: 100, // 层级间距
+      marginx: 20,
+      marginy: 20
+    })
+
+    // 添加节点到 dagre 图
+    nodes.forEach(node => {
+      dagreGraph.setNode(node.id, {
+        width: nodeWidth,
+        height: nodeHeight
+      })
+    })
+
+    // 添加边到 dagre 图
+    edges.forEach(edge => {
+      if (edge.source && edge.target) {
+        dagreGraph.setEdge(edge.source, edge.target)
+      }
+    })
+
+    // 计算布局
+    dagre.layout(dagreGraph)
+
+    // 转换节点位置
+    const layoutedNodes = nodes.map(node => {
+      const nodeWithPosition = dagreGraph.node(node.id)
+
+      return {
+        ...node,
+        targetPosition: isHorizontal ? 'left' : 'top',
+        sourcePosition: isHorizontal ? 'right' : 'bottom',
+        position: {
+          x: nodeWithPosition.x - nodeWidth / 2 + Math.random() * 10,
+          y: nodeWithPosition.y - nodeHeight / 2 + Math.random() * 10
+        }
+      }
+    })
+
+    return layoutedNodes
+  }, [])
+
+  // 初始化布局
+
+  const initFu = useCallback(() => {
+    if (initialNodesWithoutPosition.length > 0) {
+      const layoutedNodes = applyAutoLayout(
+        initialNodesWithoutPosition,
+        initialEdges,
+        layoutDirection
+      )
+      setNodes(layoutedNodes)
+      setEdges(initialEdges)
+
+      // 自适应视图
+      setTimeout(() => {
+        fitView({ duration: 300, padding: 0.1 })
+      }, 100)
+    }
+  }, [applyAutoLayout, fitView, initialEdges, initialNodesWithoutPosition, setEdges, setNodes])
+
+  useEffect(() => {
+    initFu()
+  }, [initFu])
+
+  // 处理节点点击
+  const onNodeClick = useCallback((event: React.MouseEvent, node: any) => {
+    console.log('------', event, node)
+  }, [])
+
+  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={initFu}>
+        <img src={require('@/assets/three/Reset.png')} alt='' />
+        <div>重置</div>
+      </div>
+
+      <div className={classNames('A5Amain')} style={{ width: '100%', height: '100%' }}>
+        <ReactFlow
+          nodes={nodes}
+          edges={edges}
+          onNodesChange={onNodesChange}
+          onEdgesChange={onEdgesChange}
+          onNodeClick={onNodeClick} // 添加这行
+          fitView
+        ></ReactFlow>
+      </div>
+    </div>
+  )
+}
+
+// 主组件,用 ReactFlowProvider 包裹
+function A5atlas() {
+  return (
+    <ReactFlowProvider>
+      <FlowChart />
+    </ReactFlowProvider>
+  )
+}
+
+const MemoA5atlas = React.memo(A5atlas)
+
+export default MemoA5atlas

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

@@ -41,6 +41,7 @@
       .relation-graph {
         background-image: url('../../../../assets/three/background.jpg');
         background-size: 100% 100%;
+        // pointer-events: none;
       }
 
       // 样式重置
@@ -128,6 +129,13 @@
         // }
       }
     }
+
+    .A5AmainAc {
+      .relation-graph {
+        pointer-events: auto;
+      }
+    }
+
     .rel-link-peel {
       pointer-events: none !important;
     }

+ 8 - 2
project/src/pages/A5view/PageSon/A5atlas/index2.tsx

@@ -1,5 +1,5 @@
 import React, { useCallback, useEffect, useRef, useState } from 'react'
-import styles from './index.module.scss'
+import styles from './index2.module.scss'
 import { infoPageIDGet } from '@/utils/locStore'
 import history from '@/utils/history'
 
@@ -9,6 +9,8 @@ import { baseOssUrl } from '@/utils/http'
 import { urlCanRes } from '@/utils/urlCan'
 import classNames from 'classnames'
 
+const isMobile = /Android|webOS|iPhone|iPad|iPod/i.test(navigator.userAgent)
+
 function A5atlas() {
   // 通过id高亮线条
   const liangXianFu = useCallback((id: string) => {
@@ -86,7 +88,11 @@ function A5atlas() {
         <div>重置</div>
       </div>
 
-      <div className={classNames('A5Amain')}>
+      <div
+        className={classNames('A5Amain', isMobile ? '' : 'A5AmainAc')}
+        // 可选:防止移动浏览器在拖动/缩放时的一些默认行为
+        style={{ touchAction: 'none' }}
+      >
         <RelationGraph
           ref={graphRef}
           options={{

+ 0 - 4
project/src/pages/A5view/初始化组件/index.module.scss

@@ -1,4 +0,0 @@
-  .AAAAA {
-  :global {
-  }
-}

+ 0 - 13
project/src/pages/A5view/初始化组件/index.tsx

@@ -1,13 +0,0 @@
-import React from 'react'
-import styles from './index.module.scss'
-function AAAAA() {
-  return (
-    <div className={styles.AAAAA}>
-      <h1>AAAAA</h1>
-    </div>
-  )
-}
-
-const MemoAAAAA = React.memo(AAAAA)
-
-export default MemoAAAAA

+ 4 - 3
project/src/pages/初始化组件/index.module.scss

@@ -1,4 +1,5 @@
-  .AAAAA {
-  :global {
+.AAAAA{
+  :global{
+    
   }
-}
+}