在某些需求下需要用到樹形圖來表達(dá)數(shù)據(jù)結(jié)構(gòu)刊头,我使用的是echarts逛绵,關(guān)于echart樹形圖的基礎(chǔ)配置和使用這里就不展開椿访。
直接上圖,這是一個(gè)基礎(chǔ)的樹形圖demo:
當(dāng)點(diǎn)擊非最末節(jié)點(diǎn)的時(shí)候,echart的默認(rèn)行為為收縮該節(jié)點(diǎn)的子節(jié)點(diǎn),這個(gè)行為會(huì)與下面實(shí)現(xiàn)的效果有關(guān)系加酵,效果:
現(xiàn)在回到標(biāo)題的需求根灯,當(dāng)點(diǎn)擊節(jié)點(diǎn)的時(shí)候,實(shí)現(xiàn)整條鏈路高亮中符,也就是更換線的顏色姜胖,因?yàn)榉亲钅┕?jié)點(diǎn)的節(jié)點(diǎn)可能對(duì)應(yīng)多個(gè)子節(jié)點(diǎn),所以只有最末節(jié)點(diǎn)才存在一對(duì)一的關(guān)系淀散,所以需求就是點(diǎn)擊末節(jié)點(diǎn)的時(shí)候右莱,實(shí)現(xiàn)整條鏈路高亮,效果:
下面進(jìn)入實(shí)現(xiàn)档插,一開始思考這個(gè)需求的時(shí)候慢蜓,以為跟經(jīng)常做的柱狀圖點(diǎn)擊更換柱子顏色一樣,都是去替換配置郭膛,當(dāng)然某種情況下也是可以實(shí)現(xiàn)的晨抡,先簡單說一下樹形圖的data結(jié)構(gòu),是使用children屬性層層嵌套的結(jié)構(gòu):
[
{
name: '',
value: 0,
itemStyle: {},
lineStyle: {},
children: [...]
}
]
按上面的思路,只要監(jiān)聽節(jié)點(diǎn)的點(diǎn)擊事件耘柱,然后獲取對(duì)應(yīng)鏈路相關(guān)的節(jié)點(diǎn)如捅,更改他們的lineStyle
,然后echart實(shí)例重新setOption
就可以帆谍,下面看一下大概實(shí)現(xiàn):
myChart.on('click', function (params) {
console.log(params)
})
看一下點(diǎn)擊節(jié)點(diǎn)伪朽,echart帶的參數(shù)
關(guān)注里面的兩個(gè)屬性,一個(gè)data汛蝙,也就是我們自己給節(jié)點(diǎn)添加的屬性烈涮,然后是treeAncestors屬性,它就代表了節(jié)點(diǎn)的鏈路關(guān)系窖剑,尋找唯一的父節(jié)點(diǎn)一直到根節(jié)點(diǎn)坚洽,這里只保留了name、value西土、dataIndex三個(gè)關(guān)鍵屬性讶舰,dataIndex是echart生成的唯一索引,在我們的原始數(shù)據(jù)中沒有需了,而name很有可能出現(xiàn)同名的情況跳昼,所以假設(shè)我們生成一個(gè)唯一的value,通過這個(gè)treeAncestors數(shù)組的每一個(gè)value和我們原始配置的數(shù)據(jù)中的value去匹配肋乍,相同的話就更換它的
lineStyle
屬性鹅颊,最后重新setOption
。具體實(shí)現(xiàn):
myChart.on('click', function (params) {
console.log(params)
// 深拷貝墓造,防止原始配置被修改
const copyOption = JSON.parse(JSON.stringify(initOption))
const data = params.data
if (data.children) {
return
} else {
const treeAncestors = params.treeAncestors
treeAncestors.forEach((item) => {
if(item.value !== undefined) {
findSameValue(copyOption.series[0].data, item.value)
}
})
myChart.setOption(copyOption)
}
})
function findSameValue(data, value) {
data.forEach((item) => {
if(item.value === value) {
item.lineStyle = {
color: '#42cccc'
}
}
if(item.children) {
findSameValue(item.children, value)
}
})
}
到這里這種點(diǎn)擊更換相關(guān)節(jié)點(diǎn)linestyle
的方式就實(shí)現(xiàn)堪伍,但是這種方式有兩個(gè)問題:
1.上面我們是假設(shè)value是唯一的,如果實(shí)際開發(fā)中value有實(shí)際用途不能讓我們生成唯一的值觅闽,這種方法就無法實(shí)現(xiàn)帝雇。但這個(gè)還不是致命的。
2.上面說到蛉拙,非最末節(jié)點(diǎn)點(diǎn)擊時(shí)尸闸,會(huì)收縮與展開它的子節(jié)點(diǎn),而我們上面實(shí)現(xiàn)高亮的時(shí)候是重新setOption
刘离,會(huì)將已操作的交互覆蓋掉室叉,點(diǎn)擊前效果:
點(diǎn)擊后:
可以看到,原本收起來的節(jié)點(diǎn)回到一開始的展開效果了硫惕,這對(duì)交互效果來說是致命的茧痕,
setOption
無法做到還保留之前的交互效果,所以這種實(shí)現(xiàn)方法要放棄了恼除。
實(shí)現(xiàn)高亮的核心還是更換節(jié)點(diǎn)屬性的linestyle
踪旷,但是不能通過重新setOption
來實(shí)現(xiàn)曼氛,在翻遍echart配置項(xiàng)的時(shí)候,最后看到了一個(gè)屬性和一個(gè)方法:
emphasis其實(shí)是定義鼠標(biāo)移入節(jié)點(diǎn)時(shí)的效果令野,但是在echart api中可以用
dispatchAction
來手動(dòng)觸發(fā)這個(gè)效果舀患,通過傳入type='highlight'
,那么只要在點(diǎn)擊的時(shí)候气破,通過dispatchAction
觸發(fā)相關(guān)節(jié)點(diǎn)的emphasis效果聊浅,那我們的需求就能實(shí)現(xiàn)了。dispatchAction
可以傳入節(jié)點(diǎn)的唯一索引dataIndex或者多個(gè)dataIIndex組成的數(shù)組现使,代表手動(dòng)高亮哪些節(jié)點(diǎn)低匙;且還有相對(duì)應(yīng)的取消emphasis效果的api,通過dispatchAction
傳入type='downplay'
來實(shí)現(xiàn)碳锈,很完美顽冶。
實(shí)現(xiàn):
先在echart配置項(xiàng)中添加emphasis時(shí)的效果:
series:[
{
....,
emphasis: {
lineStyle: {
color: '#42cccc'
}
}
}
]
因?yàn)?strong>emphasis屬性默認(rèn)是鼠標(biāo)移入節(jié)點(diǎn)時(shí)的效果,所以我們手動(dòng)觸發(fā)高亮?xí)湍J(rèn)行為沖突售碳,需要一個(gè)數(shù)組保存點(diǎn)擊高亮的節(jié)點(diǎn)dataIndex强重。
let currentDataIndexs = []
點(diǎn)擊時(shí)手動(dòng)觸發(fā)相關(guān)節(jié)點(diǎn)的高亮:
myChart.on('click', function (params) {
// 先取消已高亮的節(jié)點(diǎn)連線
myChart.dispatchAction({
type: 'downplay',
dataIndex: currentDataIndexs
})
// 針對(duì)非最尾節(jié)點(diǎn)點(diǎn)擊收縮展開后已高亮線路失效
if (params.data.children) {
myChart.dispatchAction({
type: 'highlight',
dataIndex: currentDataIndexs
})
return
}
const treeAncestors = params.treeAncestors
const dataIndexs = treeAncestors.map((item) => item.dataIndex)
// 重新保存當(dāng)前高亮的節(jié)點(diǎn)
currentDataIndexs = dataIndexs
// 高亮相關(guān)節(jié)點(diǎn)連線
myChart.dispatchAction({
type: 'highlight',
dataIndex: dataIndexs
})
})
還需要覆蓋emphasis的默認(rèn)行為,也就是鼠標(biāo)移入事件:
// 節(jié)點(diǎn)鼠標(biāo)移入事件
myChart.on('mouseover', function (params) {
// 取消當(dāng)前節(jié)點(diǎn)的高點(diǎn)贸人,頂替默認(rèn)事件
myChart.dispatchAction({
type: 'downplay',
dataIndex: params.dataIndex
})
// 高亮點(diǎn)擊已保存的相關(guān)節(jié)點(diǎn)的連線间景,防止上一步取消了已保存節(jié)點(diǎn)的高亮
myChart.dispatchAction({
type: 'highlight',
dataIndex: currentDataIndexs
})
})
實(shí)現(xiàn)效果:
點(diǎn)擊前:
點(diǎn)擊后:
實(shí)現(xiàn)了。
我是鴨子艺智,祝你幸福拱燃。