|
@@ -1,168 +1,258 @@
|
|
|
<template>
|
|
|
- {{infoText}}
|
|
|
+ <el-button @click="getWholeData" type="primary">重新获取全部数据点</el-button>
|
|
|
+ <el-form label-position="top">
|
|
|
+ <el-form-item label="路径1数据(必填)(在全部节点中的index,以英文逗号分隔)(蓝色圆圈表示)">
|
|
|
+ <el-input v-model="formData.path1"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="路径2数据(选填)(在全部节点中的index,以英文逗号分隔)(绿色数字1表示)">
|
|
|
+ <el-input v-model="formData.path2"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-button type="primary" @click="renderPath">显示路径</el-button>
|
|
|
+ <el-button @click="resetForm">Reset</el-button>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div>{{infoText}}</div>
|
|
|
<div class="svgWrapper"></div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import * as d3 from "d3";
|
|
|
-import rawWholeData from "../input-data/data3.js";
|
|
|
-import { path1 as rawPathDataIndex, path2 as rawPathDataIndex2 } from "../input-data/mock-path3.js";
|
|
|
+import { getWholeData } from "./api.js";
|
|
|
+import { ElLoading } from 'element-plus'
|
|
|
|
|
|
-// 基于path index 拿到path节点数组
|
|
|
-let rawPathData = {
|
|
|
- data: [
|
|
|
- ]
|
|
|
-}
|
|
|
-for (let index = 0; index < rawPathDataIndex.length; index++) {
|
|
|
- const element = rawWholeData.data[rawPathDataIndex[index]];
|
|
|
- rawPathData.data.push(element)
|
|
|
-}
|
|
|
-let rawPathData2 = {
|
|
|
- data: [
|
|
|
- ]
|
|
|
-}
|
|
|
-for (let index = 0; index < rawPathDataIndex2.length; index++) {
|
|
|
- const element = rawWholeData.data[rawPathDataIndex2[index]];
|
|
|
- rawPathData2.data.push(element)
|
|
|
-}
|
|
|
-
|
|
|
-// 原始字符串数组处理成二维数组
|
|
|
-let wholeInputPointArray = rawWholeData.data.map((eachString, index) => {
|
|
|
- console.assert(eachString.split(' ').length === 12, `index ${index}处数据点 数字个数不是12!`)
|
|
|
- return eachString.split(' ')
|
|
|
-})
|
|
|
-let pathInputPointArray = rawPathData.data.map((eachString) => {
|
|
|
- return eachString.split(' ')
|
|
|
-})
|
|
|
-let pathInputPointArray2 = rawPathData2.data.map((eachString) => {
|
|
|
- return eachString.split(' ')
|
|
|
-})
|
|
|
-
|
|
|
-// 所有点的分布情况
|
|
|
-let xArray = wholeInputPointArray.map((eachPoint) => {
|
|
|
- return eachPoint[0]
|
|
|
-})
|
|
|
-let xLength = Math.max(...xArray) - Math.min(...xArray)
|
|
|
-let xCenter = (Math.max(...xArray) + Math.min(...xArray)) / 2
|
|
|
-
|
|
|
-let yArray = wholeInputPointArray.map((eachPoint) => {
|
|
|
- return eachPoint[1]
|
|
|
-})
|
|
|
-
|
|
|
-let yLength = Math.max(...yArray) - Math.min(...yArray)
|
|
|
-let yCenter = (Math.max(...yArray) + Math.min(...yArray)) / 2
|
|
|
-
|
|
|
-console.log(`x轴分布范围: ${Math.min(...xArray)} 到 ${Math.max(...xArray)}`)
|
|
|
-console.log(`y轴分布范围: ${Math.min(...yArray)} 到 ${Math.max(...yArray)}`)
|
|
|
-
|
|
|
-let areaRatio = xLength / yLength
|
|
|
+const LENGTH_PER_POINT = 0.36
|
|
|
|
|
|
// 视口尺寸
|
|
|
-let viewportWidth = document.documentElement.clientWidth
|
|
|
-let viewportHeight = document.documentElement.clientHeight
|
|
|
-let viewportRatio = viewportWidth / viewportHeight
|
|
|
+let svgWidth = document.documentElement.clientWidth
|
|
|
+let svgHeight = document.documentElement.clientHeight - 300
|
|
|
+let viewportRatio = svgWidth / svgHeight
|
|
|
|
|
|
-// 各个点坐标映射到视口坐标
|
|
|
let pxPerUnitLength = 0 // 原始单位长度对应的像素数
|
|
|
-if (viewportRatio >= areaRatio) { // 视口高度应略小于y轴方向分布幅度
|
|
|
- pxPerUnitLength = viewportHeight / yLength * 0.9
|
|
|
-} else { // 视口宽度应略小于x轴方向分布幅度
|
|
|
- pxPerUnitLength = viewportWidth / xLength * 0.9
|
|
|
-}
|
|
|
-let wholeXArrayInPx = xArray.map((eachX) => {
|
|
|
- return (eachX - xCenter) * pxPerUnitLength + viewportWidth / 2
|
|
|
-})
|
|
|
-let wholeYArrayInPx = yArray.map((eachY) => {
|
|
|
- return (eachY - yCenter) * pxPerUnitLength + viewportHeight / 2
|
|
|
-})
|
|
|
-let pathXArrayInPx = pathInputPointArray.map((eachPoint) => {
|
|
|
- return eachPoint[0]
|
|
|
-}).map((eachX) => {
|
|
|
- return (eachX - xCenter) * pxPerUnitLength + viewportWidth / 2
|
|
|
-})
|
|
|
-let pathYArrayInPx = pathInputPointArray.map((eachPoint) => {
|
|
|
- return eachPoint[1]
|
|
|
-}).map((eachY) => {
|
|
|
- return (eachY - yCenter) * pxPerUnitLength + viewportHeight / 2
|
|
|
-})
|
|
|
-let pathXArrayInPx2 = pathInputPointArray2.map((eachPoint) => {
|
|
|
- return eachPoint[0]
|
|
|
-}).map((eachX) => {
|
|
|
- return (eachX - xCenter) * pxPerUnitLength + viewportWidth / 2
|
|
|
-})
|
|
|
-let pathYArrayInPx2 = pathInputPointArray2.map((eachPoint) => {
|
|
|
- return eachPoint[1]
|
|
|
-}).map((eachY) => {
|
|
|
- return (eachY - yCenter) * pxPerUnitLength + viewportHeight / 2
|
|
|
-})
|
|
|
-
|
|
|
-// 组合成最终数据用来渲染
|
|
|
+let rawWholeData = []
|
|
|
let wholeDataForRender = []
|
|
|
-for (let index = 0; index < wholeInputPointArray.length; index++) {
|
|
|
- wholeDataForRender.push([wholeXArrayInPx[index], wholeYArrayInPx[index], ...wholeInputPointArray[index], index])
|
|
|
-}
|
|
|
-let pathDataForRender = []
|
|
|
-for (let index = 0; index < pathInputPointArray.length; index++) {
|
|
|
- pathDataForRender.push([pathXArrayInPx[index], pathYArrayInPx[index], ...pathInputPointArray[index]])
|
|
|
-}
|
|
|
-let pathDataForRender2 = []
|
|
|
-for (let index = 0; index < pathInputPointArray2.length; index++) {
|
|
|
- pathDataForRender2.push([pathXArrayInPx2[index], pathYArrayInPx2[index], ...pathInputPointArray2[index]])
|
|
|
+
|
|
|
+// 全部数据点的分布中心
|
|
|
+let xCenter = 0
|
|
|
+let yCenter = 0
|
|
|
+
|
|
|
+function resetGlobalVars() {
|
|
|
+ pxPerUnitLength = 0 // 原始单位长度对应的像素数
|
|
|
+ rawWholeData = []
|
|
|
+ wholeDataForRender = []
|
|
|
+ xCenter = 0
|
|
|
+ yCenter = 0
|
|
|
}
|
|
|
|
|
|
export default {
|
|
|
name: 'App',
|
|
|
data() {
|
|
|
return {
|
|
|
- wholeInputPointArray,
|
|
|
- colNum: 15,
|
|
|
- infoText: ''
|
|
|
+ infoText: '',
|
|
|
+ loadingHandler: null,
|
|
|
+ formData: {
|
|
|
+ path1: '',
|
|
|
+ path2: '',
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
},
|
|
|
- mounted() {
|
|
|
- const that = this
|
|
|
- d3.select('.svgWrapper').append("svg").attr("width", document.documentElement.clientWidth).attr('height', document.documentElement.clientHeight)
|
|
|
-
|
|
|
- d3.select('svg').selectAll('rect').data(wholeDataForRender).enter().append('rect')
|
|
|
- .attr('x', (d) => d[0] - 0.36 * pxPerUnitLength / 2)
|
|
|
- .attr('y', (d) => d[1] - 0.36 * pxPerUnitLength / 2)
|
|
|
- .attr('width', 0.36 * pxPerUnitLength)
|
|
|
- .attr('height', 0.36 * pxPerUnitLength)
|
|
|
- .attr('fill', 'black')
|
|
|
- .attr('render-data', (d) => {
|
|
|
- return d
|
|
|
+ methods: {
|
|
|
+ inputToArray(input) {
|
|
|
+ let temp = input.trim()
|
|
|
+ if(temp[0] === '[') { temp = temp.substr(1)}
|
|
|
+ if (temp[temp.length - 1] === ']') { temp = temp.substr(0, temp.length - 1) }
|
|
|
+ temp = temp.split(',').map((item) => {
|
|
|
+ return Number(item)
|
|
|
+ })
|
|
|
+ if (temp.includes(NaN)) {
|
|
|
+ window.alert(`解析输入路径失败:${input}`)
|
|
|
+ return -1
|
|
|
+ }
|
|
|
+ return temp
|
|
|
+ },
|
|
|
+ getWholeData() {
|
|
|
+ this.loadingHandler = ElLoading.service({
|
|
|
+ lock: true,
|
|
|
+ text: 'Loading',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)',
|
|
|
})
|
|
|
|
|
|
- d3.select('svg').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[15]}, \n具体值: ${renderDataItem.slice(2, 14).join(', ')}`
|
|
|
- }).on('mouseleave', function (e) {
|
|
|
- d3.select(this).attr('fill', 'black')
|
|
|
- that.infoText = ''
|
|
|
- })
|
|
|
-
|
|
|
- d3.select('svg').selectAll('circle').data(pathDataForRender).enter().append('circle')
|
|
|
- .attr('cx', (d) => d[0])
|
|
|
- .attr('cy', (d) => d[1])
|
|
|
- .attr('r', 0.36 * pxPerUnitLength / 2)
|
|
|
- .attr('fill', 'blue')
|
|
|
- .attr('pointer-events', 'none')
|
|
|
- .attr('render-data', (d) => {
|
|
|
- return d
|
|
|
+ resetGlobalVars()
|
|
|
+ d3.select('svg').selectAll('rect').remove()
|
|
|
+ d3.select('svg').selectAll('circle').remove()
|
|
|
+ d3.select('svg').selectAll('text').remove()
|
|
|
+
|
|
|
+ const that = this
|
|
|
+ getWholeData().then((res) => {
|
|
|
+ rawWholeData = res
|
|
|
+ // 原始字符串数组处理成二维数组
|
|
|
+ let wholeInputPointArray = rawWholeData.map((eachString, index) => {
|
|
|
+ console.assert(eachString.split(' ').length === 12, `index ${index}处数据点 数字个数不是12!`)
|
|
|
+ return eachString.split(' ')
|
|
|
+ })
|
|
|
+
|
|
|
+ // 所有点的分布情况
|
|
|
+ let xArray = wholeInputPointArray.map((eachPoint) => {
|
|
|
+ return eachPoint[0]
|
|
|
+ })
|
|
|
+ let xLength = Math.max(...xArray) - Math.min(...xArray)
|
|
|
+ xCenter = (Math.max(...xArray) + Math.min(...xArray)) / 2
|
|
|
+
|
|
|
+ let yArray = wholeInputPointArray.map((eachPoint) => {
|
|
|
+ return eachPoint[1]
|
|
|
+ })
|
|
|
+ let yLength = Math.max(...yArray) - Math.min(...yArray)
|
|
|
+ yCenter = (Math.max(...yArray) + Math.min(...yArray)) / 2
|
|
|
+
|
|
|
+ let areaRatio = xLength / yLength
|
|
|
+
|
|
|
+ // 各个点坐标映射到视口坐标
|
|
|
+ if (viewportRatio >= areaRatio) { // 视口高度应略小于y轴方向分布幅度
|
|
|
+ pxPerUnitLength = svgHeight / yLength * 0.9
|
|
|
+ } else { // 视口宽度应略小于x轴方向分布幅度
|
|
|
+ pxPerUnitLength = svgWidth / xLength * 0.9
|
|
|
+ }
|
|
|
+ let wholeXArrayInPx = xArray.map((eachX) => {
|
|
|
+ return (eachX - xCenter) * pxPerUnitLength + svgWidth / 2
|
|
|
+ })
|
|
|
+ let wholeYArrayInPx = yArray.map((eachY) => {
|
|
|
+ return (eachY - yCenter) * pxPerUnitLength + svgHeight / 2
|
|
|
+ })
|
|
|
+
|
|
|
+ // 组合成最终数据用来渲染
|
|
|
+ for (let index = 0; index < wholeInputPointArray.length; index++) {
|
|
|
+ wholeDataForRender.push([wholeXArrayInPx[index], wholeYArrayInPx[index], ...wholeInputPointArray[index], index])
|
|
|
+ }
|
|
|
+
|
|
|
+ d3.select('svg').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)
|
|
|
+ .attr('height', LENGTH_PER_POINT * pxPerUnitLength)
|
|
|
+ .attr('fill', 'black')
|
|
|
+ .attr('render-data', (d) => {
|
|
|
+ return d
|
|
|
+ })
|
|
|
+
|
|
|
+ d3.select('svg').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(', ')}`
|
|
|
+ }).on('mouseleave', function (e) {
|
|
|
+ d3.select(this).attr('fill', 'black')
|
|
|
+ that.infoText = ''
|
|
|
+ })
|
|
|
+ }).finally(() => {
|
|
|
+ this.loadingHandler.close()
|
|
|
})
|
|
|
+ },
|
|
|
+ renderPath() {
|
|
|
+ if (!this.formData.path1.trim()) {
|
|
|
+ window.alert('路径1必填!')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ d3.select('svg').selectAll('circle').remove()
|
|
|
+ d3.select('svg').selectAll('text').remove()
|
|
|
+
|
|
|
+ let rawPathDataIndex = this.inputToArray(this.formData.path1)
|
|
|
+ if (rawPathDataIndex === -1) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let rawPathDataIndex2 = this.inputToArray(this.formData.path2)
|
|
|
+ if (rawPathDataIndex2 === -1) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 基于path index 拿到path节点数组
|
|
|
+ let rawPathData = {
|
|
|
+ data: [
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ for (let index = 0; index < rawPathDataIndex.length; index++) {
|
|
|
+ const element = rawWholeData[rawPathDataIndex[index]];
|
|
|
+ rawPathData.data.push(element)
|
|
|
+ }
|
|
|
+ let rawPathData2 = {
|
|
|
+ data: [
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ for (let index = 0; index < rawPathDataIndex2.length; index++) {
|
|
|
+ const element = rawWholeData[rawPathDataIndex2[index]];
|
|
|
+ rawPathData2.data.push(element)
|
|
|
+ }
|
|
|
|
|
|
- // todo: 不用数字,改用不同颜色的图形。
|
|
|
- d3.select('svg').selectAll('text').data(pathDataForRender2).enter().append('text')
|
|
|
- .text('1')
|
|
|
- .attr('x', (d) => d[0])
|
|
|
- .attr('y', (d) => d[1] + 0.36 * pxPerUnitLength / 2)
|
|
|
- .attr('fill', 'green')
|
|
|
- .attr('text-anchor', 'middle')
|
|
|
- .attr('pointer-events', 'none')
|
|
|
- }
|
|
|
+ // 原始字符串数组处理成二维数组
|
|
|
+ let pathInputPointArray = rawPathData.data.map((eachString) => {
|
|
|
+ return eachString.split(' ')
|
|
|
+ })
|
|
|
+ let pathInputPointArray2 = rawPathData2.data.map((eachString) => {
|
|
|
+ return eachString.split(' ')
|
|
|
+ })
|
|
|
+
|
|
|
+ // 各个点坐标映射到视口坐标
|
|
|
+ let pathXArrayInPx = pathInputPointArray.map((eachPoint) => {
|
|
|
+ return eachPoint[0]
|
|
|
+ }).map((eachX) => {
|
|
|
+ return (eachX - xCenter) * pxPerUnitLength + svgWidth / 2
|
|
|
+ })
|
|
|
+ let pathYArrayInPx = pathInputPointArray.map((eachPoint) => {
|
|
|
+ return eachPoint[1]
|
|
|
+ }).map((eachY) => {
|
|
|
+ return (eachY - yCenter) * pxPerUnitLength + svgHeight / 2
|
|
|
+ })
|
|
|
+ let pathXArrayInPx2 = pathInputPointArray2.map((eachPoint) => {
|
|
|
+ return eachPoint[0]
|
|
|
+ }).map((eachX) => {
|
|
|
+ return (eachX - xCenter) * pxPerUnitLength + svgWidth / 2
|
|
|
+ })
|
|
|
+ let pathYArrayInPx2 = pathInputPointArray2.map((eachPoint) => {
|
|
|
+ return eachPoint[1]
|
|
|
+ }).map((eachY) => {
|
|
|
+ return (eachY - yCenter) * pxPerUnitLength + svgHeight / 2
|
|
|
+ })
|
|
|
+
|
|
|
+ // 组合成最终数据用来渲染
|
|
|
+ let pathDataForRender = []
|
|
|
+ for (let index = 0; index < pathInputPointArray.length; index++) {
|
|
|
+ pathDataForRender.push([pathXArrayInPx[index], pathYArrayInPx[index], ...pathInputPointArray[index]])
|
|
|
+ }
|
|
|
+ let pathDataForRender2 = []
|
|
|
+ for (let index = 0; index < pathInputPointArray2.length; index++) {
|
|
|
+ pathDataForRender2.push([pathXArrayInPx2[index], pathYArrayInPx2[index], ...pathInputPointArray2[index]])
|
|
|
+ }
|
|
|
+
|
|
|
+ // 进行渲染
|
|
|
+ d3.select('svg').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')
|
|
|
+ .text('1')
|
|
|
+ .attr('x', (d) => d[0])
|
|
|
+ .attr('y', (d) => d[1] + LENGTH_PER_POINT * pxPerUnitLength / 2)
|
|
|
+ .attr('fill', 'green')
|
|
|
+ .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>
|
|
|
|
|
@@ -176,6 +266,7 @@ export default {
|
|
|
}
|
|
|
.svgWrapper {
|
|
|
position: absolute;
|
|
|
- top: 20px;
|
|
|
+ top: 300px;
|
|
|
+ background: #eee;
|
|
|
}
|
|
|
</style>
|