Echarts常见问题整理
前言
本次项目中负责了一个使用Echarts做的页面,涉及的图表类型有
柱状图(横竖两种)、折线图、气泡图、漏斗图、饼图
期间也遇到了不少问题,但是大部分的问题都是可以通过Echarts官方文档上找到解决办法的。下面记录一下问题及解决办法和Echarts的一些学习、码字心得。
一、常见问题记录
1.如何创建一个自适应的Echarts图表(动态给Echarts图表当前高度初始化+窗口缩放Echarts图表自适应)
讲道理这个问题一开始着实困扰我了大半天,因为页面需要自适应,根本不知道图表一开始具体的 Height 是多少。而且此次布局使用的是Flex布局,分左中右三块,每块上下各有一个图表,加一起是六个
。这里有两种解决思路,各有优缺点吧,这次用的第二个。
提供的思路并非最优解,只是在解决本次项目的过程中效果比较好,如果有什么更好的想法欢迎指出
动态高度初始化
思路一:通过css样式aspect-ratio(宽高比)解决
因为采用的是Flex布局
,而且是左中右三块,左右25%,中间50%,因此宽度是一定有的
此时,给图表的容器加上一个宽高比aspect-ratio,高度设置为100%
,图表在初始化的时候就能根据宽高比初始化出来。
优点:
- 操作简单,
css直接加
就ok - 对于
宽高比确定
的图表完美契合 - 图表
不会变形
缺点
- 分配的宽度过大的话会
影响整体布局
(超出盒子范围) 不适合
难以确定宽高比 或 图表不要求定型 的情况没办法使用
思路二:通过在父组件dom操作获取当前高度clientHeight(只读),作为参数调用子组件方法,在子组件获取到当前高度后初始化。
优点
布局不会乱
适合
难以确定宽高比 或 图表不要求定型 的情况
缺点
- 这样写的
高度是定死的
,除非再次传参初始化
,否则在不同大小的显示器上就只有刷新
后才能正常自适应
。
代码实现
父组件:关键代码
1 | <Histogram ref="echarts1" /> |
子组件:关键代码
1 | <template> |
窗口缩放时图表内容自适应
其实图表本身是通过canvas这个容器画出来的,canvas在画完后想要让内容自适应只有重绘了。好在Echarts官方提供了这个函数resize()
1 | // 监听实现 |
通过全局设置监听,实现在窗口缩放时图表的重绘,当然这个监听对象加给谁都行,但是要记得销毁
。
本次项目中将每个图表都搞成了一个组件(维护起来比较方便),然后在组件里面写的监听。
其实感觉正确的写法应该是在父组件加监听,调6个子组件的resize()
方法的,但是项目比较急,就没维护这块。
2.调整Echarts图表大小、位置、显示网格线
通过在option
中设置grid
的四个值即可:
1 | option = { |
grid
设置两个值即可确定图表的大小和位置。值可以是像 20
这样的具体像素值,可以是像 '20%'
这样相对于容器高宽的百分比,也可以是 'left', 'center', 'right'
。如果 left 的值为'left', 'center', 'right'
,组件会根据相应的位置自动对齐
。
值得一提的是,grid
中containLabel
如果为true
的话,grid
决定的是包括了坐标轴标签在内的所有内容所形成的矩形的位置,常用于防止标签溢出
的场景。为false
,则只算由图标形成的区域。
网格的背景只有在设置show:true时才会起作用,默认为透明
3.柱状图根据x坐标数量动态判断柱状图柱条的宽度、防止x坐标过多导致重叠
本次在写项目时,由于存在检索范围这一条件,导致x坐标的个数有时候很密集,有时候有很稀疏,所以就有了要根据x坐标的个数来动态改变柱状图柱子的宽度,来保证图表不会引起误解(1月份的柱子太宽占到了2月份的坐标)。
宽度问题
图表的样式修改一般在series
内的itemStyle
里面,我们可以通过barwidth
来修改柱状图柱条的宽度。
动态改变宽度的前提条件是我们需要知道数据量,也就是请求成功后的返回值。
1 | // getBarGraphData 发出请求,.then表示请求成功后的回调函数,res为请求的返回值 |
初始化时可以不给数据,只写配置。在请求成功后通过
setOption
更新配置即可。
防止x坐标过多导致重叠
两种解决办法
- 通过旋转一定的x坐标角度实现不重叠
1
2
3
4
5
6
7
8
9option = {
xAxis: {
axisLabel: {
//interval: 0, // 显示全部x坐标
rotate: 35,
color: 'rgba(255, 255, 255,1)'
},
}
} - 显示部分x坐标,隔几个个x坐标显示一个(间隔的x坐标数目固定)
1
2
3
4
5
6
7
8
9option = {
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内部是带有一个渐变色生成器的
就是不知道为啥,官方文档上没给出来这个东西。但其实是可以直接使用的,比如我希望柱状图的填充为渐变填充,我就可以这么写
1 | option = { |
然后官方上貌似是直接把这个new出来的对象搞成配置项了,下面是官方的写法:
1 | option = { |
不是很清楚哪个好点,但是感觉上应该是直接配置会好点,而不是 new 调用。
### 径向渐变
new渐变色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)'
}])
// ... 以此类推
]
}
官方文档写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
}
}]
}
### 重置数据渐变消失的问题
本次项目中因为需要隔一段时间执行一遍动画(科技感,要动态),所以就写了个计时器清空数据再放进去。
1
2
3
4
5
6
7
8
9
10
11
12
timer2 = setInterval(function () {
myEcharts.setOption({ // 展示/更新 数据
series:[
{ data: [] }
]
})
myEcharts.setOption({ // 展示/更新 数据
series:[
{ data: that.charsData }
]
})
}, 6000)
1 | option = { |
1 | option = { |
1 | timer2 = setInterval(function () { |
上面这样写在其他图(柱状、饼、漏斗、气泡)里面都是可以正常出来重新加载的过度动画的。但是到了折线图里却没了反应
。
折线图只有在第一次执行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常见的数据格式有下面两种
1 | dataset: { |
维度和映射
维度
显然,相对于第一种来说,第二种可读性更高一点
。但是第一种的灵活性更高
。
我们可以把维度理解为横纵两个方向
(不考虑3d图,这个没了解呢哈哈)。
通过一定的配置,我们能够
- 将横向维度的数据映射到x轴上,纵向的数据叫做横向维度的数据项
- 将纵向维度的数据映射到x轴上,横向的数据叫做纵向维度的数据项
用第一个例子来帮助理解下:
1 | dataset: { |
要实现上述更改xy轴的效果,可以使用 seriesLayoutBy
配置项,改变图表对于行列的理解。seriesLayoutBy
可取值:
'column'
: 默认值。系列被安放到 dataset 的列上面。'row'
: 系列被安放到 dataset 的行上面。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34option = {
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
来配置映射,效果和上面说的差不多,但是能够指定某列去映射
,写个例子大家去官网上瞅瞅吧
1 | var option = { |
Echarts常见问题整理