瀏覽代碼

实现svg缩放

任一存 3 年之前
父節點
當前提交
ba0bde9801
共有 1 個文件被更改,包括 53 次插入27 次删除
  1. 53 27
      src/App.vue

+ 53 - 27
src/App.vue

@@ -1,25 +1,39 @@
 <template>
   <el-form label-position="left">
     <el-form-item label="场景名或完整url">
-      <el-input v-model="sceneNameOrUrl"></el-input>
+      <el-input v-model="sceneNameOrUrl" />
     </el-form-item>
-    <el-button @click="getWholeData" type="primary">重新获取全部数据点</el-button>
+    <el-button
+      type="primary"
+      @click="getWholeData"
+    >
+      重新获取全部数据点
+    </el-button>
   </el-form>
 
   <el-form label-position="top">
     <el-form-item label="路径1数据(必填)(在全部节点中的index,以英文逗号分隔)(蓝色圆圈表示)">
-      <el-input v-model="formData.path1"></el-input>
+      <el-input v-model="formData.path1" />
     </el-form-item>
     <el-form-item label="路径2数据(选填)(在全部节点中的index,以英文逗号分隔)(绿色数字1表示)">
-      <el-input v-model="formData.path2"></el-input>
+      <el-input v-model="formData.path2" />
     </el-form-item>
 
-    <el-button type="primary" @click="renderPath">显示路径</el-button>
-    <el-button @click="resetForm">Reset</el-button>
+    <el-button
+      type="primary"
+      @click="renderPath"
+    >
+      显示路径
+    </el-button>
+    <el-button @click="resetForm">
+      Reset
+    </el-button>
   </el-form>
 
-  <div>{{infoText}}</div>
-  <div class="svgWrapper"></div>
+  <div class="infoText">
+    {{ infoText }}
+  </div>
+  <div class="svgWrapper" />
 </template>
 
 <script>
@@ -31,7 +45,7 @@ const LENGTH_PER_POINT = 0.36
 
 // 视口尺寸
 let svgWidth = document.documentElement.clientWidth
-let svgHeight = document.documentElement.clientHeight - 300
+let svgHeight = document.documentElement.clientHeight - 330
 let viewportRatio = svgWidth / svgHeight
 
 let pxPerUnitLength = 0 // 原始单位长度对应的像素数
@@ -50,6 +64,9 @@ function resetGlobalVars() {
   yCenter = 0 
 }
 
+let svgNode = null
+let gNode = null
+
 export default {
   name: 'App',
   data() {
@@ -65,6 +82,13 @@ export default {
   },
   computed: {
   },
+  mounted() {
+    svgNode = d3.select('.svgWrapper').append("svg")
+      .attr("width", svgWidth)
+      .attr('height', svgHeight)
+    gNode = svgNode.append('g')
+    this.getWholeData()
+  },
   methods: {
     inputToArray(input) {
       let temp = input.trim()
@@ -91,9 +115,9 @@ export default {
       })
 
       resetGlobalVars()
-      d3.select('svg').selectAll('rect').remove()
-      d3.select('svg').selectAll('circle').remove()
-      d3.select('svg').selectAll('text').remove()
+      gNode.selectAll('rect').remove()
+      gNode.selectAll('circle').remove()
+      gNode.selectAll('text').remove()
 
       const that = this
       getWholeData(this.sceneNameOrUrl).then((res) => {
@@ -137,7 +161,7 @@ export default {
           wholeDataForRender.push([wholeXArrayInPx[index], wholeYArrayInPx[index], ...wholeInputPointArray[index], index])
         }
 
-        d3.select('svg').selectAll('rect').data(wholeDataForRender).enter().append('rect')
+        gNode.selectAll('rect').data(wholeDataForRender).enter().append('rect')
           .attr('x', (d) => d[0] - LENGTH_PER_POINT * pxPerUnitLength / 2)
           .attr('y', (d) => d[1] - LENGTH_PER_POINT * pxPerUnitLength / 2)
           .attr('width', LENGTH_PER_POINT * pxPerUnitLength)
@@ -147,7 +171,7 @@ export default {
             return d
           })
 
-        d3.select('svg').selectAll('rect').on('mouseover', function(e) {
+        gNode.selectAll('rect').on('mouseover', function(e) {
           d3.select(this).attr('fill', 'orange')
           let renderDataItem = e.target.attributes['render-data'].value.split(',')
           that.infoText = `数据点index(从0数起):${renderDataItem[renderDataItem.length - 1]}, \n具体值: ${renderDataItem.slice(2, 14).join(', ')}`
@@ -155,6 +179,13 @@ export default {
           d3.select(this).attr('fill', 'black')
           that.infoText = ''
         })
+
+        svgNode.call(d3.zoom().on("zoom", zoomed));
+
+        function zoomed({transform}) {
+          gNode.attr("transform", transform);
+        }
+
       }).finally(() => {
         this.loadingHandler.close()
       })
@@ -165,8 +196,8 @@ export default {
         return
       }
       
-      d3.select('svg').selectAll('circle').remove()
-      d3.select('svg').selectAll('text').remove()
+      gNode.selectAll('circle').remove()
+      gNode.selectAll('text').remove()
       
       let rawPathDataIndex = this.inputToArray(this.formData.path1)
       if (rawPathDataIndex === -1) {
@@ -236,14 +267,14 @@ export default {
       }
 
       // 进行渲染
-      d3.select('svg').selectAll('circle').data(pathDataForRender).enter().append('circle')
+      gNode.selectAll('circle').data(pathDataForRender).enter().append('circle')
         .attr('cx', (d) => d[0])
         .attr('cy', (d) => d[1])
         .attr('r', LENGTH_PER_POINT * pxPerUnitLength / 2)
         .attr('fill', 'blue')
         .attr('pointer-events', 'none')
       // todo: 不用数字,改用不同颜色的图形。
-      d3.select('svg').selectAll('text').data(pathDataForRender2).enter().append('text')
+      gNode.selectAll('text').data(pathDataForRender2).enter().append('text')
         .text('1')
         .attr('x', (d) => d[0])
         .attr('y', (d) => d[1] + LENGTH_PER_POINT * pxPerUnitLength / 2)
@@ -251,19 +282,12 @@ export default {
         .attr('text-anchor', 'middle')
         .attr('pointer-events', 'none')
         .attr('font-size', LENGTH_PER_POINT * pxPerUnitLength * 10)
-
     },
     resetForm() {
       this.formData.path1 = ''
       this.formData.path2 = ''
     },
   },
-  mounted() {
-    d3.select('.svgWrapper').append("svg")
-      .attr("width", svgWidth)
-      .attr('height', svgHeight)
-    this.getWholeData()
-  },
 }
 </script>
 
@@ -275,9 +299,11 @@ export default {
   text-align: center;
   color: #2c3e50;
 }
+.infoText {
+  min-height: 2em;
+}
 .svgWrapper {
-  position: absolute;
-  top: 300px;
+  overflow: hidden;
   background: #eee;
 }
 </style>