1.小节概述
上小节中,我们搭建了Vue(2.x)项目并集成了ECharts(5.4.3)、Axios(1.4.0),从这节开始将通过完善项目来了解ECharts中各类图表的具体用法。ECharts本身功能比较强悍,建议在实际业务开发中遇到问题时多查阅官网文档,尤其是配置项手册、API、示例等内容。在本小节和后续专栏章节中,并非逐个学习了解官方文档的各个配置项或API,而是直接根据业务场景中的小需求点来熟悉ECharts图表的常用配置。
柱状图一般指柱形图,又称长条图、柱状统计图、条图、条状图、棒形图,是一种以长方形的长度为变量的统计图表,主要是用来反映对比数据之间的关系,也可以用来反应数据的变化趋势等。在本小节中,主要记录ECharts柱状图的基础设置,结合实际业务场景实现双柱图、堆叠柱图、动态排序柱状图、阶梯瀑布图等图表展现。
2.操作步骤
2.1.基础设置
1.以上小节最后得到的分公司销售量柱状图为例,首先调整下图例的设置,包括图例位置、图标类型、字体颜色大小等。图例展现了不同系列的标记,颜色和名字,可以通过点击图例控制哪些系列显示或者不显示。参考代码:
legend: {
show: true,
data: ["销量"],
icon: "roundRect",
x: "center",
y: "bottom",
padding: [0, 0, 10, 0],
textStyle: {
fontStyle: "normal",
fontSize: 12,
},
},
2.可以看到上图的图形位置感觉有点不正,可以通过绘图网格grid相关属性来调整图表离容器的距离样式,可以通过调整grid组件离容器上下左右的距离来控制图表位置(参数可以是具体像素值或百分比,后续随着图表元素的增多此处可以根据实际情况调整边距)。另外需要注意containLabel参数(grid区域是否包含坐标轴的刻度标签),有时为了防止标签溢出此处设置为true(算边距时带上刻度标签以防溢出容器或者覆盖其他组件)。参考代码:
grid: {
top: '8%',
bottom: '10%',
left: '2%',
right: '8%',
containLabel: true
},
3.提示框的内容设置(鼠标滑过或点击图表时的显示框),包括提示框内容字体颜色大小、提示框显示样式格式化等。参考代码:
tooltip: {
show: true,
textStyle: {
color: "#000000",
fontStyle: "normal",
fontSize: 14,
align: "left",
},
formatter: function (param) {
let message = "分公司:" + param.name + "<br />" + "销量:" + param.data;
return message;
},
},
4.坐标轴设置:x轴和y轴。
[1] 设置x轴和y轴刻度线、分割线、坐标轴轴线和箭头等样式内容。参考代码:
xAxis: {
type: 'category',
data: chartData.data.dept,
axisLine: {
// 坐标轴轴线
show: true,
// 只在末端显示箭头
symbol: ['none', 'arrow'],
// 箭头大小和位置
symbolSize: [6, 6],
symbolOffset: [0, 6],
},
axisTick: {
// 刻度线设置
show: true,
alignWithLabel: true,
},
axisLabel: {
show: true,
interval: 0,
},
splitLine: {
show: false,
},
},
yAxis: {
type: 'value',
name: '件',
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolSize: [6, 6],
symbolOffset: [0, 6],
},
axisTick: {
show: false,
alignWithLabel: true,
},
splitLine: {
// 分隔线设置
show: true,
lineStyle: {
color: ['#E5EAF3'],
width: 1,
type: 'dashed',
},
},
},
[2] 设置x轴横坐标:有时候横坐标值显示的字太多稍显拥挤甚至自动隐藏掉了,那么能否设置为倾斜显示。参考代码:
xAxis: {
axisLabel: {
show: true,
interval: 0,
rotate: 45,
},
},
[3] 设置x轴横坐标:既然横坐标值能倾斜显示,那么能否设置为竖排显示。参考代码:
axisLabel: {
show: true,
interval: 0,
// rotate: 45,
formatter: function (value) {
return value.split('').join('\n')
},
},
5.配置图表系列(series)。
[1] 为了方便记录,按照上小节搭建项目时的步骤,新建组件ChartBarTwo.vue(可以通过复制ChartBarOne快速创建),并引入到Home页图表2的位置上。设置柱子宽度,柱子圆角显示,设置柱子颜色和值显示到柱子上。参考代码:
series: [
{
name: '销量',
type: 'bar',
data: chartData.data.salesAmount,
// 设置柱子宽度
barWidth: 55,
label: {
// 值显示到柱子上
show: true,
position: 'top',
fontSize: 10,
},
itemStyle: {
// 顺时针设置圆角:左上、右上、右下、左下
borderRadius: [8, 8, 0, 0],
// 柱子颜色设置方式1:批量设置柱子颜色
color: '#F43368',
},
},
],
[2] 给不同的柱子设置不同的颜色。参考代码:
series: [
{
itemStyle: {
// 顺时针设置圆角:左上、右上、右下、左下
borderRadius: [8, 8, 0, 0],
// 柱子颜色设置方式2:给不同的柱子加不同颜色
color: function (params) {
let colorList = ["#5470C6","#91CC75","#FAC858","#EE6666","#73C0DE"];
return colorList[params.dataIndex];
},
},
},
],
[3] 根据值的情况给柱子设置不同的颜色,例如销量超过8000显示蓝色,销售超过5000低于8000显示黄色,销量低于5000显示红色。参考代码:
series: [
{
itemStyle: {
// 顺时针设置圆角:左上、右上、右下、左下
borderRadius: [8, 8, 0, 0],
// 柱子颜色设置方式3:根据值的情况设置不同颜色
color: function (params) {
let colorList = ["#5470C6", "#FAC858", "#EE6666"];
let amount = params.data;
if (amount >= 8000) {
return colorList[0];
} else if (amount < 8000 && amount >= 5000) {
return colorList[1];
} else {
return colorList[2];
}
},
},
},
],
[4] 标记最大值、最小值和平均值。参考代码:
grid: {
top: '14%',
bottom: '10%',
left: '2%',
right: '10%',
containLabel: true,
},
series: [
{
label: {
show: true,
position: 'inside',
fontSize: 10,
},
markPoint: {
data: [
{
type: "max",
name: "最大值",
symbol: "pin",
itemStyle: {color: '#5470C6'}
},
{
type: "min",
name: "最小值",
symbol: "pin",
itemStyle: {color: '#EE6666'}
},
],
},
markLine: {
data: [
{
type: "average",
name: "平均值",
},
],
},
},
],
6.至此,基础设置相关介绍告一段落,启动项目,预览Home页如下图:
2.2.双柱图和堆叠图
1.准备工作:假设要展示的各分公司销量包括两大产品的销售-牛奶和面包,那么可以用双柱图来展示。修改前端前需要再加一个后端接口(RAP接口管理平台中新建接口提供分公司牛奶和面包的产品销量),然后复制出一个的图表组件ChartBarThree.vue放在Home页图表3的位置上进行展示。
2.请求接口数据,配置series,实现双柱显示(即显示多个系列的柱子)。参考代码:
// 请求数据回来
async getChartData() {
this.chartData = await this.$axios({ url: 'sales/product' })
},
// 部分echarts配置项信息
legend: {
show: true,
x: "center",
y: "bottom",
padding: [0, 0, 10, 0],
},
series: [
{
name: '面包',
type: 'bar',
data: chartData.data.breadAmount,
itemStyle: {
// 顺时针设置圆角:左上、右上、右下、左下
borderRadius: [6, 6, 0, 0],
// 设置柱子颜色
color: '#5470C6',
},
},
{
name: '牛奶',
type: 'bar',
data: chartData.data.milkAmount,
itemStyle: {
// 顺时针设置圆角:左上、右上、右下、左下
borderRadius: [6, 6, 0, 0],
// 设置柱子颜色
color: '#91CC75',
},
},
],
3.既然已经展示了多条柱子,能否进行堆叠展示,并且希望顶部显示出来合计值。其实只需要给各个图例添加相同的stack属性便于实现,合计值的实现是在最后一个图例上显示值并进行格式化处理。参考代码:
series: [
{
name: '面包',
type: 'bar',
stack: '销量',
data: chartData.data.breadAmount,
itemStyle: {
// 顺时针设置圆角:左上、右上、右下、左下
borderRadius: [6, 6, 0, 0],
// 设置柱子颜色
color: '#5470C6',
},
},
{
name: '牛奶',
type: 'bar',
stack: '销量',
data: chartData.data.milkAmount,
itemStyle: {
// 顺时针设置圆角:左上、右上、右下、左下
borderRadius: [6, 6, 6, 6],
// 设置柱子颜色
color: '#91CC75',
},
label: {
show: true,
position: 'top',
fontSize: 10,
formatter: function (params) {
return params.data + chartData.data.breadAmount[params.dataIndex]
},
},
},
],
4.至此,双柱和堆叠相关介绍告一段落,启动项目,预览Home页如下图:
2.3.动态排序柱状图
1.动态排序柱状图是一种展示随时间变化的数据排名变化的图表。准备工作:假设要展示的各分公司上半年累计销量排名情况,那么可以用动态排序柱状图来展示。修改前端前需要再加一个后端接口(RAP接口管理平台中新建接口提供上半年销量数据),然后复制出一个的图表组件ChartBarFour.vue放在Home页图表4的位置上进行展示。
2.在ChartBarFour.vue组件中实现动态排序柱状图,具体实现要点包括:[1] 动态排序柱状图通常是横向的柱条,如果想要采用纵向的柱条,可以把x轴和y轴相反设置即可。[2] 在option中,设置series.realtimeSort、xAxis.max、yAxis.inverse、yAxis.animationDuration、animationDuration、animationDurationUpdate等参数。[3] 以 animationDurationUpdate 的频率调用 setInterval,更新数据值,显示下一个时间点对应的柱条排序。参考代码:
<template>
<div class="mainDiv">
<div class="titleDiv">上半年累计销量</div>
<div class="chartDiv" id="chartBarFour"></div>
</div>
</template>
<script>
export default {
data() {
return {
chartData: {},
saleAmountArray: {},
currentIndex: 0,
currentMonth: '2023.01',
}
},
name: 'ChartBarFour',
mounted() {
this.getChartData().then(() => {
let myChart = this.$echarts.init(document.getElementById('chartBarFour'))
// 数据请求到后渲染图表
this.renderChart(myChart)
// 更新图表option
let that = this
setInterval(function () {
that.update(myChart)
}, 3000)
})
},
methods: {
// 请求数据回来
async getChartData() {
this.chartData = await this.$axios({ url: '/sales/halfYear' })
this.saleAmountArray = this.chartData.data.salesAmount
},
// 渲染图表
renderChart(myChart) {
let chartData = this.chartData
let saleAmountArray = this.saleAmountArray
let index = this.currentIndex
var option = {
grid: {
top: '8%',
bottom: '5%',
left: '2%',
right: '12%',
containLabel: true,
},
xAxis: {
max: 'dataMax',
},
yAxis: {
type: 'category',
data: chartData.data.dept,
inverse: true,
animationDuration: 300,
animationDurationUpdate: 300,
max: 7,
},
series: [
{
realtimeSort: true,
name: '销量',
type: 'bar',
data: saleAmountArray[index].value,
label: {
show: true,
position: 'right',
valueAnimation: true,
},
itemStyle: {
// 顺时针设置圆角:左上、右上、右下、左下
borderRadius: [0, 8, 8, 0],
// 柱子颜色设置方式3:根据值的情况设置不同颜色
color: function (params) {
let colorList = ['#5470C6', '#FAC858', '#EE6666']
let amount = params.data
if (amount >= 6000) {
return colorList[0]
} else if (amount < 6000 && amount >= 4000) {
return colorList[1]
} else {
return colorList[2]
}
},
},
},
],
animationDuration: 3000,
animationDurationUpdate: 3000,
animationEasing: 'linear',
animationEasingUpdate: 'linear',
graphic: {
elements: [
{
type: 'text',
right: 20,
top: 0,
style: {
text: '2023.01',
font: 'bolder 20px monospace',
fill: 'rgba(100, 100, 100, 0.6)',
},
z: 100,
},
],
},
}
// 使用刚指定的配置项和数据显示图表
myChart.setOption(option)
},
// 更新图表option
update(myChart) {
// 半年度数据动态增长
if (this.currentIndex < 5) {
this.currentIndex = this.currentIndex + 1
} else {
this.currentIndex = 0
}
let saleAmountArray = this.saleAmountArray
let index = this.currentIndex
var newOption = {
series: [
{
data: saleAmountArray[index].value,
},
],
graphic: {
elements: [
{
type: 'text',
right: 20,
top: 0,
style: {
text: saleAmountArray[index].month,
font: 'bolder 20px monospace',
fill: 'rgba(100, 100, 100, 0.6)',
},
z: 100,
},
],
},
}
myChart.setOption(newOption)
},
},
}
</script>
<style scoped>
.mainDiv {
border: 1px solid;
height: 410px;
border-radius: 5px;
text-align: center;
}
.titleDiv {
height: 30px;
line-height: 30px;
font-size: 12;
}
.chartDiv {
height: 380px;
}
</style>
3.至此,动态排序柱状图相关介绍告一段落,启动项目,预览Home页如下图:
2.4.瀑布柱状图
1.瀑布图通过巧妙的设置,使图表中数据的排列形状(称为浮动列)看似瀑布悬空,从而反映数据在不同时期或受不同因素影响的程度及结果,还可以直观反映出数据的增减变化,常见的有瀑布柱状图和阶梯瀑布图。
2.瀑布柱状图主要反应数据的构成,例如展示当月收入来源情况。准备工作:修改前端前需要再加一个后端接口(RAP接口管理平台中新建接口提供当月收入来源数据),然后复制出一个的图表组件ChartBarFive.vue放在Home页图表5的位置上进行展示。
3.在ChartBarFive.vue组件中实现瀑布柱状图,实际上实现原理和堆叠柱状图是一样的,只不过通过柱状颜色把一些堆叠柱子隐藏掉了,这样看来就像瀑布一样,飞流直下。参考代码:
<template>
<div class="mainDiv">
<div class="titleDiv">当月收入来源情况</div>
<div class="chartDiv" id="chartBarFive"></div>
</div>
</template>
<script>
export default {
data() {
return {
chartData: {},
}
},
name: 'ChartBarFive',
mounted() {
this.getChartData().then(() => {
// 数据请求到后渲染图表
this.renderChart()
})
},
methods: {
// 请求数据回来
async getChartData() {
this.chartData = await this.$axios({ url: 'income' })
},
// 渲染图表
renderChart() {
let myChart = this.$echarts.init(document.getElementById('chartBarFive'))
let chartData = this.chartData
var option = {
tooltip: {
show: true,
},
grid: {
top: '5%',
bottom: '5%',
left: '2%',
right: '8%',
containLabel: true,
},
xAxis: {
type: 'category',
data: chartData.data.type,
axisTick: {
// 刻度线设置
show: true,
alignWithLabel: true,
},
splitLine: {
show: false,
},
},
yAxis: {
type: 'value',
},
series: [
{
name: '占位',
type: 'bar',
stack: '收入',
itemStyle: {
borderColor: 'transparent',
color: 'transparent',
},
emphasis: {
itemStyle: {
borderColor: 'transparent',
color: 'transparent',
},
},
data: chartData.data.placeholder,
},
{
name: '收入',
type: 'bar',
stack: '收入',
label: {
show: true,
position: 'inside',
},
itemStyle: {
color: function (params) {
if(params.name == '合计'){
return '#91CC75'
}else{
return '#5470C6'
}
}
},
data: chartData.data.income,
},
],
}
// 使用刚指定的配置项和数据显示图表
myChart.setOption(option)
},
},
}
</script>
<style scoped>
.mainDiv {
border: 1px solid;
height: 410px;
border-radius: 5px;
text-align: center;
}
.titleDiv {
height: 30px;
line-height: 30px;
font-size: 12;
}
.chartDiv {
height: 380px;
}
</style>
4.阶梯瀑布图可以展示出某个时间段线上某些值的增减情况,例如展示当月收入支出情况。准备工作:修改前端前需要再加一个后端接口(RAP接口管理平台中新建接口提供当月收入支出数据),然后复制出一个的图表组件ChartBarSix.vue放在Home页图表6的位置上进行展示。
5.在ChartBarSix.vue组件中实现阶梯瀑布图,相比瀑布柱状图,此处相当于进行三柱堆叠处理。参考代码:
<template>
<div class="mainDiv">
<div class="titleDiv">当月收入支出情况</div>
<div class="chartDiv" id="chartBarSix"></div>
</div>
</template>
<script>
export default {
data() {
return {
chartData: {},
}
},
name: 'ChartBarFive',
mounted() {
this.getChartData().then(() => {
// 数据请求到后渲染图表
this.renderChart()
})
},
methods: {
// 请求数据回来
async getChartData() {
this.chartData = await this.$axios({ url: 'income/expense' })
},
// 渲染图表
renderChart() {
let myChart = this.$echarts.init(document.getElementById('chartBarSix'))
let chartData = this.chartData
var option = {
tooltip: {
show: true,
},
grid: {
top: '5%',
bottom: '5%',
left: '2%',
right: '8%',
containLabel: true,
},
xAxis: {
type: 'category',
data: chartData.data.type,
axisTick: {
// 刻度线设置
show: true,
alignWithLabel: true,
},
splitLine: {
show: false,
},
},
yAxis: {
type: 'value',
},
series: [
{
name: '占位',
type: 'bar',
stack: '收支',
itemStyle: {
borderColor: 'transparent',
color: 'transparent',
},
emphasis: {
itemStyle: {
borderColor: 'transparent',
color: 'transparent',
},
},
data: chartData.data.placeholder,
},
{
name: '收入',
type: 'bar',
stack: '收支',
label: {
show: true,
position: 'inside',
fontSize: 10,
},
itemStyle: {
color: function (params) {
if (params.name == '合计') {
return '#91CC75'
} else {
return '#5470C6'
}
},
},
data: chartData.data.income,
},
{
name: '支出',
type: 'bar',
stack: '收支',
label: {
show: true,
position: 'inside',
fontSize: 10,
},
itemStyle: {
color: '#F43368',
},
data: chartData.data.expense,
},
],
}
// 使用刚指定的配置项和数据显示图表
myChart.setOption(option)
},
},
}
</script>
<style scoped>
.mainDiv {
border: 1px solid;
height: 410px;
border-radius: 5px;
text-align: center;
}
.titleDiv {
height: 30px;
line-height: 30px;
font-size: 12;
}
.chartDiv {
height: 380px;
}
</style>
6.至此,瀑布图相关介绍告一段落,启动项目,预览Home页如下图:
3.小节总结
柱状图最适合对分类的数据进行比较,尤其是当数值比较接近时,由于人眼对于高度的感知优于其他视觉元素(如面积、角度等),因此使用柱状图更加合适。本小节主要记录了ECharts柱状图的基础设置,并延伸介绍了如何实现双柱图、堆叠柱图、动态排序柱状图、瀑布柱状图、阶梯瀑布图等可视化图表。