[本文出自天外归云的博客园]
需求
1. Vue中使用ECharts画散点图
2. 在图中加入加均值线
3. 在图中标注出阴影区域
实现
实现这个需求,要明确两点:
1. 知道如何在vue中使用echarts
2. 要知道如何在echarts散点图中画均值线和阴影区域
在下面的代码option对象的series属性中用到了markLine和markArea,标注最值用到了markPoint。
所以去官方文档搜索标线、标点、标图的关键字要搜mark。
如何在vue中使用echarts见文末。
需要注意的是vue的渲染时序,不要在页面没有渲染完就开始画图,那会找不到你定位id的元素。
如何解决找不到元素的问题呢?网上说是在mounted函数中调用nextTick,这种方法可以试试,我是没成功。所以我自己发明的解法如下:
以下的方法要放到vue文件的watch中,目的是监控showInfo和findAll两个变量的值的变化,一旦变量值变化则执行调用:
showInfo: function() { // 元素显示了开始画线,待优化,可以细分到不用showInfo控制,用每个chart的v-if分别进行控制,因为有时候可能没有图表数据 if (this.showInfo === true) { this.findAll = false this.timer = setInterval(() => { this.findElements() }, 1000) } }, findAll: function() { if (this.findAll === true) { console.log('Timer stop.') clearInterval(this.timer) } }
其中用到的变量都要在data函数中声明赋适当的初始值:
1. this.showInfo控制页面元素的v-if显示开关,而showInfo变量的初始值一般为false,在mounted函数中我们可以把它的值设置为true,等页面加载完后打开显示开关
2. this.timer是定时器,这里用到setInterval函数做一个定时的查询,用来定时查找页面上用来画echarts的div是否已经出现在页面,都找到了就停止定时查找
3. this.findAll是一个signal,一旦为true说明所有元素都已找到,立即清空定时器this.timer,不再定时查询
以下代码放到vue文件的methods中,是watch变量所用到的一些辅助函数:
findElements() { if (this.findEleById('test_id_1')) { this.if_find_test_img_1_id = true } if (this.findEleById('test_id_2')) { this.if_find_test_img_2_id = true } if (this.findEleById('test_id_3')) { this.if_find_test_img_3_id = true } if (this.if_find_test_img_1_id && this.if_find_test_img_2_id && this.if_find_test_img_3_id) { this.findAll = true } }, findEleById(ele_id) { var ele = document.getElementById(ele_id) if (ele !== null) { console.log('发现id为' + ele_id + '的元素') return true } return false }
ECharts设置相关的核心代码如下:
<template> <el-row> <el-col :span="24"> <div id="chartDivId" :style="{ '100%', height: '500px'}"></div> </el-col> </el-row> </template> <script> export default{ data() { return { imgData : { 'columns': ['c1','c2','c3'], 'rows': [ { 'c1': 'v1', 'c2': 'v2', 'c3': 'v3' }, ], 'mean': 2, 'y_top': 3, 'y_bottom': 1 }, methods: { // 画图函数,传入散点图所在div的id和图表数据 drawImgChart(chartDivId, imgData) { // 基于准备好的dom,初始化echarts实例 const myChart = this.$echarts.init(document.getElementById(chartDivId))// 绘制图表 var option = { tooltip: { trigger: 'axis', showDelay: 0, axisPointer: { show: true, type: 'cross', lineStyle: { type: 'dashed', 1 } } }, visualMap: { min: 0, max: imgData.mean, // 渐变色最深色对应的y轴坐标 dimension: 1, precision: 3, orient: 'vertical', right: 10, top: 'center', text: ['HIGH', 'LOW'], calculable: true, inRange: { color: ['#f2c31a', '#24b7f2'] } }, xAxis: [ { type: 'category', show: false, scale: true, splitLine: { show: true }, data: imgData.columns, // x轴的数据 axisLabel: { interval: 0, rotate: 70 } } ], yAxis: [ { type: 'value', scale: true, splitLine: { show: true }, axisLabel: { formatter: '{value} s' // y轴数据的格式 xx s } } ], series: [ { type: 'scatter', symbolSize: 5, data: imgData.rows, // 设置最大值点和最小值点 markPoint: { data: [ { type: 'max', name: '最大值' }, { type: 'min', name: '最小值' } ] }, // 设置平均值线 markLine: { lineStyle: { normal: { type: 'solid' } }, data: [ { name: '平均值线', yAxis: imgData.mean // 数值类型,对应y轴坐标 } ] }, // 设置阴影区域 markArea: { silent: true, itemStyle: { normal: { color: '#E8E8E8', borderWidth: 1, borderType: 'dashed' } }, data: [[{ name: '正常值范围区间', yAxis: imgData.y_top // 阴影区域上边界 }, { yAxis: imgData.y_bottom // 阴影区域下边界 }]] } } ] } myChart.setOption(option) } } } } }
谈谈封装
有时候封装的不好不如不封装,封装对外的接口如果不是大家需要的功能,反而相当于给被封装的对象关上了一道门,拒人于封装之外。
比如eleme和baidu维护的两版针对vue使用的vchart,我觉得现在的封装程度就是能用一些echart的基本功能,很多细节都没有封装好。
所以,即使vue不推荐直接操作dom元素,但是这次要在散点图中画线我还是选择用原装的echarts。