需求:关系族谱图,多叉树结构展示
技术:Echarts tree结构
难点
- 控制节点的缩起和展开状态
- 同一个等级的只能展开一个节点
- 控制高度的自动伸缩
知识
- 数组的递归
- ES6 map的使用
tree结构的数据结构以及配置项
option: {
series: [
{
type: 'tree', // 类型是tree
top: '1%', //距离div块top距离
left: '10%',
bottom: '1%',
right: '10%',
// 每个节点都有文字,label属性是设置字体(位置,大小,样式)
label: {
normal: {
position: 'left',
verticalAlign: 'middle',
align: 'right',
fontSize: 12
}
},
// 当此节点下还有子节点时候,设置的节点样式,用于区别 没有子节点的节点的样式
itemStyle: {
normal: {
color: '#b22125'
},
emphasis: {
borderColor: '#ccc'
}
},
// 叶子节点设置
leaves: {
label: {
normal: {
position: 'right',
verticalAlign: 'middle',
align: 'left',
fontSize: 12
}
}
},
// 图形大小
symbolSize: 20,
initialTreeDepth: 2, // 一开始展开深度
// expandAndCollapse 全部打开,全部收缩,值未布尔类型
data: []
}
]
}
一切准备就绪,开始上代码
- 初始化echarts
<div id="tree">
<div id="myChart"></div>
</div>
this.myChart = echarts.init(document.getElementById('myChart'))
this.myChart.on('contextmenu', this.handleClick) // 右击,弹窗弹出此节点的详情;有一个参数param(可以打印出来)
this.myChart.on('click', this.handleClickCircle) // 左击,控制节点的展开和伸缩;有一个参数param(可以打印出来)
- 右击,弹窗弹出此节点的详情,在此处,右击浏览会弹出菜单,需要屏蔽掉默认事件
// 自带param参数
handleClick(param) {
let _this = this
param.event.event.preventDefault() //屏蔽浏览器默认行为
this.Ajax.post(url, data, this,
function(data, context) {
Object.keys(data.data).forEach(key => {
// 对数据进行一些处理
})
}
)
}
- 左击,控制节点的伸缩和展开,高度计算
//右击的时候,需要判断此节点是否已经展开
//节点的展开和收缩状态存储在一个map中,map中的key是此节点的唯一标示(唯一标识自己和后台定啦),value为true或者false(true为收缩状态,false为展开状态);每次点击取到这个节点的唯一标识,然后从map中取出此节点是展开还是缩起的状态
//如果已经展开,就执行默认的行为(收缩起来);并且将map中此节点的唯一标示改为true
//如果点击节点并且此节点是缩起的状态,这个时候需要将同级的节点全部收起来,只设置此节点是展开状态;并且将map中此节点的唯一标示改为false
handleClickCircle(param) {
let index = param.data.index // 获取当钱节点的深度param.data是自己传的数据
this.findId(this.option.series[0].data, param.value, 'getObj') // 获取当前节点
// 判断此节点是展开还是收缩状态
if (this.map.get(this.currentClickObj.value)) {
// 收缩状态,执行下面代码
this.map.set(this.currentClickObj.value, false)
// 将同级的全部收缩 this.option.series[0].data是本树的data数据(数组)
this.handleCollapsed(this.option.series[0].data, index)
// 当前节点展开
this.findId(this.option.series[0].data, param.value, 'setCollapsed')
this.map.set(this.currentClickObj.value, true) // 将当前节点设置为收缩状态
// 重新渲染 echart中的data更改的时候,需要重新渲染
this.myChart.clear()
this.myChart.setOption(this.option)
}
// 计算高度
//计算高度这个点,我是查找此子树的每个级别的节点,并找出最多的节点数,根据这个子节点数来计算高度
this.listNumber = []
let charts = document.getElementById('myChart')
this.findMostLeaves(param.data.index + 1)
// Math.max.apply(null, this.listNumber) 取出listNumber中的最大值并且计算高度
charts.style.height = Math.max.apply(null, this.listNumber) * 80 + 500 + 'px'
// 重要的一步,小编当时就是漏掉此步,导致没办法更新高度,敲黑板
this.myChart.resize()
},
//////////////////////////分割线//////////////////////////
// 将同级的全部收缩
handleCollapsed(array, index) {
array.forEach((value, i) => {
if (value.index == index) {
value.collapsed = true // collapsed属性为true,设置此节点收缩状态
this.map.set(value.value, false) // 并且将此节点设置为可收缩状态(map)
} else {
if (value.children.length > 0) {
// 递归
this.handleCollapsed(value.children, index)
} else {
return
}
}
})
}
//////////////////////////分割线//////////////////////////
// 查找当前节点 当前节点展开
findId(array, id, flag) {
array.forEach((value, i) => {
if (value.value == id) {
if (flag == 'setCollapsed') {
value.collapsed = false //collapsed属性为true,设置此节点展开状态
this.map.set(value.value, true) // 并且将此节点设置为可展开状态(map)
} else {
this.currentClickObj = value
}
} else {
if (value.children.length > 0) {
this.findId(value.children, id, flag)
} else {
return
}
}
})
}
//////////////////////////分割线//////////////////////////
// 找出最多的节点
findMostLeaves(index) {
// this.myChart._chartsViews[0]._data.tree._nodes 此值是tree数据将结构中的数据,左击的时候就可以获取到此数值,并且里面的isExpand就是判断当前节点的展开和收缩状态
this.myChart._chartsViews[0]._data.tree._nodes.forEach(value => {
if (value.depth <= index) {
if (value.isExpand) {
// 将每一个等级的叶子数量存入listNumber中
this.listNumber.push(value.children.length)
}
}
})
}
- 我当时这篇文章帮了我很多,可以参考
- 此过程中用到的map类型,将在下期总结ES6的map和set的用法(敬请期待鸭)
感谢您的view,留个赞再走呗