一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情。
本文从工作中摘取比较有典型性的图表来展示echarts踩坑过程。
堆叠柱状图
有时候,我们不仅希望知道不同系列各自的数值,还希望知道它们之和的变化,这时候通常使用堆积柱状图图来表现。顾名思义,堆积柱状图就是一个系列的数值堆积在另一个系列上,因而从他们的高度总和就能表达总量的变化。
使用 EChart 实现堆积折线图的方法非常简单,只需要给一个系列的 stack 值设置一个字符串类型的值,这一个值表示该系列堆积的类别。也就是说,拥有同样 stack 值的系列将堆积在一组。
option = {
xAxis: {
data: ['A', 'B', 'C', 'D', 'E']
},
yAxis: {},
series: [
{
data: [10, 22, 28, 43, 49],
type: 'bar',
stack: 'x'
},
{
data: [5, 4, 3, 5, 10],
type: 'bar',
stack: 'x'
}
]
};
平滑的面积图
要做出下面的这个图有几点需要注意:
- 图形完全撑满整个区域
- 整个坐标系占满整个区域
- 隐藏坐标轴
- 去掉图形上面的点和线
getOptions() {
return {
xAxis: {
type: 'category',
show: false,
// 距离x轴两侧是有个距离,如果要做极限拉伸必须设置为false
boundaryGap: false
},
yAxis: {
show: false
},
series: [
{
type: 'line',
data: [123, 234, 422, 343, 234, 897, 1000, 410, 908, 100, 200],
// 展示面积区域
areaStyle: {
color: 'purple'
},
// 线条变的平滑
smooth: true,
// 去掉线条
lineStyle: {
width: 0
},
// 去掉点
itemStyle: {
opacity: 0
}
}
],
// 定位:让坐标系占满整个空间
grid: {
left: 0,
right: 0,
top: 0,
bottom: 0
}
}
}
自定义图表
我们现在来一步一步的实现上面这个图。
x轴和y轴颠倒
首先是把x轴当做y轴,把y轴当做x轴,颠倒过来才能把柱状图横着摆放:
xAxis: { type: 'value' },
yAxis: { type: 'category' }
上面的图是一个进度条,就是有一个总数,还有一个当前的进度,是两条数据,所以应该是两条柱状图:
series: [
{ type: 'bar', data: [200], barWidth: 10 },
{ type: 'bar', data: [250], barWidth: 10 },
]
最后利用stack属性把柱状图进行叠加:
series: [
{
type: 'bar',
// 让系列进行重合
stack: '总量',
data: [200],
barWidth: 10,
itemStyle: {
color: '#45c946'
}
},
{
type: 'bar',
stack: '总量',
data: [250],
itemStyle: {
color: '#eee'
}
}
]
自定义两个小三角
两个小三角,它们是根据数据进行位置移动的,那如何自定义绘图呢?
自定义绘图就是自定义一个系列, 也就是往series里面加一个对象,这个对象就是自定义的图形。
{
// type是custom表示是自定义的,
type: 'custom',
// 因为也要和上面的bar进行叠加,所以设置stact
stack: '总量',
// 这个数据一定要和进度数据保持一致
data: [100],
renderItem: (params, api) => {
const value = api.value(0)
// 就是自定义的图形放在哪个地方
const endPoint = api.coord([value, 0])
return {
// 返回一组自定义的图形
type: 'group',
position: endPoint,
children: [
{
type: 'path',
shape: {
// 这个就是svg,可以到iconfont里面找个图标,然后复制它的svg里面d属性的值即可
d: 'M1024 255.996 511.971 767.909 0 255.996 1024 255.996z',
// x, y表示相对于父节点进行偏移,就是微调放在哪个地方
x: -5,
y: -20,
// 设置图形的宽高
width: 10,
height: 10,
// 我们定义了图形的宽高,但是svg图形自己也有宽高,
// 为了让svg图形的宽高缩放到我们定义的宽高,那么就需要设置layout
layout: 'cover'
},
style: {
fill: '#45c946'
}
},
{
type: 'path',
shape: {
d: 'M0 767.909l512.029-511.913L1024 767.909 0 767.909z',
x: -5,
y: 10,
width: 10,
height: 10,
layout: 'cover'
},
style: {
fill: '#45c946'
}
}
]
}
}
}
如何画一个比较复杂的饼图
标题
标题有两个标题:
- 品类分布
- 累计订单量,320为副标题
title: [
{
text: `品类分布`,
textStyle: {
fontSize: 14,
color: '#666'
},
// 设置标题位置
left: 20,
top: 20
},
{
text: '累计订单量',
subtext: '320',
// 通过left top进行位置的迁移
left: '34.5%',
top: '42.5%',
// 文本水平居中
textAlign: 'center',
textStyle: {
fontSize: 14,
color: '#999'
},
subtextStyle: {
fontSize: 28,
color: '#333'
}
}
],
圆环
// 数据
chartData = [
{
legendname: axis[index],
value: item,
percent,
itemStyle: {
color: colors[index]
},
name: `${axis[index]} | ${percent}`
}
]
{
// 最好在每个系列中写一个name,因为这个name会展示到tooltip上。
name: '品类分布',
type: 'pie',
data: chartData,
label: {
show: true,
position: 'outter',
formatter: function(params) {
return params.data.legendname
}
},
// 圆心的位置,房子是宽度的35% 50%的位置,设置了圆心的位置相当于设置了图标的位置,因为饼图就是一个圆,圆心的位置决定了图的位置
center: ['35%', '50%'],
// 第一个参数是内半径,第二个参数是外半径,60%指的是整个宽高中最小的那个的60%作为直径, 默认是[0, 75%]
radius: ['45%', '60%'],
// 折线
labelLine: {
length: 15,
length2: 5,
smooth: true
},
// 数据排列顺序 顺时针 逆时针
clockwise: true,
// 给每个数据块加上一个border,并设置为白色,那么块和块之间就相当于有个空白
itemStyle: {
borderWidth: 4,
borderColor: '#fff'
}
}
legend
legend: {
type: 'scroll',
// 排列方式是垂直的
orient: 'vertical',
// 整个legend的高度,如果高度不够,那么就可以scroll
height: 250,
// 设置定位
left: '70%',
// 整个画布垂直居中
top: 'middle',
textStyle: {
color: '#8c8c8c'
}
},
tooltip
// 必须在数据中有name属性
tooltip: {
trigger: 'item',
formatter: function(params) {
const str =
params.seriesName +
'<br />' +
params.marker +
params.data.legendname +
'<br />' +
'数量:' +
params.data.value +
'<br />' +
'占比:' +
params.data.percent
return str
}
}
echarts插件:水球图
对于一些比较复杂的图标,我们也没有必要重新画,npm上有很多其他开发者创建的图标,我们可以拿来直接使用,现在以水球图为例来介绍如何使用echarts。
npm install echarts-liquidfill
import 'echarts-liquidfill'
series: [
{
type: 'liquidFill',
data: [percent],
color: [this.getColor(newValue)],
// 振幅8px
amplitude: 8,
radius: '80%',
name: '用户月同比增长',
label: {
position: ['50%', '50%'],
fontSize: 24,
color: '#999',
fontWeight: 'normal',
formatter: v => {
return `${(v.value * 100).toFixed(2)}%`
}
},
backgroundStyle: {
color: '#fff'
},
itemStyle: {
shadowBlur: 0,
shadowColor: '#fff'
},
outline: {
show: true,
// 内外边框的边距
borderDistance: 0,
itemStyle: {
color: 'none',
borderColor: '#aaa4a4',
borderWidth: 1,
shadowBlur: 0,
shadowColor: '#fff'
}
}
}
]