效果如上
html部分
<svg width="500px" height="500px" viewBox="0 0 400 400"><!-- 绘制连线 --><template v-for="(point, index) in points"><line :x1="point.x" :y1="point.y" :x2="index - 1 > 0 || index - 1 == 0 ? points[index - 1].x : point.x":y2="index - 1 > 0 || index - 1 == 0 ? points[index - 1].y : point.y" stroke="#1677ee" stroke-width="4"key="index" /><circle :cx="point.x" :cy="point.y" r="8" :fill="point.pointColor" key="index"@click="getSiteDetails(point)" v-if="point.siteType != 'end'" /><text :x="point.x" :y="point.y" fill="#fff" text-anchor="top" v-if="point.siteType != 'end'">{{ index + 1}}</text><image xlink:href="../../../../assets/img/robot.png" height="25px" width="25px" :x="robotPos":y="robotPosY"></image></template>
</svg>
重点解释一下:
1.svg中的:width、height是整画布的大小;viewBox是视野的值(个人这么理解,可以通过改变其中的值越大 整个svg中的内容越小反之亦然)
2.这个图中的线段和圆形都是svg中的line和circle,根据后台中返回的数据实时生成的,所有使用了template遍历数据
3.其中的层级关系 谁在后面谁的层级越高(目前的文字越高)
4.其中引入的图片 路径需要上述的xlink:href引入
5.想要文字在圆形中居中可以设置 text-anchor="middle" alignment-baseline="middle"这俩个属性
<text x="200" y="200" text-anchor="middle" alignment-baseline="middle" fill="black" font-size="16px">Your Text Here</text>
回到那个页面中的js部分:其中这里是使用websocket实时发心跳,updateWorkStatus里就是反馈的实时数据
难点就是在于那个坡度的地方,需要沿着坡度去走,那么图片的y轴距离如何得出就是一个问题
(robotPos ,robotPosY)
整体的思路下面是实现方式:
//图片的实时状态updateWorkStatus(v) {this.robotPos = v.pos * 10this.robotState = v.statethis.robotDir = v.dirif (this.robotPos > this.upOpint.x && this.robotPos < this.downOpint.x) {let lineLength = this.calculateHypotenuse((this.downOpint.x - this.upOpint.x), (this.upOpint.y - this.downOpint.y)) / (this.robotPos - this.upOpint.x)this.robotPosY = 200 - (this.downOpint.y / lineLength) * 4} else if (this.robotPos < this.upOpint.x) {this.robotPosY = 200} else if (this.robotPos > this.downOpint.x || this.robotPos == this.downOpint.x) {this.robotPosY = 100}//机器人路过的点没有异常时候点变成绿色this.points.forEach(item => {//机器人的方向去判断if (this.robotDir == 1) {if (this.robotPos > item.pos * 10 || this.robotPos == item.pos * 10) {item.pointColor = '#23A459'}} else if (this.robotDir == 2) {if (this.robotPos < item.pos * 10) {item.pointColor = '#23A459'}}})},//a直角边a的长度 b直角边b的长度calculateHypotenuse(a, b) {var c = Math.sqrt(a * a + b * b);return c;},
站点折线数据加工:
// 获取站点初始化setStaionList() {if (this.uniqueid) {initializeSiteList(this.uniqueid).then(res => {let data = res.data.datadata.forEach(item => {if (item.siteType == 'down') {item.x = item.pos * 10item.y = 100item.pointColor = '#1677ee'this.downOpint = {x: item.pos * 10,y: 100}} else if (item.siteType == 'end') {item.x = item.pos * 10item.y = 100item.pointColor = '#1677ee'} else if (item.siteType == 'up') {item.x = item.pos * 10item.y = 200item.pointColor = '#1677ee'this.upOpint = {x: item.pos * 10,y: 200}} else {item.x = item.pos * 10item.y = 200item.pointColor = '#1677ee'this.robotPosY = 200}})this.points = data})}},