Echarts常见问题整理

文章目录

  • 前言
  • 一、常见问题记录
    • 1.如何创建一个自适应的Echarts图表(动态给Echarts图表当前高度初始化+窗口缩放Echarts图表自适应)
      • 动态高度初始化
        • 思路一:通过css样式aspect-ratio(宽高比)解决
        • 思路二:通过在父组件dom操作获取当前高度clientHeight(只读),作为参数调用子组件方法,在子组件获取到当前高度后初始化。
      • 窗口缩放时图表内容自适应
    • 2.调整Echarts图表大小、位置、显示网格线
    • 3.柱状图根据x坐标数量动态判断柱状图柱条的宽度、防止x坐标过多导致重叠
      • 宽度问题
      • 防止x坐标过多导致重叠
    • 4.Echarts实现渐变色及更新数据后渐变消失的问题
      • 线性渐变
      • 径向渐变
      • 重置数据渐变消失的问题
    • 5.Echarts中data和dataset的含义、Echarts数据返回格式
      • Echarts中data和dataset的含义
        • Data
        • dataset
      • Echarts数据返回格式
        • 维度和映射
          • 维度
          • 映射
  • 二、Echarts学习、解决问题建议
    • 1.先看官方文档的教程
    • 2.使用图表时先看示例有没有能用的,然后cv工程师
    • 3.遇到问题先搜博客
    • 4.博客解决不掉,或不起作用
    • 5.还是解决不掉怎么办?

前言

本次项目中负责了一个使用Echarts做的页面,涉及的图表类型有
柱状图(横竖两种)、折线图、气泡图、漏斗图、饼图
期间也遇到了不少问题,但是大部分的问题都是可以通过Echarts官方文档上找到解决办法的。下面记录一下问题及解决办法和Echarts的一些学习、码字心得。

一、常见问题记录

1.如何创建一个自适应的Echarts图表(动态给Echarts图表当前高度初始化+窗口缩放Echarts图表自适应)

讲道理这个问题一开始着实困扰我了大半天,因为页面需要自适应,根本不知道图表一开始具体的 Height 是多少。而且此次布局使用的是Flex布局,分左中右三块,每块上下各有一个图表,加一起是六个。这里有两种解决思路,各有优缺点吧,这次用的第二个。

提供的思路并非最优解,只是在解决本次项目的过程中效果比较好,如果有什么更好的想法欢迎指出

动态高度初始化

思路一:通过css样式aspect-ratio(宽高比)解决

因为采用的是Flex布局,而且是左中右三块,左右25%,中间50%,因此宽度是一定有的

此时,给图表的容器加上一个宽高比aspect-ratio,高度设置为100%,图表在初始化的时候就能根据宽高比初始化出来。

优点:

  1. 操作简单,css直接加就ok
  2. 对于宽高比确定的图表完美契合
  3. 图表不会变形

缺点

  1. 分配的宽度过大的话会影响整体布局(超出盒子范围)
  2. 不适合难以确定宽高比 或 图表不要求定型 的情况没办法使用
思路二:通过在父组件dom操作获取当前高度clientHeight(只读),作为参数调用子组件方法,在子组件获取到当前高度后初始化。

优点

  1. 布局不会乱
  2. 适合难以确定宽高比 或 图表不要求定型 的情况

缺点

  1. 这样写的高度是定死的除非再次传参初始化,否则在不同大小的显示器上就只有刷新后才能正常自适应

代码实现
父组件:关键代码

<Histogram ref="echarts1" />
// 有五个类似的组件
for (var i = 1; i <= 5; i++) {
      this.$refs['echarts'+i].setHeight(document.getElementsByClassName('side-echarts-container')[0].clientHeight)
}

子组件:关键代码

<template>
  <div>
    <div id="hstogram" class="charts" :style="{'height':sideEchartsContainerHeight+'px','width':' 100%'}"  />
  </div>
</template>

<script>
import * as echarts from 'echarts'
import { getBarGraphData } from '../../api/dataStatistics.js'
var option = {
  // color: ['rgb(245,33,45)', 'rgb(255,229,143)', 'rgb(11,115,255)'],
  color: [new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
              offset: 1,
              color: '#f00'
          }, {
              offset: 0,
              color: '#f99'
          }]), 
          new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
              offset: 1,
              color: 'rgb(249, 173, 21)'
          }, {
              offset: 0,
              color: 'rgb(255,255,153)'
          }]), 
          new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
              offset: 1,
              color: 'rgb(11,115,255)'
          }, {
              offset: 0,
              color: 'rgba(0,255,255)'
          }])
        ],
  legend: {
    textStyle: {
      color: 'white'
    },
    top: 25
  },
  grid: {
    show: true,
    borderColor: 'rgba(255, 255, 255,0.5)'
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'shadow'
    }
  },
  xAxis: {
    type: 'category',
    axisLabel: {
      interval: 0, // 显示全部x坐标
    //   rotate: 35,
      color: 'rgba(255, 255, 255,1)'
    },
    nameTextStyle: {
      align: 'center'
    },
    splitLine: {
      show: true,
      lineStyle: {
        color: 'rgba(255, 255, 255,0.5)',
        width: 1,
        type: 'dashed'
      }
    }
  },
  yAxis: {
    axisLabel: {
      color: 'rgba(255, 255, 255,1)'
    },
    splitLine: {
      lineStyle: {
        color: 'rgba(255, 255, 255,0.5)',
        width: 1,
        type: 'dashed'
      }
    }
  },
  series: [
    { 
      type: 'bar', 
      barWidth: 10,
      itemStyle: {
        //柱形图圆角,鼠标移上去效果,如果只是一个数字则说明四个参数全部设置为那么多
        normal: {
            //柱形图圆角,初始化效果
            barBorderRadius:[15, 15, 0, 0]
        }
      } 
    },
    { 
      type: 'bar', 
      barWidth: 10,
      itemStyle: {
        //柱形图圆角,鼠标移上去效果,如果只是一个数字则说明四个参数全部设置为那么多
        normal: {
            //柱形图圆角,初始化效果
            barBorderRadius:[15, 15, 0, 0]
        }
      } 
    },
    { 
      type: 'bar', 
      barWidth: 10,
      itemStyle: {
        //柱形图圆角,鼠标移上去效果,如果只是一个数字则说明四个参数全部设置为那么多
        normal: {
            //柱形图圆角,初始化效果
            barBorderRadius:[15, 15, 0, 0]
        }
      } 
    },
  ]
}

export default {
  name: 'Histogram',
  data() {
    return {
      charsData: [], // 之后通过请求放数据,需要效果的可以先加进去看看
      sideEchartsContainerHeight: 0
    }
  },
  methods: {
    setHeight(height){
      this.sideEchartsContainerHeight = height
      this.getData() // 请求默认数据(无参数)
      this.$nextTick(function() {
        this.echartsInit() // 初始化echarts
      })
    },
    echartsInit() {
      myEcharts = echarts.init(document.getElementById('hstogram')) // 获取图表节点
      myEcharts.setOption(option)
    }
  }
}
</script>

窗口缩放时图表内容自适应

其实图表本身是通过canvas这个容器画出来的,canvas在画完后想要让内容自适应只有重绘了。好在Echarts官方提供了这个函数resize()

// 监听实现
window.addEventListener('resize', function() {
  // bubbleChart 是图表的实例 echartsInstance(调用过init函数后)
  bubbleChart.resize()
})
// 手动调用
chartsResize(){
  bubbleChart.resize()
}

通过全局设置监听,实现在窗口缩放时图表的重绘,当然这个监听对象加给谁都行,但是要记得销毁

本次项目中将每个图表都搞成了一个组件(维护起来比较方便),然后在组件里面写的监听。
其实感觉正确的写法应该是在父组件加监听,调6个子组件的resize()方法的,但是项目比较急,就没维护这块。

2.调整Echarts图表大小、位置、显示网格线

通过在option中设置grid的四个值即可:

option = {
  grid: {
  	show:true, // 显示网格线
    top:10,
    left:10// bottom:10,
    // right:10
  }
}

grid设置两个值即可确定图表的大小和位置。值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比,也可以是 'left', 'center', 'right'。如果 left 的值为'left', 'center', 'right',组件会根据相应的位置自动对齐

值得一提的是,gridcontainLabel如果为true的话,grid决定的是包括了坐标轴标签在内的所有内容所形成的矩形的位置,常用于防止标签溢出的场景。为false,则只算由图标形成的区域。

网格的背景只有在设置show:true时才会起作用,默认为透明

3.柱状图根据x坐标数量动态判断柱状图柱条的宽度、防止x坐标过多导致重叠

本次在写项目时,由于存在检索范围这一条件,导致x坐标的个数有时候很密集,有时候有很稀疏,所以就有了要根据x坐标的个数来动态改变柱状图柱子的宽度,来保证图表不会引起误解(1月份的柱子太宽占到了2月份的坐标)。

宽度问题

图表的样式修改一般在series内的itemStyle里面,我们可以通过barwidth来修改柱状图柱条的宽度。

动态改变宽度的前提条件是我们需要知道数据量,也就是请求成功后的返回值。

// getBarGraphData 发出请求,.then表示请求成功后的回调函数,res为请求的返回值
getBarGraphData().then(res => {
   let baseLength = 10
   let resLength = 40 / res.data.length // 此处应该是 (图表宽度 / {请求返回的数据条数 * 每个x坐标展示的柱条个数})。结果可以稍微小点,便于更好的去展示。这里只是演示用,先写死了。
   myEcharts.setOption({
     series: [
       { type: 'bar', barWidth: Math.min(baseLength, resLength) },
       { type: 'bar', barWidth: Math.min(baseLength, resLength) },
       { type: 'bar', barWidth: Math.min(baseLength, resLength) }
     ],
     dataset: {
       dimensions: ['product', '红', '黄', '蓝'],
       source: that.charsData
     }
   })
 })

初始化时可以不给数据,只写配置。在请求成功后通过setOption更新配置即可。

防止x坐标过多导致重叠

两种解决办法

  1. 通过旋转一定的x坐标角度实现不重叠
    option = {
    	 xAxis: {
    	 	axisLabel: {
    	      //interval: 0, // 显示全部x坐标
    	      rotate: 35,
    	      color: 'rgba(255, 255, 255,1)'
    	    },
    	 }
    }
    
  2. 显示部分x坐标,隔几个个x坐标显示一个(间隔的x坐标数目固定)
    option = {
    	 xAxis: {
    	 	axisLabel: {
    	      interval: 1, // 是否显示全部x坐标
    	      // rotate: 35,
    	      color: 'rgba(255, 255, 255,1)'
    	    },
    	 }
    }
    

4.Echarts实现渐变色及更新数据后渐变消失的问题

如果我们不给图表设置颜色,图表会默认从['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc']中挑选颜色。但是单纯设置颜色有时候丑的一批,所以加上渐变效果会好很多

线性渐变

不知道为什么官方文档上没搜到,Echarts内部是带有一个渐变色生成器的

更多关于echarts.graphic的细节请参阅

就是不知道为啥,官方文档上没给出来这个东西。但其实是可以直接使用的,比如我希望柱状图的填充为渐变填充,我就可以这么写

option = {
	
	color: [
		// 第一个柱状图的颜色填充,参数依次对应 右/下/左/上 四个位置,1表示渐变色从正上方开始
		// 第5个参数则是一个数组 用于配置颜色的渐变过程. 包含offset和color两个参数. offset的范围是0 ~ 1, 用于表示位置, color表示颜色
		new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
	            offset: 1, // 100%处的颜色
	            color: '#f00'
	        }, {
	            offset: 0, // 0%处的颜色
	            color: '#f99'
	        }]), 
	        // 第二个柱状图的颜色填充
	        new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
	            offset: 1, // 100%处的颜色
	            color: 'rgb(249, 173, 21)'
	        }, {
	            offset: 0, // 0%处的颜色
	            color: 'rgb(255,255,153)' 
	        }])
	        // ... 以此类推
    ]
}

然后官方上貌似是直接把这个new出来的对象搞成配置项了,下面是官方的写法:

	option = {
		series:[{
			color: {
			    type: 'linear',
			    x: 0, // 渐变起始位置横坐标。
			    y: 0, // 渐变起始位置纵坐标。
			    x2: 0, // 渐变终止位置横坐标。
			    y2: 1, // 渐变终止位置纵坐标。
			    // 组成渐变色的颜色。每个颜色包括 offset 与 color 属性,
			    // 前者表示渐变位置(类型:number),后者表示具体的颜色(类型:string)
			    colorStops: [{ 
			        offset: 0, color: 'red' // 0% 处的颜色
			    }, {
			        offset: 1, color: 'blue' // 100% 处的颜色
			    }],
			    // 如果为 false,则 colorStops 取值范围是 0 到 1;
			    // 如果为 true,则 x、 y、 x2、 y2、 colorStops 的坐标和元素是一致的
			    // (也就是说,原先用 1 表示物体最右侧,这时需要用元素实际宽度表示最右侧)。
			    global: false // 缺省为 false
			}
		}]
	}

不是很清楚哪个好点,但是感觉上应该是直接配置会好点,而不是 new 调用。

径向渐变

new渐变色

option = {
	color: [
		// 第一个柱状图的颜色填充,参数依次对应 渐变中心位置横坐标/渐变中心位置纵坐标/渐变半径,默认值为0.5
		// 第5个参数则是一个数组 用于配置颜色的渐变过程. 包含offset和color两个参数. offset的范围是0 ~ 1, 用于表示位置, color表示颜色
		new echarts.graphic.RadialGradient(0.5, 0.5, 0.5, [{ // !!!! 此处是RadialGradient 而不是 LinearGradient
	            offset: 1, // 100%处的颜色
	            color: '#f00'
	        }, {
	            offset: 0, // 0%处的颜色
	            color: '#f99'
	        }]), 
	        // 第二个柱状图的颜色填充
	        new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
	            offset: 1, // 100%处的颜色
	            color: 'rgb(249, 173, 21)'
	        }, {
	            offset: 0, // 0%处的颜色
	            color: 'rgb(255,255,153)' 
	        }])
	        // ... 以此类推
    ]
}

官方文档写法

	option = {
		series:[{
			color: {
			    type: 'radial', // !!!!! 变成了radial
				x: 0.5,
				y: 0.5,
				r: 0.5,
			    // 组成渐变色的颜色。每个颜色包括 offset 与 color 属性,
			    // 前者表示渐变位置(类型:number),后者表示具体的颜色(类型:string)
			    colorStops: [{ 
			        offset: 0, color: 'red' // 0% 处的颜色
			    }, {
			        offset: 1, color: 'blue' // 100% 处的颜色
			    }],
			    // 如果为 false,则 colorStops 取值范围是 0 到 1;
			    // 如果为 true,则 x、 y、 x2、 y2、 colorStops 的坐标和元素是一致的
			    // (也就是说,原先用 1 表示物体最右侧,这时需要用元素实际宽度表示最右侧)。
			    global: false // 缺省为 false
			}
		}]
	}

重置数据渐变消失的问题

本次项目中因为需要隔一段时间执行一遍动画(科技感,要动态),所以就写了个计时器清空数据再放进去。

timer2 =  setInterval(function () {
    myEcharts.setOption({ // 展示/更新 数据
      series:[
        { data: [] }
      ]
    })
    myEcharts.setOption({ // 展示/更新 数据
     series:[
        { data: that.charsData }
     ]
    })
}, 6000)

上面这样写在其他图(柱状、饼、漏斗、气泡)里面都是可以正常出来重新加载的过度动画的。但是到了折线图里却没了反应
折线图只有在第一次执行setOption时才有过度动画,之后就没有了,思来想去没想出来啥问题。就避开了这个问题

这里使用了myEcharts.clear()方法清除了当前实例里面的内容(不是销毁),之后通过重新setOption来放入配置和数据实现动画加载。

然后问题来了,重新加载的图表走的是默认颜色!即使在新的配置里面写渐变色也还是没有起作用人直接傻了,想不通为啥。

解决办法
看了看官方文档,发现setOption接收的不止一个参数,他有一个notMerge这个参数,表示了是否不跟之前设置的 option 进行合并。默认为 false。改成true后解决了这个问题。

具体原因还是没搞明白。按理说默认合并也会和数据一样覆盖之前的数据啊,猜测是因为没有用官方写的渐变而是用了new实现,有待测试。

5.Echarts中data和dataset的含义、Echarts数据返回格式

Echarts中data和dataset的含义

乍一看下data和dataSet好像没什么区别,只是一个需要切割数据到每个series里,一个可以统一使用。但其实在一些特殊情况下,是不支持使用dataSet的。

举个例子:使用 dataset 同时使用 appendData,只支持系列使用自己的 series.data 时使用 appendData。

Data

没什么好说的,给那个系列哪个系列就用这组数据。

优点是

  • 直观易理解
  • 适于对一些特殊图表类型进行一定的数据类型定制

缺点是

  • 为匹配这种数据输入形式,常需要有数据处理的过程,分割到不同系列
  • 此外,不利于多个系列共享一份数据,也不利于基于原始数据进行图表类型、系列的映射安排
dataset

相对于data来说,最直观的就是我们不需要做分割数据的处理。

优点是

  • 能够贴近这样的数据可视化常见思维方式:(I) 提供数据,(II) 指定数据到视觉的映射,从而形成图表。
  • 数据和其他配置可以被分离开来。数据常变,其他配置常不变。分开易于分别管理。
  • 数据可以被多个系列或者组件复用,对于大数据量的场景,不必为每个系列创建一份数据。
  • 支持更多的数据的常用格式,例如二维数组、对象数组等,一定程度上避免使用者为了数据格式而进行转换。

缺点是

  • 可能需要对dataset进行映射,要理解维度和映射的意思。
  • 在部分场景下不适用,比如上面的例子。

根据之前的学习来看,应该是在数据量特别大的时候会用到一些特定的方法,在使用这些方法时不支持与dataset一起使用。假如我们数据量不是很大的情况下,还是dataset会方便好用一点

Echarts数据返回格式

data就不用说了吧,主要说下dataset

dataset常见的数据格式有下面两种

dataset: {
	// 提供一份数据。
	source: [
	     ['product', '2015', '2016', '2017'],
	     ['Matcha Latte', 43.3, 85.8, 93.7],
	     ['Milk Tea', 83.1, 73.4, 55.1],
	     ['Cheese Cocoa', 86.4, 65.2, 82.5],
	     ['Walnut Brownie', 72.4, 53.9, 39.1]
	 ]
}
dataset: {
     // 用 dimensions 指定了维度的顺序。直角坐标系中,
     // 默认把第一个维度映射到 X 轴上,第二个维度映射到 Y 轴上。
     // 如果不指定 dimensions,也可以通过指定 series.encode完成映射
     dimensions: ['product', '2015', '2016', '2017'],
     source: [
         {product: 'Matcha Latte', '2015': 43.3, '2016': 85.8, '2017': 93.7},
         {product: 'Milk Tea', '2015': 83.1, '2016': 73.4, '2017': 55.1},
         {product: 'Cheese Cocoa', '2015': 86.4, '2016': 65.2, '2017': 82.5},
         {product: 'Walnut Brownie', '2015': 72.4, '2016': 53.9, '2017': 39.1}
     ]
 },
维度和映射
维度

显然,相对于第一种来说,第二种可读性更高一点。但是第一种的灵活性更高

我们可以把维度理解为横纵两个方向(不考虑3d图,这个没了解呢哈哈)。

通过一定的配置,我们能够

  • 将横向维度的数据映射到x轴上,纵向的数据叫做横向维度的数据项
  • 将纵向维度的数据映射到x轴上,横向的数据叫做纵向维度的数据项

用第一个例子来帮助理解下:

dataset: {
	// 提供一份数据。
	// 横向维度就是每一行,纵向维度就是每一列。
	// 在此种数据格式下,我们可以轻松地理解维度的含义。
	// 我们可以将这份数据看做一个坐标系,第一列和第一行可以是xy轴(任意)
	// 后面的数据对应的是x轴和y轴所对应的值
	// 比如我把Matcha Latte当为x轴,那么43.3的意义是Matcha Latte在2015年的值
	// 或者我把2015当为x轴,那么43.3的意义是在2015年Matcha Latte的值
	source: [
	     ['product', '2015', '2016', '2017'],
	     ['Matcha Latte', 43.3, 85.8, 93.7],
	     ['Milk Tea', 83.1, 73.4, 55.1],
	     ['Cheese Cocoa', 86.4, 65.2, 82.5],
	     ['Walnut Brownie', 72.4, 53.9, 39.1]
	 ]
}

要实现上述更改xy轴的效果,可以使用 seriesLayoutBy 配置项,改变图表对于行列的理解。seriesLayoutBy 可取值:

  • 'column': 默认值。系列被安放到 dataset 的列上面。
  • 'row': 系列被安放到 dataset 的行上面。
option = {
	dataset:[
		source: [
	     ['product', '2015', '2016', '2017'],
	     ['Matcha Latte', 43.3, 85.8, 93.7],
	     ['Milk Tea', 83.1, 73.4, 55.1],
	     ['Cheese Cocoa', 86.4, 65.2, 82.5],
	     ['Walnut Brownie', 72.4, 53.9, 39.1]
	 ]
	],
	xAxis: [
        {type: 'category', gridIndex: 0},
        {type: 'category', gridIndex: 1}
    ],
    yAxis: [
        {gridIndex: 0},
        {gridIndex: 1}
    ],
    grid: [
        {bottom: '55%'},
        {top: '55%'}
    ],
    series: [
        // 这几个系列会在第一个直角坐标系中,每个系列对应到 dataset 的每一行。
        {type: 'bar', seriesLayoutBy: 'row'},
        {type: 'bar', seriesLayoutBy: 'row'},
        {type: 'bar', seriesLayoutBy: 'row'},
        // 这几个系列会在第二个直角坐标系中,每个系列对应到 dataset 的每一列。
        {type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
        {type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
        {type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
        {type: 'bar', xAxisIndex: 1, yAxisIndex: 1}
    ]
}
映射

一般通过series.encode来配置映射,效果和上面说的差不多,但是能够指定某列去映射,写个例子大家去官网上瞅瞅吧

	var option = {
    dataset: {
        source: [
            ['score', 'amount', 'product'],
            [89.3, 58212, 'Matcha Latte'],
            [57.1, 78254, 'Milk Tea'],
            [74.4, 41032, 'Cheese Cocoa'],
            [50.1, 12755, 'Cheese Brownie'],
            [89.7, 20145, 'Matcha Cocoa'],
            [68.1, 79146, 'Tea'],
            [19.6, 91852, 'Orange Juice'],
            [10.6, 101852, 'Lemon Juice'],
            [32.7, 20112, 'Walnut Brownie']
        ]
    },
    xAxis: {},
    yAxis: {type: 'category'},
    series: [
        {
            type: 'bar',
            encode: {
                // 将 "amount" 列映射到 X 轴。
                x: 'amount',
                // 将 "product" 列映射到 Y 轴。
                y: 'product'
            }
        }
    ]
};

二、Echarts学习、解决问题建议

1.先看官方文档的教程

5分钟上手ECharts

主要目的是看图表有哪几个部分,要改的话能够想起来去哪个属性里面看文档。这是其一

其二是对EChaarts有一个大体的了解

2.使用图表时先看示例有没有能用的,然后cv工程师

之后根据自己需求删删改改写配置

3.遇到问题先搜博客

不为其他,只为他快、准、狠。

4.博客解决不掉,或不起作用

根据博客提供的信息去官方文档上搜这个配置项。看看有没有细节性问题,或者博客中没写的、与自己使用的场景不符合的情况。

5.还是解决不掉怎么办?

在对图表有了大体认识后,确定需要改的东西叫什么,然后去搜配置项或者api,一个一个阅读吧,莫得办法。或者直接找大佬来帮忙看看也行。

你可能感兴趣的:(笔记,echarts,javascript,vue.js,前端,html)