其实这些效果之前都有用js写过,但是最近在写vue项目,里面的些许语法还是有些不一样的,所以还是写一遍文章总结一下,下次遇到就可以直接用了。

如果想看js写法,可以看我别的文章

首先,实现效果入下图:

下面简单介绍一下每种实现方式

1.将树图的节点修改成图片以及修改连线的颜色

代码布局如下:

主要代码:

symbolSize: [30, 30],
/**
* 遍历树节点信息
* @param nodes 拓扑图节点数据
* 通过某种状态区分显示拓扑图的节点图片或连线颜色* */readNodes(nodes) {for (const item of nodes) { // js遍历树形数组结构if (item.children && item.children.length) {this.readNodes(item.children)}if (item.name == '服务器') {item.symbol = 'image://' + require('@/assets/topo/server_online_unreg.png');// 修改连线颜色item.lineStyle = {color: '#ff0000'}} else {item.symbol = 'image://' + require('@/assets/topo/internet.png');item.lineStyle = {color: '#2E8B57'}}}},

2.添加鼠标悬停事件

代码布局如下:

主要代码:

formatter: this.formatterHover// 修改鼠标悬停显示的内容
/*** 鼠标悬停显示详情* @param params* @returns {string}*/formatterHover(params) {// console.log(params);var deviceType = params.data.type;var imgPath = params.data.symbol;// 图片地址截取,因为echarts修改图片的时候有一个------image://---前缀,前缀后面的才是图片真正的地址var imgPathSrc = imgPath.split('image://')[1];// console.log('str',imgPathSrc);if (deviceType === 'Internet' || deviceType === 'hub') {return "<img src='" + imgPathSrc + " ' width='30px' height='30px'>" + '<span style="padding:0 5px;font-size: 14px;">' + params.data.name + '</span>';} if (deviceType === 'switch') {return "<img src='" + imgPathSrc + " ' width='30px' height='30px'>" + '<span style="padding: 0 5px;font-size: 14px;">设备类型:' + params.data.name + '</span>' + '<br>' +'<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">IP:' + params.data.IP + '</span>' + '<br>' +'<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">MAC:' + params.data.MAC + '</span>' + '<br>';// +'<button style="padding:2px 5px;border:none;outline:none;color:#ffffff;border-radius: 5px;background:rgba(0,0,0,0.5);"><span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span> IP列表</button>'// +'<button style="padding:2px 5px;border:none;outline:none;color:#ffffff;border-radius: 5px;background:rgba(0,0,0,0.5);margin-left: 10px;"><span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span> MAC列表</button>';} else {return "<img src='" + imgPathSrc + " ' width='30px' height='30px'>" + '<span style="padding: 0 5px;font-size: 14px;">设备类型:' + params.data.name + '</span>' + '<br>' +'<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">IP:' + params.data.IP + '</span>' + '<br>' +'<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">MAC:' + params.data.MAC + '</span>' + '<br>';}},

3.鼠标右键弹出菜单

代码布局如下:

主要代码:

<style scoped>.menu{/*这个样式不写,右键弹框会一直显示在画布的左下角*/position: absolute;background: rgba(255, 255, 255, 1);border-radius: 5px;left: -99999px;top: -999999px;}.menu ul{list-style: none;padding: 0;margin: 0;}.menu ul li{cursor: pointer;padding: 5px 10px;color: #000000;border-bottom: 1px dashed #a9a9a9;font-size: 14px;}.menu ul li:last-child{border-bottom: none;}
</style>
<!--右键弹出菜单--><div ref="rightMenu" class="menu" style="display: none;"><ul><li>下线</li><li>上线</li><li>掉线</li></ul></div>
<div class="app-container" @contextmenu.prevent="" @click="mainClick"></div>
/**
* 鼠标右键,显示右键菜单
*/
echarts.init(chart).on('contextmenu', function(params) {// console.log('params', params)that.contextmenu = true// 去掉悬停that.$refs.main.children[1].style.display = 'none'that.$refs.rightMenu.style.display = 'block';// // //让自定义菜单随鼠标的箭头位置移动that.$refs.rightMenu.style.left = params.event.offsetX + 45 + 'px'that.$refs.rightMenu.style.top = params.event.offsetY + 45 + 'px'
});
/**
* 点击页面其它地方时,隐藏右键菜单
* */
mainClick() {this.contextmenu = falsethis.$refs.rightMenu.style.display = 'none';
},

 注:以上代码实现右键菜单是没有问题的,但是后期在开发的过程中,发现当在浏览器左下角,右下角,最右边点击时,菜单会被覆盖显示不全,所以对菜单显示的位置做了一些调整,调整完后效果如下:

主要代码:<至于里面的数字,具体要根据自己的项目进行修改>

/**
* smallWidth:即能容下弹框的最小宽度=document.body.clientWidth<浏览器窗口宽度> - 210<左侧导航菜单宽度> - params.event.offsetX<当前点击距离左上角宽度>
* smallHeight:即能容下弹框的最小高度=document.body.clientHeight<浏览器窗口高度> - 120<上方导航菜单宽度> - params.event.offsetY<当前点击距离左上角高度>
* 140,在浏览器中console.log打印,差不多smallWidth小于140的时候,右键菜单宽度就放不下了
* 256,在浏览器中console.log打印,差不多smallHeight小于256的时候,右键菜单高度就放不下了
* 接下来右键菜单的显示,差不多就是当前点击的位置加或减去右键菜单宽或高的长度
* */
const smallWidth = document.body.clientWidth - 210 - params.event.offsetX
const smallHeight = document.body.clientHeight - 120 - params.event.offsetY
// console.log('smallWidth', smallWidth)
// console.log('smallHeight', smallHeight)
if (smallHeight <= 256 && smallWidth > 140) { // 高度不够,宽度够// 让自定义菜单随鼠标的箭头位置移动that.$refs.rightMenu.style.left = params.event.offsetX + 45 + 'px'that.$refs.rightMenu.style.top = params.event.offsetY - 200 + 'px'
} else if (smallHeight > 256 && smallWidth <= 140) { // 高度够,宽度不够that.$refs.rightMenu.style.left = params.event.offsetX - 52 + 'px'that.$refs.rightMenu.style.top = params.event.offsetY + 45 + 'px'
} else if (smallHeight <= 256 && smallWidth <= 140) { // 高度不够,宽度不够that.$refs.rightMenu.style.left = params.event.offsetX - 52 + 'px'that.$refs.rightMenu.style.top = params.event.offsetY - 200 + 'px'
} else { // 高度和宽度都够that.$refs.rightMenu.style.left = params.event.offsetX + 45 + 'px'that.$refs.rightMenu.style.top = params.event.offsetY + 45 + 'px'
}

4.搜索

代码布局如下:

主要代码:

<el-input v-model="inputSearch" type="text" placeholder="请输入名称" style="width: 200px;" @keyup.enter.native="handleFilter"/><el-button type="primary" icon="el-icon-search" size="mini" @click="handleFilter">搜索</el-button>
inputSearch: '', // 搜索框
 /*** 搜索,输入名称时,实现搜索功能* */handleFilter() {const that = thisvar num = 0; // 记录查询到节点的数量function readNodes(nodes) {for (const item of nodes) { // js遍历树形数组结构if (item.children && item.children.length) {readNodes(item.children)}// 查询,名称中包含输入值就修改label颜色和字体大小if (item.name.indexOf(that.inputSearch) >= 0 && that.inputSearch != '') {item.label = {color: 'red',fontSize: '15'};num++;} else { // 否则为默认颜色和大小item.label = {color: '#666',fontSize: '9'};}}}readNodes(this.dataTree); // 调用时,要给data加[],因为原本的data不是一个正常的数组结构if (num > 0) { // 查询节点数量大于0的时候展开所有层级this.defaultOpt.series[0].initialTreeDepth = -1;} else { // 否则恢复初始的层级this.defaultOpt.series[0].initialTreeDepth = 2;}const chart = this.$refs.mainif (chart) {echarts.init(chart).setOption(this.defaultOpt); // 重新设置一遍树图,不然不起效果}},

5.导出PNG

代码布局:

主要代码:

toolbox: {show: true,top: 20,left: 20,feature: {restore: {title: '刷新'// 刷新echarts图标},saveAsImage: {title: '下载图片', // 鼠标悬停在下载图标上时,显示的文字name: 'network-topology'// 下载图片的文件名为network-topology.png}}},

6.高亮:这个高亮的效果我感觉不是很好,但是如果有朋友需要的话,就是下面用法

代码布局:

主要代码:

emphasis: { // 高亮,个人感觉这个高亮的效果不是很好focus: 'descendant'
},

7.查看节点是否还有子节点

代码布局:

主要代码:

symbol: function(params, params1) {/**
* 自定义图片后,不知道是否还有子节点未展开
* 通过打印,发现没有展开的节点,和最后一层子节点的collapsed属性都为true
* 所以判断collapsed为true,并且没有孩子节点的时候,就是还有没展开的子节点
* 修改label的样式,来判断是否还存在子节点没展开*/
// console.log('params11111111111111111', params1)
if (params1.collapsed == true && params1.data.children.length > 0) {params1.data.label = {color: '#0099cc',fontSize: '13',fontWeight: 'bold'}}
},
/**
* 鼠标单机节点
* (1)隐藏右键菜单
* (2)判断子节点是否展开,修改label的样式
*/
echarts.init(chart).on('click', function(params) {that.contextmenu = falsethat.$refs.rightMenu.style.display = 'none';// 解决树图点击展开图片不显示问题// echarts.init(chart).resize()console.log('params', params)if (params.collapsed == true && params.data.children.length > 0) {params.data.label = {color: '#0099cc',fontSize: '13',fontWeight: 'bold'}} else {params.data.label = {color: '#ffffff',fontSize: '9',fontWeight: 'normal'}}echarts.init(chart).resize()
});

8.修改树图的展示方式

注:起初只是简单的实现了切换的效果,并没有注重细节主要如下:

代码布局:

主要代码:

 <el-button size="mini" @click="lrClick('LR')">左到右</el-button><el-button size="mini" @click="rlClick('RL')">右到左</el-button><el-button size="mini" @click="tbClick('TB')">上到下</el-button><el-button size="mini" @click="btClick('BT')">下到上</el-button>
/*** 左到右按钮点击* @param option 树图属性LR* */lrClick(option) {this.treeDisplay(option)},/*** 右到左按钮点击* @param option 树图属性RL* */rlClick(option) {this.treeDisplay(option)},/*** 上到下按钮点击* @param option 树图属性TB* */tbClick(option) {this.treeDisplay(option)},/*** 下到上按钮点击* @param option 树图属性BT* */btClick(option) {this.treeDisplay(option)},/*** 左到右,右到左,上到下,下到上按钮点击时,对拓扑属性的设置* */treeDisplay(option) {this.defaultOpt.series[0].orient = option;const chart = this.$refs.mainif (chart) {echarts.init(chart).setOption(this.defaultOpt);}}

后期在实际开发中,发现,切换后,结点的label会挤在一起,非常丑,所以要对每种展示方式的label也要做调整,具体如下:

代码布局:

主要代码:

type: 'tree',data: this.dataTree,left: '10%',right: '2%',top: '16%',bottom: '8%',label: {position: 'top',rotate: -90,verticalAlign: 'middle',align: 'right',color: '#fff',fontSize: 9},orient: 'TB',leaves: {label: {position: 'bottom',rotate: -90,verticalAlign: 'middle',align: 'left'}},symbolSize: [30, 30],
/*** 左到右按钮点击* @param option 树图属性LR* */lrClick(option) {this.treeDisplay(option)},/*** 右到左按钮点击* @param option 树图属性RL* */rlClick(option) {this.treeDisplay(option)},/*** 上到下按钮点击* @param option 树图属性TB* */tbClick(option) {this.treeDisplay(option)},/*** 下到上按钮点击* @param option 树图属性BT* */btClick(option) {this.treeDisplay(option)},/*** 左到右,右到左,上到下,下到上按钮点击时,对拓扑属性的设置* orient:修改拓扑图展示的方向* label、leaves修改结点旁边的文字展示* */treeDisplay(option) {this.defaultOpt.series[0].orient = option;// console.log('option', option)if (option == 'LR') {this.defaultOpt.series[0].label = {position: 'left',rotate: 0,verticalAlign: 'middle',align: 'right',color: '#fff',fontSize: 9}this.defaultOpt.series[0].leaves = {label: {position: 'right',rotate: 0,verticalAlign: 'middle',align: 'left'}}}if (option == 'RL') {this.defaultOpt.series[0].label = {position: 'right',rotate: 0,verticalAlign: 'middle',align: 'left',color: '#fff',fontSize: 9}this.defaultOpt.series[0].leaves = {label: {position: 'left',rotate: 0,verticalAlign: 'middle',align: 'right'}}}if (option == 'TB') {this.defaultOpt.series[0].label = {position: 'top',rotate: -90,verticalAlign: 'middle',align: 'right',color: '#fff',fontSize: 9}this.defaultOpt.series[0].leaves = {label: {position: 'bottom',rotate: -90,verticalAlign: 'middle',align: 'left'}}}if (option == 'BT') {this.defaultOpt.series[0].label = {position: 'bottom',rotate: 90,verticalAlign: 'middle',align: 'right',color: '#fff',fontSize: 9}this.defaultOpt.series[0].leaves = {label: {position: 'top',rotate: 90,verticalAlign: 'middle',align: 'left'}}}const chart = this.$refs.mainif (chart) {echarts.init(chart).setOption(this.defaultOpt);}},

 完整代码:

topoTree.js

import Mock from 'mockjs'const tree = [{'id': '0','name': '外部网络','type': 'Internet','children': [{'id': '1','name': '交换机','type': 'switch','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '交换机','deviceNum': 'HUAWEI','children': [{'id': '2','name': '笔记本','type': 'switch','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c'},{'id': '3','name': '计算机','type': 'computer','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','children': [{'id': '4','name': '计算机1','type': 'computer','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c'},{'id': '5','name': '计算机2','type': 'computer','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c'},{'id': '6','name': '计算机3','type': 'computer','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c'},{'id': '7','name': '计算机4','type': 'computer','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','lastLoginTime': '2020-8-26'}]},{'id': '8','name': '路由器','type': 'rooter','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '路由器'},{'id': '9','name': '服务器','type': 'service','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '服务器'},{'id': '10','name': '打印机','type': 'print','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '打印机'},{'id': '11','name': '计算机','type': 'computer','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','lastLoginTime': '2020-8-26'}]},{'id': '12','name': '无线交换机','type': 'switch','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '交换机','deviceNum': 'HUAWEI','children': [{'id': '13','name': '手机','type': 'phone','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '手机'},{'id': '14','name': '平板','type': 'phone','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '平板'}]},{'id': '15','name': 'hub','type': 'hub','children': [{'id': '16','name': '计算机','type': 'computer','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '计算机'},{'id': '17','name': '笔记本','type': 'phone','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '手机'},{'id': '18','name': '打印机','type': 'print','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '打印机'},{'id': '19','name': '路由器','type': 'rooter','IP': '192.168.30.126','MAC': 'b0:98:6e:bf:6r:4c','deviceType': '路由器'}]}]}
]Mock.mock('/topo/tree', 'get', tree)
export default []

index.vue

<template><div class="app-container" @contextmenu.prevent="" @click="mainClick"><el-input v-model="inputSearch" type="text" placeholder="请输入名称" style="width: 200px;" @keyup.enter.native="handleFilter"/><el-button type="primary" icon="el-icon-search" size="mini" @click="handleFilter">搜索</el-button><el-button size="mini" @click="lrClick('LR')">左到右</el-button><el-button size="mini" @click="rlClick('RL')">右到左</el-button><el-button size="mini" @click="tbClick('TB')">上到下</el-button><el-button size="mini" @click="btClick('BT')">下到上</el-button><div ref="main" class="app-container"></div><!--右键弹出菜单--><div ref="rightMenu" class="menu" style="display: none;"><ul><li>下线</li><li>上线</li><li>掉线</li></ul></div></div>
</template><script>
import * as echarts from 'echarts'
require('echarts/theme/macarons')
import axios from 'axios'export default {name: 'TopologyDisplay',props: {},data() {return {inputSearch: '', // 搜索框dataTree: [], // data数据defaultOpt: {}, // 拓扑图属性设置contextmenu: false // 鼠标右键事件}},watch: {},mounted: function() {this.setOptions()this.day_init()},created() {},methods: {/*** 实现自适应* */day_init() {const self = this; // 因为箭头函数会改变this指向,指向windows。所以先把this保存const todaypieId = this.$refs.mainif (!todaypieId) {return false;} else {setTimeout(() => {window.onresize = function() {//   self.chart = echarts.init(self.$refs.myEchart);self.chart_today = echarts.init(todaypieId);self.chart_today.resize();};}, 20);}},/*** 遍历树节点信息* @param nodes 拓扑图节点数据* 通过某种状态区分显示拓扑图的节点图片或连线颜色* */readNodes(nodes) {for (const item of nodes) { // js遍历树形数组结构if (item.children && item.children.length) {this.readNodes(item.children)}if (item.name == '服务器') {item.symbol = 'image://' + require('@/assets/topo/server_online_unreg.png');// 修改连线颜色item.lineStyle = {color: '#ff0000'}} else {item.symbol = 'image://' + require('@/assets/topo/internet.png');item.lineStyle = {color: '#2E8B57'}}}},/*** 对拓扑图属性的设置* */setOptions() {axios.get('/topo/tree').then(res => {console.log('树节点数据', JSON.parse(JSON.stringify(res.data)));this.dataTree = res.dataif (this.dataTree) {this.readNodes(this.dataTree) // 在设置属性之前遍历显示图片,否则节点图片不生效this.defaultOpt = {tooltip: {trigger: 'item',triggerOn: 'mousemove',enterable: true, // 鼠标是否可进入提示框浮层中formatter: this.formatterHover// 修改鼠标悬停显示的内容},toolbox: {show: true,top: 20,left: 20,feature: {restore: {title: '刷新'// 刷新echarts图标},saveAsImage: {title: '下载图片', // 鼠标悬停在下载图标上时,显示的文字name: 'network-topology'// 下载图片的文件名为network-topology.png}}},series: [{type: 'tree',data: this.dataTree,left: '10%',right: '2%',top: '16%',bottom: '8%',label: {position: 'top',rotate: -90,verticalAlign: 'middle',align: 'right',color: '#fff',fontSize: 9},orient: 'TB',leaves: {label: {position: 'bottom',rotate: -90,verticalAlign: 'middle',align: 'left'}},symbolSize: [30, 30],symbol: function(params, params1) {/*** 自定义图片后,不知道是否还有子节点未展开* 通过打印,发现没有展开的节点,和最后一层子节点的collapsed属性都为true* 所以判断collapsed为true,并且没有孩子节点的时候,就是还有没展开的子节点* 修改label的样式,来判断是否还存在子节点没展开*/// console.log('params11111111111111111', params1)if (params1.collapsed == true && params1.data.children.length > 0) {params1.data.label = {color: '#0099cc',fontSize: '13',fontWeight: 'bold'}}},edgeForkPosition: '72%',emphasis: { // 高亮,个人感觉这个高亮的效果不是很好focus: 'descendant'},initialTreeDepth: 2, // 树图初始展开层级roam: true, // 鼠标缩放,拖拽整颗树expandAndCollapse: true, // 无关的子树折叠收起animationDuration: 550,animationDurationUpdate: 750,width: '85%'// 组件宽度}]}const chart = this.$refs.mainif (chart) {const that = this// console.log('echarts', echarts)echarts.init(chart).setOption(this.defaultOpt) // 将画布添加到页面中/*** 鼠标右键,显示右键菜单*/echarts.init(chart).on('contextmenu', function(params) {// console.log('params', params)that.contextmenu = true// 去掉悬停that.$refs.main.children[1].style.display = 'none'that.$refs.rightMenu.style.display = 'block';// // //让自定义菜单随鼠标的箭头位置移动that.$refs.rightMenu.style.left = params.event.offsetX + 45 + 'px'that.$refs.rightMenu.style.top = params.event.offsetY + 45 + 'px'});/*** 鼠标单机节点* (1)隐藏右键菜单* (2)判断子节点是否展开,修改label的样式*/echarts.init(chart).on('click', function(params) {that.contextmenu = falsethat.$refs.rightMenu.style.display = 'none';// 解决树图点击展开图片不显示问题// echarts.init(chart).resize()// console.log('params.collapsed', params.collapsed)if (params.collapsed == true) {params.data.label = {color: '#0099cc',fontSize: '13',fontWeight: 'bold'}} else {params.data.label = {color: '#ffffff',fontSize: '9',fontWeight: 'normal'}}echarts.init(chart).resize() // 不写修改的样式不生效});// 解决树图首次加载图片不显示问题echarts.init(chart).resize()}}})},/*** 点击页面其它地方时,隐藏右键菜单* */mainClick() {this.contextmenu = falsethis.$refs.rightMenu.style.display = 'none';},/*** 鼠标悬停显示详情* @param params* @returns {string}*/formatterHover(params) {// console.log(params);var deviceType = params.data.type;var imgPath = params.data.symbol;// 图片地址截取,因为echarts修改图片的时候有一个------image://---前缀,前缀后面的才是图片真正的地址var imgPathSrc = imgPath.split('image://')[1];// console.log('str',imgPathSrc);if (deviceType === 'Internet' || deviceType === 'hub') {return "<img src='" + imgPathSrc + " ' width='30px' height='30px'>" + '<span style="padding:0 5px;font-size: 14px;">' + params.data.name + '</span>';} if (deviceType === 'switch') {return "<img src='" + imgPathSrc + " ' width='30px' height='30px'>" + '<span style="padding: 0 5px;font-size: 14px;">设备类型:' + params.data.name + '</span>' + '<br>' +'<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">IP:' + params.data.IP + '</span>' + '<br>' +'<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">MAC:' + params.data.MAC + '</span>' + '<br>';// +'<button style="padding:2px 5px;border:none;outline:none;color:#ffffff;border-radius: 5px;background:rgba(0,0,0,0.5);"><span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span> IP列表</button>'// +'<button style="padding:2px 5px;border:none;outline:none;color:#ffffff;border-radius: 5px;background:rgba(0,0,0,0.5);margin-left: 10px;"><span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span> MAC列表</button>';} else {return "<img src='" + imgPathSrc + " ' width='30px' height='30px'>" + '<span style="padding: 0 5px;font-size: 14px;">设备类型:' + params.data.name + '</span>' + '<br>' +'<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">IP:' + params.data.IP + '</span>' + '<br>' +'<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">MAC:' + params.data.MAC + '</span>' + '<br>';}},/*** 搜索,输入名称时,实现搜索功能* */handleFilter() {const that = thisvar num = 0; // 记录查询到节点的数量function readNodes(nodes) {for (const item of nodes) { // js遍历树形数组结构if (item.children && item.children.length) {readNodes(item.children)}// 查询,名称中包含输入值就修改label颜色和字体大小if (item.name.indexOf(that.inputSearch) >= 0 && that.inputSearch != '') {item.label = {color: 'red',fontSize: '15'};num++;} else { // 否则为默认颜色和大小item.label = {color: '#666',fontSize: '9'};}}}readNodes(this.dataTree); // 调用时,要给data加[],因为原本的data不是一个正常的数组结构if (num > 0) { // 查询节点数量大于0的时候展开所有层级this.defaultOpt.series[0].initialTreeDepth = -1;} else { // 否则恢复初始的层级this.defaultOpt.series[0].initialTreeDepth = 2;}const chart = this.$refs.mainif (chart) {echarts.init(chart).setOption(this.defaultOpt); // 重新设置一遍树图,不然不起效果}},/*** 左到右按钮点击* @param option 树图属性LR* */lrClick(option) {this.treeDisplay(option)},/*** 右到左按钮点击* @param option 树图属性RL* */rlClick(option) {this.treeDisplay(option)},/*** 上到下按钮点击* @param option 树图属性TB* */tbClick(option) {this.treeDisplay(option)},/*** 下到上按钮点击* @param option 树图属性BT* */btClick(option) {this.treeDisplay(option)},/*** 左到右,右到左,上到下,下到上按钮点击时,对拓扑属性的设置* orient:修改拓扑图展示的方向* label、leaves修改结点旁边的文字展示* */treeDisplay(option) {this.defaultOpt.series[0].orient = option;// console.log('option', option)if (option == 'LR') {this.defaultOpt.series[0].label = {position: 'left',rotate: 0,verticalAlign: 'middle',align: 'right',color: '#fff',fontSize: 9}this.defaultOpt.series[0].leaves = {label: {position: 'right',rotate: 0,verticalAlign: 'middle',align: 'left'}}}if (option == 'RL') {this.defaultOpt.series[0].label = {position: 'right',rotate: 0,verticalAlign: 'middle',align: 'left',color: '#fff',fontSize: 9}this.defaultOpt.series[0].leaves = {label: {position: 'left',rotate: 0,verticalAlign: 'middle',align: 'right'}}}if (option == 'TB') {this.defaultOpt.series[0].label = {position: 'top',rotate: -90,verticalAlign: 'middle',align: 'right',color: '#fff',fontSize: 9}this.defaultOpt.series[0].leaves = {label: {position: 'bottom',rotate: -90,verticalAlign: 'middle',align: 'left'}}}if (option == 'BT') {this.defaultOpt.series[0].label = {position: 'bottom',rotate: 90,verticalAlign: 'middle',align: 'right',color: '#fff',fontSize: 9}this.defaultOpt.series[0].leaves = {label: {position: 'top',rotate: 90,verticalAlign: 'middle',align: 'left'}}}const chart = this.$refs.mainif (chart) {echarts.init(chart).setOption(this.defaultOpt);}}}
}
</script><style scoped>.menu{/*这个样式不写,右键弹框会一直显示在画布的左下角*/position: absolute;background: rgba(255, 255, 255, 1);border-radius: 5px;left: -99999px;top: -999999px;}.menu ul{list-style: none;padding: 0;margin: 0;}.menu ul li{cursor: pointer;padding: 5px 10px;color: #000000;border-bottom: 1px dashed #a9a9a9;font-size: 14px;}.menu ul li:last-child{border-bottom: none;}
</style>

vue实现echarts树图修改节点图片,修改连线颜色,鼠标悬停显示详情,鼠标右键弹出菜单,搜索,导出PNG,高亮,查看节点是否还有子节点,修改树图的展示方式相关推荐

  1. python右键弹出菜单编写_python实现应用程序在右键菜单中添加打开方式功能

    最近项目组开发的一个小工具想要在右键菜单中添加打开方式,以有道云笔记为例进行了需求拆解和代码编写 1.需求拆解: 如何实现手动添加右键菜单的打开方式: Step1:打开注册表编辑器,Win+R-> ...

  2. echarts修改鼠标悬停在节点上时显示的内容,自定义鼠标悬停显示内容

    首先看一下效果,如下图所示: 代码部分: 1.在option对象下的tooltip对象中添加formatter函数,代码如下: var option = {tooltip: {trigger: 'it ...

  3. rp原型中鼠标悬停显示图片_悬停状态原型4种方式

    rp原型中鼠标悬停显示图片 There are tons of options available for UX designers to prototype a user experience an ...

  4. -webkit-touch-callout: none;禁止ios弹出菜单,长按图片保存到手机时

    -webkit-touch-callout: none;禁止ios弹出菜单,长按图片保存到手机时 有一个需求就是h5页面中,长按二维码图片,保存到手机:在ios上经常长按会弹出ios的菜单,而无法每次 ...

  5. Vue之鼠标悬停显示页面加载时间

    效果如下: 代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> & ...

  6. ECharts外部调用保存为图片操作及工作流接线mouseenter和mouseleave由于鼠标移动速度过快导致问题解决办法...

    记录两个项目开发中遇到的问题,一个是ECharts外部调用保存为图片操作,一个是workflow工作流连接曲线onmouseenter和onmouseleave事件由于鼠标移动过快触发问题. 一.外部 ...

  7. 鼠标悬停显示图片html5,JavaScript 鼠标悬停图片,显示隐藏文本

    Unsplash 当我们在浏览网页的时候,描述性的文本通常不会跟在图片之后,而是当我们将鼠标移至图片上时,才会将文本显示出来,这样的好处是,以突显图片为主,并节省布局空间 HTML 结构如下 世界上最 ...

  8. vue 悬停显示另一个div_CSS或者JS实现鼠标悬停显示另一元素

    想达到鼠标悬停到元素a上,显示另一个元素b,可以通过css实现也可以通过js实现. js: 写两个函数:mouseenter,mouseleave,例如:其中 $("#a").mo ...

  9. 修改NavigationBar的分根线颜色

    [self.navigationController.navigationBar setShadowImage:[Static ColorToImage:[Static colorWithHexStr ...

最新文章

  1. 创建守护进程关键步骤
  2. 解析Vue.js中的computed工作原理
  3. 【腾讯面试题】Nginx
  4. java 不存在就创建_Java 判断多级路径是否存在,不存在就创建
  5. IntelliJ IDEA快捷键(Shortcut)官方文档地址
  6. 计算机科学与技术专业改革,浅析计算机科学与技术专业教学改革
  7. java 复制一个对象_Java如何完全复制一个对象
  8. larav实战教程 百度网盘
  9. java大牛博客链接合集
  10. Python剑指offer之两个栈实现一个队列-两个队列实现一个栈
  11. 数据结构实现排队系统
  12. 【论文】论文中的参考文献:国标GB/T 7714-2015文献类型与格式
  13. 驰骋山海间,天地亦征途——记2022云创大数据优秀员工西域狂野自驾之旅
  14. 劳动与社会保障法-作业
  15. excel中添加有效性验证或数据验证时不选择第一行列标题的解决方法
  16. 读取经纬度坐标并存储为字典格式,即key为ID,value为轨迹点
  17. 瓦力机器人的配音_《机器人瓦力》的配套短片
  18. pythoniter 2_python [iter(list)] * 2是什么意思?
  19. 计算机视觉——特征检测
  20. 国际物流管理信息系统(LMIS)

热门文章

  1. Chrome多开高低版本分身及禁用谷歌更新(window11)
  2. Nexus3的部署(Windows版)
  3. 百度MIP技术 - MIP移动网页加速器
  4. strcmp和strncmp
  5. C#基类库苏飞版--系列教程导航
  6. 人脸识别之人脸对比 【C#】
  7. citavi显示期刊分区及影响因子
  8. [零碎的知识点]各态历经性、功率谱密度
  9. C++11 std::tuple
  10. windows10中文乱码