Explorar o código

支持图谱放大缩小

cynthia-qin hai 3 semanas
pai
achega
7dfd8d7d1b
Modificáronse 3 ficheiros con 69 adicións e 16 borrados
  1. 0 3
      components.d.ts
  2. 1 1
      package-lock.json
  3. 68 12
      src/dialogs/GraphNodeDialog.vue

+ 0 - 3
components.d.ts

@@ -24,7 +24,6 @@ declare module 'vue' {
     ElContainer: typeof import('element-plus/es')['ElContainer']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
     ElDialog: typeof import('element-plus/es')['ElDialog']
-    ElDivider: typeof import('element-plus/es')['ElDivider']
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
     ElDropdown: typeof import('element-plus/es')['ElDropdown']
     ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
@@ -42,7 +41,6 @@ declare module 'vue' {
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
     ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup']
     ElOption: typeof import('element-plus/es')['ElOption']
-    ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
     ElPagination: typeof import('element-plus/es')['ElPagination']
     ElPopover: typeof import('element-plus/es')['ElPopover']
     ElRadio: typeof import('element-plus/es')['ElRadio']
@@ -61,7 +59,6 @@ declare module 'vue' {
     ElTabs: typeof import('element-plus/es')['ElTabs']
     ElTag: typeof import('element-plus/es')['ElTag']
     ElText: typeof import('element-plus/es')['ElText']
-    ElTooltip: typeof import('element-plus/es')['ElTooltip']
     ElTree: typeof import('element-plus/es')['ElTree']
     ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
     ElUpload: typeof import('element-plus/es')['ElUpload']

+ 1 - 1
package-lock.json

@@ -5311,7 +5311,7 @@
     },
     "node_modules/svg-pan-zoom": {
       "version": "3.6.2",
-      "resolved": "https://registry.npmjs.org/svg-pan-zoom/-/svg-pan-zoom-3.6.2.tgz",
+      "resolved": "https://registry.npmmirror.com/svg-pan-zoom/-/svg-pan-zoom-3.6.2.tgz",
       "integrity": "sha512-JwnvRWfVKw/Xzfe6jriFyfey/lWJLq4bUh2jwoR5ChWQuQoOH8FEh1l/bEp46iHHKHEJWIyFJETbazraxNWECg==",
       "license": "BSD-2-Clause"
     },

+ 68 - 12
src/dialogs/GraphNodeDialog.vue

@@ -1,8 +1,13 @@
 <template>
   <el-dialog v-model="dialogFormVisible" title="图谱节点详情" width="1100" height="600">
+    <!-- 新增按钮组 -->
+    <div class="zoom-controls">
+      <el-button @click="zoomIn">放大</el-button>
+      <el-button @click="zoomOut">缩小</el-button>
+    </div>
     <div id="graph" class="graph">
 
-      <svg id="mindSvg" ref="svgContainer" viewBox="0 0 900 600" width="900" height="600">
+      <svg id="mindSvg" ref="svgContainer" viewBox="0 0 900 600" width="1000" height="600">
         <!-- 定义箭头 -->
         <defs>
           <marker id="arrow" viewBox="0 -5 10 10" refX="8" refY="0" markerWidth="6" markerHeight="6" orient="auto">
@@ -21,7 +26,7 @@
 
 <script setup lang="ts">
 
-import { ref, onMounted, nextTick } from 'vue'
+import { ref, onMounted, nextTick, watch } from 'vue'
 import { getNodeNeighbors } from '@/api/GraphApi'
 import svgPanZoom from 'svg-pan-zoom';
 import { ElMessageBox } from 'element-plus';
@@ -29,12 +34,33 @@ const dialogFormVisible = ref(false)
 const nodesData = ref([{ id: 1, label: 'Node 1', direction: "in" }])
 const edgesData = ref([{ from: 1, to: 2, fromPos: { x: 100, y: 100 }, toPos: { x: 100, y: 100 } }])
 const svgContainer = ref()
+const panZoomController = ref<any>(null)
+
 const props = defineProps({
   title: { type: String, required: true, default: '图谱节点详情' },
   nodeId: { type: Number, default: 0 },
   graphId: { type: Number, required: true, default: 0 }
-
 })
+
+// 使用 watch 监听 svgContainer 的变化
+watch(svgContainer, (newValue) => {
+  if (newValue) {
+    initSvgPanZoom(newValue);
+  }
+}, { immediate: true });
+
+const initSvgPanZoom = (svgElement: any) => {
+  panZoomController.value = svgPanZoom(svgElement, {
+    zoomEnabled: true,
+    controlIconsEnabled: false,
+    fit: true,
+    center: true,
+    minZoom: 0.1, // 最小缩放比例
+    maxZoom: 10,  // 最大缩放比例
+  });
+  console.log('panZoomController initialized:', panZoomController.value);
+}
+
 const loadNodeNeighbors = (node_id: number) => {
   nodesData.value.length = 0
   edgesData.value.length = 0
@@ -43,20 +69,15 @@ const loadNodeNeighbors = (node_id: number) => {
       const element = res.records[i];
       console.log(element)
       nodesData.value.push({ id: element.id, label: element.name, direction: element.direction })
-
     }
     drawGraph(node_id)
   })
 }
 function handleNodeClick(nodeId: any) {
   loadNodeNeighbors(Number(nodeId))
-  // var result = ElMessageBox.confirm('是否加载该节点的邻居节点?', '提示', )
-  // result.then(() => {
-
-  // })
 }
 const drawGraph = (node_id: number) => {
-  const svg = svgContainer.value //document.getElementById('mindSvg') as SVGElement | null;
+  const svg = svgContainer.value 
   if (svg == null) {
     console.log("svg is null")
     console.log(svgContainer.value)
@@ -174,20 +195,45 @@ const drawGraph = (node_id: number) => {
       handleNodeClick(nodeId)
     });
   })
+// 绘制完成后重新初始化 svgPanZoom
+if (panZoomController.value) {
+  panZoomController.value.destroy();
+}
+initSvgPanZoom(svg);
 
 }
-let panZoomController: any = null;
+// let panZoomController: any = null;
 
 onMounted(() => {
   nextTick(() => {
-
+    if (svgContainer.value) {
+      initSvgPanZoom(svgContainer.value);
+    }
   });
 });
+
+
+
+// 新增放大函数
+const zoomIn = () => {
+  console.log('panZoomController', panZoomController.value)
+  if (panZoomController.value) {
+    panZoomController.value.zoomIn();
+  }
+}
+
+// 新增缩小函数
+const zoomOut = () => {
+  if (panZoomController.value) {
+    panZoomController.value.zoomOut();
+  }
+}
+
 const showDialog = (visible: boolean = true, nodeId: number) => {
   dialogFormVisible.value = visible
-
   loadNodeNeighbors(nodeId)
 }
+
 defineExpose({ showDialog })
 </script>
 <style scoped>
@@ -198,6 +244,8 @@ defineExpose({ showDialog })
   flex-direction: column;
   align-items: center;
   justify-content: center;
+  /* 确保 SVG 元素可以正常缩放 */
+  overflow: hidden; 
 }
 
 .edge_line {
@@ -213,4 +261,12 @@ defineExpose({ showDialog })
   background-color: #cecece;
   z-index: 10;
 }
+
+/* 新增按钮样式 */
+.zoom-controls {
+  margin-bottom: 10px;
+  display: flex;
+  gap: 10px;
+  justify-content: center;
+}
 </style>