记录在Vue项目中使用ECharts遇到的问题

1,850 阅读6分钟

1、在折线图/柱状图中,如何自定义悬浮提示框tooltip之formatter?

项目需求:在折线图上,鼠标悬停后,提示框除了展示横纵坐标相关数据外,还需额外展示其余相关数据, 如下图所示。

解决思路

1、首先,搞清楚tooltip里的数据配置项options的哪儿获取:传递到tooltip.formatter函数里的参数params是从series里面的data获取。( 解释series: 系列列表,每个系列通过 type 决定自己的图表类型。其数据格式为[{},{},...],每个{}存贮对每条曲线的配置项。)因此,tooltip.formatter方法中的参数params格式也是对象数据。

2、其次,当鼠标悬浮于图表中某个坐标交叉点后,便会触发options.tooltip.formatter()方法。

文档中对formatter的说明:

标签内容格式器,支持字符串模板和回调函数两种形式,字符串模板与回调函数返回的字符串均支持用 \n 换行。

字符串模板 模板变量有:
{a}:系列名。
{b}:数据名。
{c}:数据值。
{@xxx}:数据中名为'xxx'的维度的值,如{@product}表示名为'product'的维度的值。 {@[n]}:数据中维度n的值,如{@[3]} 表示维度 3 的值,从 0 开始计数。
示例: formatter: '{b}: {@score}'

解决方案:通过自定义配置option.tooltip.formatter()方法。

后端数据格式:

avgFailCountList: [
    {time: "2020-04-09", failCount: 490720, failNum: 42867, avgFailCount: 11},
    {time: "2020-04-10", failCount: 2652729, failNum: 79549, avgFailCount: 27},
    {time: "2020-04-11", failCount: 2327734, failNum: 137805, avgFailCount: 16},
    {time: "2020-04-12", failCount: 1107100, failNum: 93675, avgFailCount: 11},
    {time: "2020-04-13", failCount: 214373, failNum: 11233, avgFailCount: 19},
    {time: "2020-04-14", failCount: 262099, failNum: 22946, avgFailCount: 11},
    {time: "2020-04-15", failCount: 279015, failNum: 30705, avgFailCount: 9}
]

配置项具体操作如下:

optionsHandle(res) {  // res 为后端返回数据
    options.tooltip.formatter = function(params) {
        let item = params[0]
        item.data = res

        let _avgFailCount = ''
        let _failNum = ''
        let _failCount = ''
        for(let i = 0; i < item.data.length; i++) {
            // 分别将item.name(横坐标值)和item.data[i].time作比较,并分别赋给自定义的变量,便于return 时返回鼠标悬浮于该点的数据值
            if(item.name == item.data[i].time) {
                _avgFailCount = item.data[i].avgFailCount
                _failNum = item.data[i].failNum
                _failCount = item.data[i].failCount
            }
        }
        return `日期:${item.name} <br/>
                拉流失败次数:${_failCount} <br/>
                拉流失败人数:${_failNum} <br/>
                ${item.seriesName}${_avgFailCount}`
    }
}

本例中,打印参数params如下:


2、在一个折线图中,需要展示多条曲线,各曲线的X轴数值不同,如何展示?

项目需求:如下图所示的折线图,展示多个用户uid的上行帧率数据,每个用户展示一条曲线。但采集到的用户数据起止时间各不相同,且各个用户的时间间隔也不相同,需要按照正常的时间顺序,使图表正确展示。

解决思路

1、因为每条线的x轴不同,所以普通的渲染方式无法实现。

2、解决办法是将所有曲线的所有时间点进行聚合并排序(日期的从小到大),并赋值给x轴的配置项options.xAxis.data。

3、设置options.series[i].data(i代表该条曲线)的数据格式 -- [ [x,y],[x,y],... ].如下所示。

4、至此,通过每条曲线的x轴的时间和所有聚合的时间进行比较,分别对每条曲线进行绘制。(思路代码如下并标有备注)

后端数据格式:


cpuList: [
  [ 
    {time: "2020-04-18 14:44:43", value: "43.33", uid: "2524412"}, 
    {time: "2020-04-18 14:45:13", value: "38.0", uid: "2524412"}
  ]
  [ 
    {time: "2020-04-18 14:24:49", value: "26.91", uid: "2497102"},
    {time: "2020-04-18 14:25:19", value: "57.66", uid: "2497102"}, 
    {time: "2020-04-18 14:25:49", value: "33.28", uid: "2497102"},
    {time: "2020-04-18 14:26:19", value: "37.93", uid: "2497102"}, 
    {time: "2020-04-18 14:26:49", value: "20.49", uid: "2497102"}, 
    ...
  ]
  [ {time: "2020-04-18 14:36:54", value: "37.42", uid: "2086662"}, 
    {time: "2020-04-18 14:37:24", value: "46.4", uid: "2086662"}, 
    {time: "2020-04-18 14:37:54", value: "38.47", uid: "2086662"}, 
    {time: "2020-04-18 14:38:24", value: "52.31", uid: "2086662"}, 
    {time: "2020-04-18 14:38:54", value: "46.94", uid: "2086662"},
    ...
  ]
  [ 
    {time: "2020-04-18 14:37:06", value: "57.4", uid: "3868963"},
    {time: "2020-04-18 14:37:36", value: "71.85", uid: "3868963"},
    {time: "2020-04-18 14:38:06", value: "29.82", uid: "3868963"},
    {time: "2020-04-18 14:38:36", value: "25.02", uid: "3868963"},
    {time: "2020-04-18 14:39:06", value: "65.13", uid: "3868963"},
    {time: "2020-04-18 14:39:36", value: "68.03", uid: "3868963"},
    ...
  ]
]

代码如下:

// 配置项 resData为后端返回数据(上面已举例),resName为y轴名称(yAxis[i].name)
optionsHandle(resData, resName) {
    // 配置系列项,即这张图表每条曲线的基础配置
    let seriesItem = {
        type: 'line',
        symbolSize: 6,
        smooth: true,
        yAxisIndex: 0,
        lineStyle: { // 折线样式
            width: 2
        },
        areaStyle: {  // 填充区域
            opacity: 0.1
        },
        symbol: 'circle',
        markPoint: {
            symbol: 'circle',
            symbolSize: 9,
            itemStyle: {
                color: '#016072'
            },
            data: [
                {
                    symbol: 'pin',
                    symbolSize: 25,
                    itemStyle: {
                        color: '#555'
                    }
                }
            ]
        }
    }
    // 根据后端返回数据的条数(有几条折线),动态配置有多少系列列表 
    for(let i = 0; i < resData.length; i++) { 
        this.options.series.push(seriesItem)
    }

    let options = JSON.parse(JSON.stringify(this.options)) // this.options为此项目options的基础配置
    let clientTime = []  // 定义横坐标时间数组
    // 遍历后端返回的所有项(包括每条曲线的所有time),进行聚合
    for(let i = 0; i < resData.length; i++) { 
        let timeSet = resData[i].map(item => item.time)
        clientTime = [...clientTime, ...timeSet]
    }
    // 聚合所有time 并去重,排序
    clientTime = [...new Set(clientTime)]
    // 此函数功能:对时间排序
    function sortUpDate(a, b) { 
        return Date.parse(a) - Date.parse(b)
    }
    clientTime.sort(sortUpDate) // 日期排序

    // 对图表x轴赋值,不显示 年 (eg: 04-18 12:23:09)
    options.xAxis.data = clientTime.map(item => item.substr(5))
    options.grid.left = '6%'
    options.yAxis[0].name = resName
    
    // 配置图表右上方的标记属性
    for(let i = 0; i < resData.length; i++) {
        options.legend.data.push(resData[i][0].uid)
        options.series[i].name = resData[i][0].uid
    }

    // 在options配置项里 配置每条曲线的数据 格式为 
    // options.series[i].data = [['04-18 12:23:09', 232],['04-18 14:23:09', 1232],...]
    let itemArr = []
    for(let i = 0; i < resData.length; i++) {
        let res = []
        resData[i].map(item => {
            itemArr =  [item.time.substr(5), item.value]
            res.push(itemArr)
        })
        options.series[i].data = res
        
    }
    
    return options
}