阅读 169

Echarts 5 瞎入门指南 - 9

本章学习下Graph流程关系图, 这里以郭宝坤身边的关系图为例!!


//创建郭宝坤人际圈
const GuoBaoKun = [
    { name: '郭攸之', x: 100, y: 200 },
    { name: '太子', x: 200, y: 200 },
    { name: '范闲', x: 300, y: 200 },
]

复制代码
//封装连接线label
function formatLineLabel(relation={}) { //relation:人物关系
    return {
        show: true,
        formatter: function (m) {
            return relation[m.data.target]
        }
    }
}

复制代码

//创建option

const options = {
    tooltip: {},
    series: [
        {
            type: 'graph', //关系图
            symbolSize: 70,
            label: {show: true}, //显示节点文字
            edgeSymbol: ['none', 'arrow'], // 连接线两端形状,这里设置箭头
            data: [
                { name: '郭宝坤',  x: 200,  y: 100 },
                ...GuoBaoKun
            ],
            links: GuoBaoKun.map(item => {
                return  {
                    source: '郭宝坤', //起点
                    target: item.name,  //终点
                    symbolSize: 20,  //箭头大小
                    label: formatLineLabel({
                        '太子': '效忠',
                        '郭攸之': '父亲',
                        '范闲': '仇人',
                    })
                }
            })
        }
    ]
}

复制代码
//渲染图形
import * as echarts from 'echarts'

let myChart = null

myChart = echarts.init(dom)
myChart.setOption(options)

复制代码

这样一个简单的郭宝坤人物关系图就完成了

f7114a3f2e8d70ca10be31afd0818432.png

可以看到默认是圆形节点, 我们可以根据需求设置成长方形

设置各种形状的节点

    series: [
        {
            type: 'graph',
            symbol: 'rect',  //设置成长方形 
            //symbol: 'diamond', 设置成菱形◇
            //symbol: 'triangle', 设置成三角形
            //symbolSize: [100, 50], //设置长宽
            ...
        }
    ]
复制代码

来看下不同的效果图

2c9ec43add7ac286ced08aea3eeb0ca3.png

1d84d9c17f7a67ed2fb006767fc527cb.png

接下来拓展下人际关系, 我们就以范闲为例好了

拓展三级节点

//创建范闲人际圈
const FanXian = [
    { name: '陈萍萍', x: 100, y: 300 },
    { name: '林婉儿', x: 200, y: 300 },
    { name: '五竹', x: 300, y: 300 },
]
复制代码

有了人际关系,接下来我们只要在links 扩展下就可以了

links: GuoBaoKun.map(item => {
    return  {
        source: '郭宝坤',  
        target: item.name, 
        symbolSize: 20,  
        label: formatLineLabel({
            '太子': '效忠',
            '郭攸之': '父亲',
            '范闲': '仇人',
        })
    }
}).concat(FanXian.map(item => {   //这里拓展下连接线即可
    return {
        source: '范闲',
        target: item.name,
        symbolSize: 20,
        label: formatLineLabel({
            '陈萍萍': '恩师',
            '林婉儿': '爱人',
            '五竹': '叔叔',
        })
    }
}))
复制代码

效果图

47dd195dc14f1a977d503d3f833d16f7.png

有需要可以继续拓展下去,这里我就不再写了, 不过我们可以修改下连接线样式

设置连接线

series: [
    {
        ...
        lineStyle: {
            type: 'dashed',
            color: '#201ba1',
            curveness: 0.2,  //曲线 弯曲度 0~1  当然也支持负的, 只是弯曲的方向不同
        },
        
        //设置 节点文字样式
        label: {}, 
        
        //设置连接线上文字样式
        edgeLabel: {
            color: 'red',
            fontSize: 16,
        },
    }
]
复制代码

参考图

连接线.png

接下来我们试下让虚线动起来, 这样从哪到哪的可视化效果就比较明显些

动态虚线图

    所先讲下原理: 通过不断改变dashOffset 实现
    let dashOffset = 5
    
    options = {
        ...
        series: [
            {
                ...
                lineStyle: {
                    ...
                    type: [5, 10],
                    dashOffset: dashOffset,
                }  
            }
        ]
    } 
    
    
    function move() {
        dashOffset++
        if(dashOffset > 15) {
            dashOffset = 0
        }
        myChart.setOption(options)  
        setTimeout(move, 20)
    }
    
复制代码

效果图

虚线动图.gif 比较细的人可能觉得虚线逆流了, 我们只要让 dashOffset-- 即可

动态伸缩节点

可能这时候又来了个需求需要节点可伸缩展示, 点击一下展开子节点, 再点一下关闭子节点那种, 于是乎我们又要继续拓展了, 所先点击我们就想到了echarts的点击事件, 但是怎么给每个节点绑定,并且怎么知道点击的是哪个节点呢, 让我们一起来看下

这里我们还是以范闲为例

//首先创建个开关, 因为我们只给范闲添加事件,  所以只要一个开关
//如果添加多个节点事件可以根据需求创建对象

let showFanxianRelation = false  //默认不展示子节点

复制代码

把上面代码改造下,分离各个模块

//创建郭宝坤人际圈连接线links

const links_gbk = GuoBaoKun.map(item => {
    return  {
        source: '郭宝坤',
        target: item.name,
        symbolSize: 20,  //箭头大小
        label: formatLineLabel({
            '太子': '效忠',
            '郭攸之': '父亲',
            '范闲': '仇人',
        })
    }
})
复制代码
//创建范闲人际圈连接线links

const links_fx = FanXian.map(item => {
    return {
        source: '范闲',
        target: item.name,
        symbolSize: 20,
        label: formatLineLabel({
            '陈萍萍': '恩师',
            '林婉儿': '爱人',
            '五竹': '叔叔',
        })
    }
})
复制代码

初始化options里面的 links 和series的data (设置初始状态不包含人际圈,只展示范闲个人)

let links = links_gbk
let seriesData = [
    {name: '郭宝坤', x: 200, y: 100},
    ...GuoBaoKun 
]
复制代码
const options = {
    ...
    data: seriesData,
    links: links
}
复制代码

接来下只要添加事件,通过点击动态添加人际关系圈就行了

myChart && myChart.on('click', params => {
    console.log(params)  
    //这里可以通过params得到每个节点信息,然后再判断点击了哪个节点
})
复制代码

错误示例 - 全局更新 ❌

myChart && myChart.on('click', {name: '范闲'}, () => {
    //这里我指定了节点,所以不用再判断了
    
    showFanxianRelation = !showFanxianRelation
    if(showFanxianRelation) {
        links = [...links, ...links_fx]  //添加范闲关系线
        seriesData = [...seriesData, ...FanXian]
        
        //这里有个细节, 修改了数据后该怎么重新渲染呢
        //如果重新调用一遍渲染函数你会发现dom报错, 已经被占了,
        //这时候可能会调用myChart.dispose() 销毁之前的实例,
        
        myChart.dispose()
        myChart.init() 

    } else {
        ...
        //把数据还原成初始状态
    }
})
  // 但是这样每次点击节点会导致关系图闪一下, 全局更新了,
  // 所以这里我们不采取这种方法, 只要更新局部options就行
复制代码

正确示例 - 局部更新 ✔

myChart && myChart.on('click', {name: '范闲'}, () => {
    showFanxianRelation = !showFanxianRelation
    if(showFanxianRelation) {
        options.series[0].links = [...links, ...links_fx]  //添加范闲关系线
        options.series[0].data = [...seriesData, ...FanXian]
    } else {
        options.series[0].links = links_gbk
        options.series[0].data = [
            {name: '郭宝坤', x: 200, y: 100},
            ...GuoBaoKun 
        ]
    }
    
    myChart.setOptions(options)
})
复制代码

让我们来看下效果图

完美版伸缩.gif

最后的轻语

人这一生到底在追寻着什么

文章分类
前端