记一次echarts使用中遇到的问题及解决方法

2 篇文章 0 订阅
1 篇文章 0 订阅

学习效率比较低,花了很长时间才弄明白如何使用echarts,因此还是记录一下,免得以后再后头来看时又不记得怎么改了。

设想

方案就是做一个如下的图表,默认提供的查询是一周内的统计,直接在时间线上点选即可;至于超出一周的将提供一个自定义日期查询
设想图

1.x轴显示问题

x轴显示不全
echarts提供了一个旋转的方式来显示x轴文字,但是显然不适合我的要求(难道要歪着脖子看x轴?度娘的东西果然不可靠
度娘经验的示例
很快找到了另一篇文章:《echarts x轴文字显示不全》,很容易就改好了,但是马上就发现有问题:即使改成了竖排,x轴上的产品名称比预想的还长,导致显示不完全,直接溢出了。不过该文章提供了双行显示的方法,效果如下:
一种双行显示效果
不过……既然已经是竖排显示了,为什么不干脆改得完整一点呢?每一行还是从左往右啊,不能忍……我想要的是这样的效果
设想的竖排显示效果
那么,只能自己写代码实现了,反正已经知道了可以自定义显示效果(添加一个option.xAxis.axisLabel.formatter即可),直接po代码:

function(val) { //val就是要显示在x轴上的字符串了
      var rows = 2 // 这个参数表示x轴的品名需要显示为几行
      if (val.length % rows) { //字数不够,空格来凑,否则错乱
         val += ' '.repeat(rows - val.length % rows) // 必须是全角字的空格,半角字的会被忽略掉,导致无效
      }
      var count = val.length / rows
      var formattedText = []
      for (var i = 0; i < count; i++) {
           formattedText[i] = ''
           for (var j = 0; j < rows; j++) {
                formattedText[i] += val[j * count + i]
           }
      }
      return formattedText.join('\n')
}

optionformatter的层级关系如下(因为timeline组件的配置必须(?)写在baseOption里面,所以多了一层baseOption):
option与formatter的层级关系
但是!!
我忍不住再想,固定死了显示为2行真的好吗?一定要让客户自己选择,于是把rows与data里的变量绑定:

data() {
  return {
	//其他变量
	xAxisRows: 2,
	//其他变量
	option: {
		baseOption: {
			xAxis: {
				formatter: function(val) {
				      var rows = this.xAxisRows // 绑定参数
				      //下面的代码是一样的
				}
			}
		}
	}
  }
}

然后在页面里添加一个下拉框改变rows的数值(这里使用了element-UI的样式):

<el-select v-model="xAxisRows" style="width:60px;">
        <el-option value="1"></el-option>
        <el-option value="2"></el-option>
        <el-option value="3"></el-option>
        <el-option value="4"></el-option>
</el-select>

2.vue中data中的变量互相调用

运行……报错:xAxisRows未定义,很明显,是data中的变量发生了互相调用的问题。
参考《vue中data数据之间的调用》做了修改,添加了mounted

mounted(){
    this.option.baseOption.xAxis.axisLabel.formatter = function(val) {
		var rows = this.xAxisRows // 绑定参数
		//下面的代码是一样的
	}
}

运行……还是报错,错误仍然是xAxisRows未定义。嗯……别人的情况跟我的还是略有不同的,所以不能照搬代码。
我也不知道为什么会报错,不过也懒得去想,总之把formatter的动态绑定改到method里总不会报错了吧。handleChangexAxis绑定到一个按钮上去,点击才会生效

method:{
      //修改x轴文字的显示行数
      handleChangexAxis() {
        this.option.baseOption.xAxis.axisLabel.formatter = (val) => {
          var len = this.xAxisRows // 这个参数表示x轴的品名需要显示为几行,只能在这里修改
          if (val.length % len) {
            val += ' '.repeat(len - val.length % len)
          }
          var count = val.length / len
          var formattedText = []
          for (var i = 0; i < count; i++) {
            formattedText[i] = ''
            for (var j = 0; j < len; j++) {
              formattedText[i] += val[j * count + i]
            }
          }
          return formattedText.join('\n')
        }
        this.chart.setOption(this.option)
      }
}

页面里写个按钮,点击就调用handleChangexAxis方法去修改formatter:

<el-select v-model="xAxisRows" style="width:60px;">
    <el-option value="1"></el-option>
    <el-option value="2"></el-option>
    <el-option value="3"></el-option>
    <el-option value="4"></el-option>
</el-select>
<el-button type="primary" @click="handleChangexAxis">修改X轴文字行数</el-button>

OK,这次没问题了。
最终的修改x轴显示方案

3.时间线与异步加载的数据

配置

在官方提供的示例中,所有的数据都是在已完全加载完毕的情况下才使用setOption加载图表的,实际应用时肯定不能这样,必须异步加载——用户点击查询了某个日期我才加载相应的数据,否则不加载。
为了做到这一点,我先给初始数据置空(不记得不初始化会不会有问题了,貌似会不显示图表?)。这里主要是时间线麻烦一点,其他的代码就省略了。

option: {
          baseOption: {
            timeline: {
              axisType: 'category',
              top: 50,
              lineStyle: {
                color: ['#409EFF']
              },
              autoPlay: false, // 不允许自动播放
              currentIndex: 5,
              playInterval: 1000,
              controlStyle: { showPlayBtn: false },
              data: [],
              label: {
                formatter: function(s) {
                  return s.substr(5, 6).replace('月', '-')
                }
              }
            },
            xAxis: {
              type: 'category',
              axisLabel: {
                interval: 0,
                formatter: function(val) {
                  var len = 2 // vue渲染页面时还是需要一个方法来显示x轴的,所以这里还是保留了一个formatter
                  // method中的那个formatter才是用了动态修改x轴显示的
                  
                  //此处省略重复代码
                }
              }
            },
            series: [ // 必须加入此项,否则会报错。虽然我的series只有一个元素
              { name: '单品出货量', type: 'bar' }
            ]
            // baseOption中的其他配置项
          },
          // options置空,需要加载数据时再从数据库拿,然后填充options中的各个元素
          options: [{}, {}, {}, {}, {}, {}, {}]
         

注意以下几点(正确性就懒得验证了,反正按照这个办法去做不会错):

  1. timeline的配置项放在baseOption中
  2. 因为有了baseOption,异步加载的数据就只能放在options中了
  3. 注意option和options不是同一个变量。option:{baseOption:{...}, options:[...] }
加载数据

不说废话,直接贴method里对应的代码

// 处理查询的数据,data是从服务器拿到的数据,
// index表示options: [{}, {}, {}, {}, {}, {}, {}]中的下标,因为默认是查询一周,所以有7个空对象
      proccessData(data, title, index) {
        var sum = 0
        var dataArr = new Array(this.option.baseOption.xAxis.data.length)
        for (var i = 0; i < data.length; i++) {
          if (data[i].grassCount) {
            sum += data[i].grassCount
            // 插入数据时,数据的位置与x轴的产品名位置对应
            dataArr[this.option.baseOption.xAxis.data.indexOf(data[i].grassName)] = data[i].grassCount
          } else {
            dataArr[this.option.baseOption.xAxis.data.indexOf(data[i].grassName)] = 0
          }
        }
        this.option.options[index] = {
          title: { text: title, subtext: '总出货量' + sum },
          series: [{ data: dataArr }]
        }
        //修改时间线上的小红点的位置
        this.option.baseOption.timeline.currentIndex = index
        //应用所做的更改
        this.chart.setOption(this.option)
      }

绑定时间线的点击事件,

this.chart.setOption(this.option)  // 将配置应用于图表
this.chart.on('timelinechanged', this.onChange)  // 绑定时间线点击事件

事件方法,params参数是由echarts传递过来的,默认有几个属性,但是我只用到了它的currentIndex属性

// 时间线选择发生变化时
      onChange(params) {
        this.option.baseOption.timeline.currentIndex = params.currentIndex
        var len = Object.keys(this.option.options[params.currentIndex]).length
        if (len === 0) { // 该日期数据为空,则获取
          getStaticsByDate({ date: this.option.baseOption.timeline.data[params.currentIndex] }).then(res => {
            var title = this.option.baseOption.timeline.data[params.currentIndex]
            title = title.replace(/[年月]/g, '-') + '单日出货量'
            this.proccessData(res.data, title, params.currentIndex)
          })
        }
      }

值得注意的是:
为了减少向数据库的请求,在加载选中日期的数据前,会先判断options对应下标里面有无数据,没有(即options[index]是{ })才请求数据并加载。
这里判断数据是否为空用了Object.keys,当然用JSON.stringify也是可以的。

  1. Object.keys是es6中的写法,可以用来检测对象是否为空,在vue中一定要像上面那样拆开来写,写在一起,如:
if (Object.keys(this.option.options[4]).length===0 ) {
  // code
}

这样是会出错的,vue会自动把Object.keys改成_Object$keys,运行时会被识别为undefined,然后每一次都会执行到if括号里面的代码了(即使上次已经加载过这个数据了),造成重复的数据请求。所以这里分开写,没有出错。

  1. JSON.stringify也不能连用,必须拆开:
// 错误写法    实际运行时会变成 if(undefined === '{}'),这样就永远都不会加载数据了
if(JSON.stringify(this.option.options[params.currentIndex]) === '{}') {
  // 加载数据
}
// 正确写法
var str = JSON.stringify(this.option.options[params.currentIndex])
if (str === '{}') {
  // 加载数据
}
  1. 初始化选中一个日期。
    用户进入这个页面时,还是应该默认加载一个日期的数据并显示出来,否则只能看到一个空的图表。
    既然已经把时间线的点击事件写完了,那么手动触发事件就行了。
    一般情况下是echarts产生onChange里的params参数的,但是这里是我手动触发这个事件,所以就自己创建一个带有currentIndex属性的对象传进去
mounted() {  // 不能用created,会报错的
  this.onChange({ currentIndex: 0 })  //加载options下标为0处的数据
}

4.其他配置

为了减少不必要的数据请求,这里已经将数据请求设置为点击才加载,那么时间线的自动播放事件也要给它停了,配置涉及到autoPlaycontrolStylelineStyle这些属性,修改柱形图的颜色则直接在option.baseOption.color中添加即可。

更多信息建议直接阅读echarts官方文档

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值