|
@@ -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>
|