|
|
@@ -1,15 +1,104 @@
|
|
|
-import React from "react";
|
|
|
-import styles from "./index.module.scss";
|
|
|
-// import { ReactComponent as GraphSvg } from '@/assets/img/Graph.svg'
|
|
|
-function GraphSvg() {
|
|
|
+import React, { useEffect, useRef, useState } from 'react'
|
|
|
+import styles from './index.module.scss'
|
|
|
+import { ReactComponent as GraphSvg } from '@/assets/img/Graph.svg'
|
|
|
+import svgPanZoom from 'svg-pan-zoom'
|
|
|
+import { useDrag } from '@use-gesture/react'
|
|
|
+
|
|
|
+const MAIN_CONTENT_WIDTH = 1920
|
|
|
+const MAIN_CONTENT_HEIGHT = 945
|
|
|
+const MINIMAP_SCALE = 0.045
|
|
|
+function SvgGraph() {
|
|
|
+ const [startX, setStartX] = useState(0)
|
|
|
+ const [startY, setStartY] = useState(0)
|
|
|
+ const [offsetX, setOffsetX] = useState(0)
|
|
|
+ const [offsetY, setOffsetY] = useState(0)
|
|
|
+ const svgRef = useRef<any>(null)
|
|
|
+ const panZoomInstance = useRef<ReturnType<typeof svgPanZoom> | null>(null)
|
|
|
+
|
|
|
+ // 小地图相关逻辑
|
|
|
+
|
|
|
+ const miniMapScale = 0.1
|
|
|
+
|
|
|
+ // 小地图拖拽绑定
|
|
|
+ const bind = useDrag(({ offset: [x, y] }) => {
|
|
|
+ if (!panZoomInstance.current) return;
|
|
|
+ console.log(123123, offsetX, offsetY)
|
|
|
+ // 计算视口位置
|
|
|
+ const viewportX = x / miniMapScale; // 减去初始 X 偏移
|
|
|
+ const viewportY = y / miniMapScale;
|
|
|
+
|
|
|
+
|
|
|
+ // 更新主视图位置
|
|
|
+ panZoomInstance.current.pan({ // 使用正确的实例方法
|
|
|
+ x: -viewportX,
|
|
|
+ y: -viewportY
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ // 设置拖拽
|
|
|
+ useEffect(() => {
|
|
|
+ if (svgRef.current) {
|
|
|
+ // 初始化 svg-pan-zoom
|
|
|
+ svgRef.current.setAttribute('viewBox', '0 0 3000 800')
|
|
|
+ panZoomInstance.current = svgPanZoom(svgRef.current, {
|
|
|
+ zoomEnabled: false,
|
|
|
+ dblClickZoomEnabled: false,
|
|
|
+ panEnabled: true,
|
|
|
+ controlIconsEnabled: false,
|
|
|
+ fit: false,
|
|
|
+ contain: false,
|
|
|
+ center: false,
|
|
|
+ beforePan: (newPos) => {
|
|
|
+ console.log(456, newPos.x, newPos.y)
|
|
|
+ setOffsetX(newPos.x);
|
|
|
+ setOffsetY(newPos.y);
|
|
|
+ },
|
|
|
+ })
|
|
|
+ panZoomInstance.current.pan({ x: 300, y: 100 })
|
|
|
+ panZoomInstance.current.zoom(2.85)
|
|
|
+ // setOffsetX(0)
|
|
|
+ // setOffsetY(-200)
|
|
|
+ }
|
|
|
+
|
|
|
+ return () => {
|
|
|
+ // 组件卸载时销毁实例
|
|
|
+ if (panZoomInstance.current) {
|
|
|
+ panZoomInstance.current.destroy()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [])
|
|
|
|
|
|
return (
|
|
|
- <div className={styles.graphSvg}>
|
|
|
- {/* <GraphSvg className={styles.graphSvg} /> */}
|
|
|
- </div>
|
|
|
+ <>
|
|
|
+ <div className={styles.SVGContainner}>
|
|
|
+ <GraphSvg ref={svgRef} className='graphSvg' />
|
|
|
+ </div>
|
|
|
+ <div className={styles.miniMap}>
|
|
|
+ <div
|
|
|
+ className={styles.viewport}
|
|
|
+ {...bind({ offsetX, offsetY })}
|
|
|
+ style={{
|
|
|
+ transform: `translate(${-offsetX * miniMapScale}px, ${-offsetY * miniMapScale}px)`,
|
|
|
+ width: `${MAIN_CONTENT_WIDTH * MINIMAP_SCALE}px`,
|
|
|
+ height: `${MAIN_CONTENT_HEIGHT * MINIMAP_SCALE}px`
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <div
|
|
|
+ className={styles.miniContent}
|
|
|
+ style={{
|
|
|
+ transform: `scale(${miniMapScale})`,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <GraphSvg className='graphSvg' />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-const MemoGraphSvg = React.memo(GraphSvg);
|
|
|
+const MemoSvgGraph = React.memo(SvgGraph)
|
|
|
|
|
|
-export default MemoGraphSvg;
|
|
|
+export default MemoSvgGraph
|