Jelajahi Sumber

大场景热点跳转与家谱

lanxin 3 minggu lalu
induk
melakukan
01f0790e79

+ 16 - 5
src/pages/A6ybwx/Genealogy/components/Graph/index.module.scss

@@ -4,12 +4,23 @@
   touch-action: none;
   pointer-events: auto !important;
   position: relative;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  transition: all 0.1s linear;
   :global {
-    .nodeActiveG {
-      position: absolute;
-      top: 50%;
-      left: 50%;
-      transform: translate(-50%, -50%);
+    .nodeClickData {
+      transition: all 0.1s linear;
+      // background-color: #ccc;
+      width: 100%;
+      height: 100%;
+      pointer-events: none;
+      .nodeActiveG {
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+      }
     }
   }
 }

+ 132 - 104
src/pages/A6ybwx/Genealogy/components/Graph/index.tsx

@@ -1,7 +1,6 @@
 import React, { useCallback, useEffect, useRef, useState } from 'react'
 import styles from './index.module.scss'
 import { NodeTurnRight, NodeRight, NodeBottom, RightLineDash, NodeActive, NodeTurnBottomRight, NodeRightDash, NodeBottomDash, NodeTurnBottomDashRight } from '../Utils'
-import { useDrag } from '@use-gesture/react'
 import { isMobiileFu } from '@/utils/history'
 import { useSelector } from 'react-redux'
 import { RootState } from '@/store'
@@ -14,8 +13,9 @@ function Graph({ setCurrentNodeIndex }: { setCurrentNodeIndex: (index: number) =
   const { myData } = useSelector((state: RootState) => state.A0Layout)
 
   const [isDragging, setIsDragging] = useState(false)
-  const [startX, setStartX] = useState(0)
-  const [startY, setStartY] = useState(0)
+  const [zoom, setZoom] = useState(1)
+  const [zoomOrigin, setZoomOrigin] = useState({ x: 0, y: 200 })
+  const [isDraggingMiniMap, setIsDraggingMiniMap] = useState(false)
   const [offsetX, setOffsetX] = useState(0)
   const [offsetY, setOffsetY] = useState(0)
 
@@ -47,37 +47,32 @@ function Graph({ setCurrentNodeIndex }: { setCurrentNodeIndex: (index: number) =
     startOffsetY: 0  // 元素起始偏移 Y
   });
 
-  // 针对移动端miniMap
+  // 鼠标位置
+  const mousePositionRef = useRef({ x: 0, y: 0 })
+  // 针对移动端miniMap 将数据存在ref中 计算偏移量,限制大小
   useEffect(() => {
+    if (!isMobiileFu()) return
     const miniMapViewport = document.getElementById('miniMapViewport') as HTMLDivElement
     if (!miniMapViewport) return
 
     const handleTouchStart = (e: TouchEvent) => {
-      console.log('touchStart')
       const touch = e.touches[0];
-      // 记录触摸起始坐标
       miniMapStartRef.current.startX = touch.clientX;
       miniMapStartRef.current.startY = touch.clientY;
-
       miniMapStartRef.current.startOffsetX = offsetX;
       miniMapStartRef.current.startOffsetY = offsetY;
 
     }
-
     const handleTouchMove = (e: TouchEvent) => {
-      console.log('touchMove')
       const touch = e.touches[0];
       if (!touch) return;
-      // 计算滑动距离 = 当前触摸位置 - 初始触摸位置
       const dx = touch.clientY - miniMapStartRef.current.startY;
       const dy = -touch.clientX + miniMapStartRef.current.startX;
-
       setOffsetX(prev => {
         const newX = miniMapStartRef.current.startOffsetX - dx * 18;
         return Math.min(0, Math.max(-1640, newX));
         // return newX
       });
-
       setOffsetY(prev => {
         const newY = miniMapStartRef.current.startOffsetY - dy * 7;
         return Math.min(0, Math.max(-350, newY));
@@ -85,98 +80,140 @@ function Graph({ setCurrentNodeIndex }: { setCurrentNodeIndex: (index: number) =
       });
 
     }
-
     miniMapViewport.addEventListener('touchstart', handleTouchStart)
     miniMapViewport.addEventListener('touchmove', handleTouchMove)
-
     return () => {
       miniMapViewport.removeEventListener('touchstart', handleTouchStart)
       miniMapViewport.removeEventListener('touchmove', handleTouchMove)
     }
   }, [contentSize.height, contentSize.width, offsetX, offsetY])
 
+  // 针对PC端miniMap
+  useEffect(() => {
+    if (isMobiileFu()) return
+    const miniMapViewport = document.getElementById('miniMapViewport') as HTMLDivElement
+    if (!miniMapViewport) return
+
+    const handleMouseDown = (e: MouseEvent) => {
+      e.stopPropagation()
+      if (e.target !== miniMapViewport) return
+      setIsDraggingMiniMap(true)
+      miniMapStartRef.current.startX = e.clientX;
+      miniMapStartRef.current.startY = e.clientY;
+      miniMapStartRef.current.startOffsetX = offsetX;
+      miniMapStartRef.current.startOffsetY = offsetY;
+    }
+    const handleMouseMove = (e: MouseEvent) => {
+      e.stopPropagation()
+      const dx = -e.clientX + miniMapStartRef.current.startX
+      const dy = -e.clientY + miniMapStartRef.current.startY
+      if (!isDraggingMiniMap) return
+      setOffsetX(prev => {
+        const newX = miniMapStartRef.current.startOffsetX + dx * 5;
+        return Math.min(0, Math.max(-1640, newX));
+      });
+      setOffsetY(prev => {
+        const newY = miniMapStartRef.current.startOffsetY + dy * 7;
+        return Math.min(0, Math.max(-350, newY));
+        // return newY
+      });
+    }
+    const handleMouseUp = (e: MouseEvent) => {
+      e.stopPropagation()
+      miniMapViewport.removeEventListener('mousemove', handleMouseMove)
+      setIsDraggingMiniMap(false)
+    }
+    document.addEventListener('mousedown', handleMouseDown)
+    miniMapViewport.addEventListener('mousemove', handleMouseMove)
+    document.addEventListener('mouseup', handleMouseUp)
+
+    return () => {
+      document.removeEventListener('mousedown', handleMouseDown)
+      miniMapViewport.removeEventListener('mousemove', handleMouseMove)
+      document.removeEventListener('mouseup', handleMouseUp)
+    }
+  }, [contentSize.height, contentSize.width, isDraggingMiniMap, offsetX, offsetY])
 
 
+  // 主视角地图的Pc
   const handleMouseDown = (e: React.MouseEvent) => {
-    if (e.target === e.currentTarget) { // 仅当点击容器本身时触发拖拽
-      e.stopPropagation();
+    if (e.target === e.currentTarget) {
       setIsDragging(true);
-      setStartX(e.clientX);
-      setStartY(e.clientY);
-      setOffsetX(offsetX);
-      setOffsetY(offsetY);
+      startRef.current.startX = e.clientX;
+      startRef.current.startY = e.clientY;
+      startRef.current.startOffsetX = offsetX;
+      startRef.current.startOffsetY = offsetY;
     }
   }
-
-  const handleTouchStart = useCallback((e: React.TouchEvent) => {
-    const touch = e.touches[0]; // 获取第一个触摸点(单指拖拽)
-    // if (!touch) return;
-
-    // 记录触摸起始坐标
-    startRef.current.startX = touch.clientX;
-    startRef.current.startY = touch.clientY;
-
-    // 记录元素当前偏移量(避免拖拽时跳跃)
-    startRef.current.startOffsetX = offsetX;
-    startRef.current.startOffsetY = offsetY;
-
-  }, [offsetX, offsetY])
+  const handleMouseUp = () => setIsDragging(false)
 
   const handleMouseMove = (e: React.MouseEvent) => {
-    if (isDragging) {
-      // 改为使用初始点击位置计算总位移
-      const dx = e.clientX - startX
-      const dy = e.clientY - startY
+    console.log('move')
+    // 记录鼠标位置
+    const x = (e.clientX / 2.28 - offsetX)
+    const y = (e.clientY / 2.28 - offsetY)
+    mousePositionRef.current = { x, y }
+    // setZoomOrigin({ x, y })
 
-      // 使用函数式更新确保获取最新状态值
-      // setOffsetX(prev => {
-      //   const newX = prev + dx
-      //   return Math.min(0, Math.max(-1640, newX))
-      // })
-
-      setOffsetX(Math.min(0, Math.max(-1640, offsetX + dx)))
+    if (isDragging) {
+      if (zoom !== 1) {
+        setZoom(1)
+        return
+      }
+      const dx = e.clientX - startRef.current.startX
+      const dy = e.clientY - startRef.current.startY
+      setOffsetX(prev => {
+        const newX = startRef.current.startOffsetX + dx;
+        return Math.min(0, Math.max(-1640, newX));
+        // return newX
+      });
+      setOffsetY(prev => {
+        const newY = startRef.current.startOffsetY + dy;
+        return Math.min(0, Math.max(-350, newY));
+        // return newY
+      });
+    }
+  }
 
-      // setOffsetY(prev => {
-      //   const newY = prev + dy
-      //   return Math.min(0, Math.max(-350, newY))
-      // })
 
-      setOffsetY(Math.min(0, Math.max(-350, offsetY + dy)))
+  const onWheel = (e: React.WheelEvent) => {
+    console.log(e.deltaY, 'e.deltaY')
+    // 计算新的缩放比例
+    const delta = e.deltaY;
+    const newZoom = Math.min(1.5, Math.max(0.8, zoom - delta * 0.001));
+    console.log(zoom, mousePositionRef.current);
 
-      // 更新起始坐标为当前鼠标位置(保持相对移动)
-      setStartX(e.clientX)
-      setStartY(e.clientY)
+    if (Math.abs(zoom - 1) < 0.05) {
+      setZoomOrigin(mousePositionRef.current)
     }
+    setZoom(newZoom);
   }
-
+  // 主视角地图的移动端
+  const handleTouchStart = useCallback((e: React.TouchEvent) => {
+    const touch = e.touches[0]
+    // 记录触摸起始坐标
+    startRef.current.startX = touch.clientX;
+    startRef.current.startY = touch.clientY;
+    startRef.current.startOffsetX = offsetX;
+    startRef.current.startOffsetY = offsetY;
+  }, [offsetX, offsetY])
   const handleTouchMove = useCallback((e: React.TouchEvent) => {
     const touch = e.touches[0];
     if (!touch) return;
-
-    // 计算滑动距离 = 当前触摸位置 - 初始触摸位置
     const dx = touch.clientY - startRef.current.startY;
     const dy = -touch.clientX + startRef.current.startX;
-
-    // 更新 X 偏移量(限制范围:-1640 ~ 0,与你原有逻辑一致)
     setOffsetX(prev => {
-      const newX = startRef.current.startOffsetX + dx; // 基于初始偏移量计算
+      const newX = startRef.current.startOffsetX + dx;
       return Math.min(0, Math.max(-1640, newX));
       // return newX
     });
-
-    // 更新 Y 偏移量(限制范围:-350 ~ 0)
     setOffsetY(prev => {
       const newY = startRef.current.startOffsetY + dy;
       return Math.min(0, Math.max(-350, newY));
       // return newY
     });
-
   }, [])
 
-  const handleMouseUp = () => {
-    setIsDragging(false)
-  }
-
 
 
   // 动态获取容器尺寸
@@ -185,20 +222,8 @@ function Graph({ setCurrentNodeIndex }: { setCurrentNodeIndex: (index: number) =
       setContentSize({ width: graphRef.current.clientWidth, height: graphRef.current.clientHeight })
     }
   }, [])
-
-  // 小地图拖拽绑定
-  const bind = useDrag(({ initial: [initX, initY], offset: [x, y] }) => {
-    console.log(initX, initY, x, y, 'bind')
-    // 计算视口最大移动范围
-    const maxX = contentSize.width * miniMapScale - MAIN_CONTENT_WIDTH * MINIMAP_SCALE - 2
-    const maxY = contentSize.height * miniMapScale - MAIN_CONTENT_HEIGHT * MINIMAP_SCALE - 4
-    // 钳制坐标范围
-    const clampedX = Math.max(0, Math.min(x, maxX))
-    const clampedY = Math.max(0, Math.min(y, maxY))
-    setOffsetX(-clampedX / miniMapScale)
-    setOffsetY(-clampedY / miniMapScale)
-  })
-
+  // const maxX = contentSize.width * miniMapScale - MAIN_CONTENT_WIDTH * MINIMAP_SCALE - 2
+  // const maxY = contentSize.height * miniMapScale - MAIN_CONTENT_HEIGHT * MINIMAP_SCALE - 4
 
   const handleNameClick = (index: number) => {
     console.log(index, '------------')
@@ -206,7 +231,7 @@ function Graph({ setCurrentNodeIndex }: { setCurrentNodeIndex: (index: number) =
   }
 
   const NodeData = React.memo(() =>
-    <>
+    <div className='nodeData'>
       {myData.genealogyData.map((item, index) => {
         let res
         if (item.type === 'active') res = <NodeActive key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} className='nodeActiveG' />
@@ -225,31 +250,33 @@ function Graph({ setCurrentNodeIndex }: { setCurrentNodeIndex: (index: number) =
         if (item.type === 'nodeTurnBottomDashRight_n') res = <NodeTurnBottomDashRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' />
         return res
       })}
-    </>
+    </div>
   )
 
 
   const NodeClickData = React.memo(() =>
-    <>
-      {myData.genealogyData.map((item, index) => {
-        let res
-        if (item.type === 'active') res = <NodeActive key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} nameClick={() => handleNameClick(index)} className='nodeActiveG' />
-        if (item.type === 'nodeRight_n') res = <NodeRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
-        if (item.type === 'nodeRight_a') res = <NodeRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='active' />
-        if (item.type === 'nodeRight_f') res = <NodeRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='false' nameClick={() => handleNameClick(index)} />
-        if (item.type === 'nodeBottom_n') res = <NodeBottom key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
-        if (item.type === 'nodeTurnRight_n') res = <NodeTurnRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
-        if (item.type === 'nodeTurnRight_a') res = <NodeTurnRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='active' />
-        if (item.type === 'nodeTurnBottomRight_a') res = <NodeTurnBottomRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='active' />
-        if (item.type === 'nodeTurnBottomRight_n') res = <NodeTurnBottomRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
-        if (item.type === 'nodeRight_dash_n') res = <NodeRightDash key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
-        if (item.type === 'nodeRight_dash_a') res = <NodeRightDash key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='active' />
-        if (item.type === 'nodeRight_dash_f') res = <NodeRightDash key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='false' nameClick={() => handleNameClick(index)} />
-        if (item.type === 'nodeBottom_dash_n') res = <NodeBottomDash key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
-        if (item.type === 'nodeTurnBottomDashRight_n') res = <NodeTurnBottomDashRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
-        return res
-      })}
-    </>
+    <div className='nodeClickData' id='nodeClickData' style={{ transform: `scale(${zoom})`, transformOrigin: `${zoomOrigin.x}px ${zoomOrigin.y}px` }}>
+      {
+        myData.genealogyData.map((item, index) => {
+          let res
+          if (item.type === 'active') res = <NodeActive key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} nameClick={() => handleNameClick(index)} className='nodeActiveG' />
+          if (item.type === 'nodeRight_n') res = <NodeRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
+          if (item.type === 'nodeRight_a') res = <NodeRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='active' />
+          if (item.type === 'nodeRight_f') res = <NodeRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='false' nameClick={() => handleNameClick(index)} />
+          if (item.type === 'nodeBottom_n') res = <NodeBottom key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
+          if (item.type === 'nodeTurnRight_n') res = <NodeTurnRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
+          if (item.type === 'nodeTurnRight_a') res = <NodeTurnRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='active' />
+          if (item.type === 'nodeTurnBottomRight_a') res = <NodeTurnBottomRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='active' />
+          if (item.type === 'nodeTurnBottomRight_n') res = <NodeTurnBottomRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
+          if (item.type === 'nodeRight_dash_n') res = <NodeRightDash key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
+          if (item.type === 'nodeRight_dash_a') res = <NodeRightDash key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='active' />
+          if (item.type === 'nodeRight_dash_f') res = <NodeRightDash key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='false' nameClick={() => handleNameClick(index)} />
+          if (item.type === 'nodeBottom_dash_n') res = <NodeBottomDash key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
+          if (item.type === 'nodeTurnBottomDashRight_n') res = <NodeTurnBottomDashRight key={index} data={item} style={{ transform: `translate(${item.position.x}px, ${item.position.y}px)` }} type='normal' nameClick={() => handleNameClick(index)} />
+          return res
+        })
+      }
+    </div >
   )
 
 
@@ -265,12 +292,14 @@ function Graph({ setCurrentNodeIndex }: { setCurrentNodeIndex: (index: number) =
         onMouseLeave={handleMouseUp}
         onTouchStart={handleTouchStart}
         onTouchMove={handleTouchMove}
+        onWheel={onWheel}
         style={{
           cursor: isDragging ? 'grabbing' : 'grab',
-          transform: `translate(${offsetX}px, ${offsetY}px)`,
+          transform: `translate(${offsetX}px, ${offsetY}px) `,
           userSelect: 'none'
         }}
       >
+        {/* <div className="fixed" style={{ width: '5px', height: '5px', backgroundColor: '#000', borderRadius: '50%', position: 'absolute', top: '0', left: '0', transform: `translate(${zoomOrigin.x}px,${zoomOrigin.y}px)` }}></div> */}
         <NodeClickData />
       </div>
       <div className={styles.tip}>
@@ -289,7 +318,6 @@ function Graph({ setCurrentNodeIndex }: { setCurrentNodeIndex: (index: number) =
         <div
           className={styles.viewport}
           id='miniMapViewport'
-          {...(isMobiileFu() ? null : bind())}
           style={{
             transform: `translate(${-offsetX * miniMapScale}px, ${-offsetY * miniMapScale}px)`,
             width: `${MAIN_CONTENT_WIDTH * MINIMAP_SCALE}px`,

+ 3 - 1
src/pages/A7wjwj/conponents/Content/index.tsx

@@ -15,7 +15,9 @@ function Content() {
     setIsShowPano(false)
     setIsShowPoem(false)
     panoramicRoot.style.display = 'none'
-    window.location.replace('../index.html#/yblm')
+    store.dispatch({ type: 'layout/unityDel', payload: false })
+    store.dispatch({ type: 'layout/unityKey', payload: Date.now() })
+    window.location.replace('../index.html#/wjwj?to=yblm')
   }
   window.openPoem = () => {
     setIsShowPoem(true)

+ 5 - 1
src/pages/A7wjwj/index.tsx

@@ -44,7 +44,11 @@ function A7Wjwj() {
           callBackFu={() => {
             setTimeout(() => {
               setUnitySta(false)
-            }, 1000)
+              const search = new URLSearchParams(window.location.hash.split('?')[1] || '')
+              const to = search.get('to')
+              console.log(to)
+              if (to === 'yblm') window.location.replace('#/yblm')
+            }, 400)
           }}
         />
       ) : null}