EChars的那些事儿

最近在做一个新项目,其中运用了大量的图表,主要有折线图、柱状图、饼图、雷达图四种;在考虑可扩展性的情况下,优先选择了ECharts,ECharts是百度开源的一款图表插件,本文主要是记录在项目开发是所遇到的样式及功能配置上的问题,以方便以后查阅;

折线图-双轴坐标对齐

折线图是最经常使用的图表之一,但是在样式上往往又不一样,经常需要按照设计需求定制,在本项目遇到的折线图问题主要是样式定制及双坐标轴不对齐的问题,以项目中的一个图表为例

目标图表
上面的是设计图表

基本图表
上面是Echart的官网基本图表

配置解析

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
var option = {
......
xAxis: [
{

type: 'category',
data: data.XData,//横坐标值
axisLine: { show: false },//隐藏坐标轴
axisTick: { show: false }//隐藏坐标轴上刻度线
}
],
yAxis: [
//使用左右双纵坐标
{
type: 'value',
scale: true,
name: '股价/元',
axisLine: { show: false },//隐藏坐标轴
axisTick: { show: false }//隐藏坐标轴上刻度线
},
{
type: 'value',
scale: true,
name: '评分/分',
axisLine: { show: false },
axisTick: { show: false },
}
],
series: [
{
name: '股价',
type: 'line',
symbol: "none",//隐藏折线图上的圆点
connectNulls: true,//连接空坐标点
itemStyle: { //线的颜色
color: '#2fade6'
},
lineStyle: { //线的宽度
width: 1
},
data: data.Ydata.Price//纵坐标值

},
{
name: '评分',
type: 'line',
yAxisIndex: 1,//选择右侧纵坐标
symbol: "none",
connectNulls: true,
itemStyle: {
color: '#ed6a13'
},
lineStyle: {
width: 1
},
data: data.Ydata.Score//纵坐标值
}

]
}

完成上述的配置后,发现样式基本一致,但是左右两个纵坐标刻度错乱,像这样
基本图表

查阅官方文档发现,刻度值的个数及间隔需要通过四个参数配置,即:maxminsplitNumberinterval;

  • max:坐标值刻度最大值,数据类型可以是number, string, function,默认值为null
  • min:坐标值刻度最小值,数据类型可以是number, string, function,默认值为null
  • splitNumber:坐标轴的分割段数,数据类型是number,默认值为5
  • interval:坐标轴刻度标签的显示间隔

写一个通用方法computeInterval

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/**
*
* @param {Array} arr 数组值
* @param {Number} spliNum 分割段数
* @param {Boole} isSym 是否上下对称
*/
function computeInterval(arr, spliNum, isSym){
//默认返回类型
var defaultResult = {
"max": null,
"min": null,
"interval": 'auto',
"spliNum": 5
}

try{
if (arr && arr.length) {
spliNum = spliNum || 5;

var max = Math.max.apply(null,arr); //获取最大值
var min = Math.min.apply(null,arr); //获取最小值

//取坐标轴的最大最小值,这里取最大值的1.2倍为上限
if (isSym) {
if (Math.abs(max) > Math.abs(min)) {
max = parseFloat((Math.abs(max) * 1.2).toFixed(2));
} else {
max = parseFloat((Math.abs(min) * 1.2).toFixed(2));
}
min = -max;
} else {
if (max > 0) {
max = Math.ceil(max) * 1.2
} else {
max = Math.floor(max) * 0.8
}

if (min > 0) {
min = Math.floor(min) * 0.8
} else {
min = Math.ceil(min) * 1.2
}

}

//获取分隔段数
var interval = ((max - min) / spliNum) || 'auto';

return {
"max": max,
"min": min,
"interval": interval,
"spliNum": spliNum
}
} else {
return defaultResult;
}
} catch (err) {
return defaultResult;

}
}

修改下上述配置

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
34
35
36
37
38
39
40
//根据纵坐标值计算分隔线
var res1 = calInterval(data.Ydata.Price);//左
var res2 = calInterval(data.Ydata.Score);//右
....
yAxis: [
//使用左右双纵坐标
{
type: 'value',
scale: true,
name: '股价/元',
axisLine: { show: false },//隐藏坐标轴
axisTick: { show: false },//隐藏坐标轴上刻度线
min: res1.max,
max: res1.min,
splitNumber: res1.spliNum,
interval: res1.interval,
axisLabel: {
formatter:function(value, index) {
return value.toFixed(2) //坐标刻度保留两个小数点
}
}
},
{
type: 'value',
scale: true,
name: '评分/分',
axisLine: { show: false },
axisTick: { show: false },
min: res2.max,
max: res2.min,
splitNumber: res2.spliNum,
interval: res2.interval,
axisLabel: {
formatter:function(value, index) {
return value.toFixed(2)
}
}
}
]
.....

最终完成效果最终效果

柱状图-数据堆叠

柱状图主要是数据堆叠及相关tooltip提示处理

目标

上面是设计图样式,如果按照一般情况去配置图表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var option = {
series: [
.....
{
name: '当日意愿上升',
type: 'bar',
barWidth: 30,
itemStyle: {
color: '#ff0000'
},
data: upBarData
},
{
name: '当日意愿下降',
type: 'bar',
barWidth: 30,
itemStyle: {
color: '#009944'
},
data: downBarData
}
]
}

基本

上面是普通柱状图配置信息,出来的图表你会发现和设计图有点差别,我们希望图表及提示框上升和下降只显示一个,此时就要用到数据堆叠了

  • stack:数据堆叠,同个类目轴上系列配置相同的stack值可以堆叠放置。[ default: null ]

改下配置即可

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
34
35
36
37
38
var option = {
series: [
//提示框
tooltip: {
trigger: 'axis',
formatter: function (params) {
var tar;
if (params[1].value != '-') {
tar = params[1];
}else {
tar = params[2];
}
return params[0].name + '<br/>' + params[0].seriesName + ' : ' + params[0].value + '<br/>'+ tar.seriesName + ' : ' + tar.value;
}
},
.....
{
name: '当日意愿上升',
type: 'bar',
barWidth: 30,
itemStyle: {
color: '#ff0000'
},
stack: '总量',
data: upBarData
},
{
name: '当日意愿下降',
type: 'bar',
barWidth: 30,
itemStyle: {
color: '#009944'
},
stack: '总量',
data: downBarData
}
]
}

饼图-富文本标签

目标

上图为设计图中饼图样式,和普通的拼图差别不大,唯一的难点可能就是图例文字部分的样式了,图例文字部分分a,b两处,简单的方法是直接设置a的宽度即可,像这样:

1
2
3
4
5
6
7
8
9
10
11

...

legend: {
formatter: function (name) {
var value = obj[name];
return '<div style="width:150px">'+name+'</div>'+value
}

},
...

但是会发现标签会被直接输出,此方法不通后,本想自己另外模拟图例,但是在查询官网后,发现ECharts提供了富文本标签,可以对图中的文本块进行单独的样式设置,具体配置可查阅官网,我们利用富文本修改配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...

legend: {
formatter: function (name) {
var value = obj[name];
var arr = [
'{a|' + name + '}',
'{b|' + value + '}',
]

return arr.join('')
},
textStyle:{
rich: {
a: {
width:150
},
b: {}
}
}

}

...

通过以上修改后,发现达到了我们所需要的效果;