Vue中使用Echarts---小记
Echarts使用小结
vue环境使用echarts
1. 柱状图
1.1 分析
当前需求:
- 有横向滚动条;
- 柱条的颜色为渐变色;
- 鼠标悬浮自定义展示(展示数据百分比)
示例图:
柱状图的无法像饼状图可以获取每条数据的百分比,因此可能需要前端自己来计算(或后端直接返回百分比)。而按照普通方法:当前柱条数据除以总数据再进行小数位取舍,最后把各个柱条算出的百分比相加,往往达不到100%,一般是超了或者少了一点点。
因此,我们需要使用echarts中对百分比处理的方法来处理,echarts中使用“最大余额法”来计算。我们可以加以改造一下,以完成需求:
/**
* 百分比算法--最大余额法
* @param valueList 数值数组
* @param idx 索引下标
* @param precision 精确度
*/
function getPercentWithPrecision(valueList, idx, precision) {
if (!valueList[idx]) {
return 0;
}
const sum = valueList.reduce((acc, val) => acc + (isNaN(val) ? 0 : val), 0);
if (sum === 0) {
return 0;
}
const digits = Math.pow(10, precision);
const votesPerQuota = valueList.map(
(val) => ((isNaN(val) ? 0 : val) / sum) * digits * 100
);
const targetSeats = digits * 100;
const seats = votesPerQuota.map((votes) => Math.floor(votes));
let currentSum = seats.reduce((acc, val) => acc + val, 0);
const remainder = votesPerQuota.map((votes, idx) => votes - seats[idx]);
// Has remainding votes.
while (currentSum < targetSeats) {
// Find next largest remainder.
let max = Number.NEGATIVE_INFINITY;
let maxId = null;
for (let i = 0, len = remainder.length; i < len; ++i) {
if (remainder[i] > max) {
max = remainder[i];
maxId = i;
}
}
// Add a vote to max remainder.
++seats[maxId];
remainder[maxId] = 0;
++currentSum;
}
return seats[idx] / digits;
}
1.2 柱状图Option配置
// 模拟数据
const arr = [];
for (let i = 0; i < 20; i++) {
arr.push({
name: `指标值${i + 1}覆盖数`,
value: Math.round(Math.random() * 10000)
});
}
arr.push({
name: '其他标签值覆盖数',
value: Math.round(Math.random() * 10000)
});
// 配置
const option = {
// 标题
title: {
subtext: '更新周期:天',
right: 20
},
// 缩放(滚动条)
dataZoom: {
// brushSelect: false, // 是否开启刷选功能。brush 区域你可以按住鼠标左键后框选出选中部分。
type: 'slider',
height: 20,
start: 0, // 范围开始(总数据的百分比)
end: 35 // 结束位置(总数据的百分比)
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
// 自定义悬浮展示信息
formatter: (params) => {
const item = params[0];
const valueArr = arr.map((i) => i.value);
return `<div style="font-size: 13px;"><div>${item.name}</div><div>${
item.value
}(${this.getPercentWithPrecision(
valueArr,
item.dataIndex,
2
)}%)</div></div>`;
}
},
xAxis: {
data: arr.map((i) => i.name),
// x轴保证刻度线和标签对齐
axisTick: { alignWithLabel: true }
},
yAxis: {},
series: [
{
type: 'bar',
// barWidth: 30,
barMinWidth: 20, // 柱条最小宽度
barMaxWidth: 40, // 柱条最大宽度
data: arr.map((i) => i.value),
itemStyle: {
// 柱条背景渐变色
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: '#4EAAFF' // 0% 处的颜色
},
{
offset: 1,
color: '#2864FE' // 100% 处的颜色
}
],
global: false // 缺省为 false
}
}
}
]
};
2. 饼图
2.1 圆环图-1
2.1.1 分析
需求:
- 饼图展示的数据过多,导致图例多,因此使用滚动图例;
- 并且要求图例要展示值和百分比占比,这里同样需要使用上面提到的百分比-最大余额算法(getPercentWithPrecision);
- 自定义悬浮提示;
示例图:
2.1.2 Option配置
// 模拟数据
const arr2 = [];
for (let i = 0; i < 20; i++) {
arr2.push({
name: `指标值${i + 1}覆盖数`,
value: Math.round(Math.random() * 10000)
});
}
// 饼图数据的值--数组
const valueArr = arr2.map((item) => item.value);
// 配置
const option = {
// 自定义饼图背景色
color: [
'#5470c6',
'#91cc75',
'#fac858',
'#ee6666',
'#73c0de',
'#3ba272',
'#fc8452',
'#9a60b4',
'#ea7ccc'
],
series: [
{
type: 'pie',
radius: ['40%', '70%'], // 环形图范围
labelLine: { show: false }, // 饼图引导线隐藏
label: { show: false }, // 饼图引导线指向的文字隐藏
left: '-40%', // 饼图向左位移(这块自己调试, 因为图例较长,可能会出现图例贴饼图过近)
data: arr2,
emphasis: {
// 饼图某项高亮的样式调整
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
],
legend: {
icon: 'circle', // 图例颜色图标为圆圈
type: 'scroll', // 图例为滚动
orient: 'vertical',
right: 200,
top: 20,
bottom: 20,
// 图例文字样式
textStyle: {
// 富文本样式
rich: {
a: { width: 120 },
b: { width: 65 },
c: { fontWeight: 'bold' }
}
},
// 自定义图例,参数只有name,因此需要算法算出百分比
formatter: (name) => {
const val = arr2.find((item) => item.name === name);
const valIndex = arr2.findIndex((item) => item.name === name);
return [
`{a|${name}}`,
`{b|${this.getPercentWithPrecision(valueArr, valIndex, 2)}%}`,
`{c|${val.value}}`
].join('');
}
},
// 悬浮提示文本
tooltip: {
trigger: 'item',
// 自定义展示文本
formatter: (params) => `<div>
<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>
<span style="font-size:12px;margin-left:2px">${params.name}</span>
<div style="font-size:12px;font-weight:bold;margin-top:7px;margin-left:20px">${params.percent}%(${params.value})</div>
</div>`
}
};
2.2 圆环图-2
2.2.1 分析
需求:
- 初始化默认选中一项,并高亮;
- 饼图背景色为渐变色;
- 选中某项,饼图中间展示选中的模块信息,并且悬浮文字自定义;
- 图例自定义,展示数值
示例图:
2.2.2 Option配置
2.2.2.1 饼图配置
// 模拟数据
const arr = [
{ value: 44, name: '自定义标签' },
{ value: 137, name: '衍生标签' },
{ value: 54, name: '组合标签' }
];
// 配置
const option = {
// 图例
legend: {
bottom: '6',
left: 'center',
icon: 'circle',
itemGap: 30, // 图例间的间距
// 自定义图例的样式--使用富文本
textStyle: {
rich: {
a: { padding: [0, 12, 0, 0] },
b: { fontWeight: 'bold' }
}
},
// 自定义图例
formatter: (name) => {
const value = arr.find((i) => i.name === name).value;
return [`{a|${name}}`, `{b|${value}}`].join('');
}
},
// 悬浮提示信息
tooltip: {
trigger: 'item',
// 自定义悬浮信息
formatter: (params) => `<div>
<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background:linear-gradient(180deg, ${params.color.colorStops[0].color} 0%, ${params.color.colorStops[1].color} 100%);"></span>
<span style="font-size:12px;margin-left:2px">${params.name}</span>
<div style="font-size:12px;font-weight:bold;margin-top:7px;margin-left:20px">${params.value}(${params.percent}%)</div>
</div>`
},
series: [
{
type: 'pie',
radius: ['48%', '70%'],
labelLine: { show: false },
label: {
show: false,
position: 'center' // 显示位置展示在饼图中心
},
data: arr,
itemStyle: {
normal: {
// 渐变色配置
color: (params) => {
const colorMap = {
组合标签: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: '#FFAE34' },
{ offset: 1, color: '#FFD234' }
]
},
衍生标签: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: '#F1672E' },
{ offset: 1, color: '#FC946A' }
]
},
自定义标签: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: '#24F0CB' },
{ offset: 1, color: '#04DEB6' }
]
}
};
return colorMap[params.name];
}
}
},
// 饼图高亮时
emphasis: {
// 饼图样式
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
},
// 文字展示,居中且样式更改
label: {
show: true,
rich: {
a: { fontSize: 22, padding: [10, 2], fontWeight: 'bold' },
b: { fontSize: 12 }
},
formatter: (params) =>
[
`{a|${params.name}}`,
`{b|${params.percent}%(${params.value})}`
].join('\n')
}
}
}
]
};
2.2.2.2 初始化默认选中
// data中定义默认选中哪个
// data() {
// currenthighlightTagNum: '自定义标签'
// }
const myChart = this.echarts.init(this.$refs.xxxxx);
// 使用上面配置的option
myChart.setOption(option);
// 默认高亮某项
myChart.dispatchAction({
type: 'highlight',
name: this.currenthighlightTagNum
});
// 鼠标移入,判断是否是已经选中了的,如果是则取消高亮
myChart.on('mouseover', (e) => {
if (e.name !== this.currenthighlightTagNum) {
myChart.dispatchAction({
type: 'downplay',
name: this.currenthighlightTagNum
});
}
});
//当鼠标离开时,把当前项置为选中
myChart.on('mouseout', (e) => {
// 记录当前高亮
this.currenthighlightTagNum = e.name;
myChart.dispatchAction({ type: 'highlight', name: e.name });
});
3. 堆叠柱状图
3.1 分析
需求:
- 自定义悬浮信息,包含百分比信息;
- 有横向滚动条;
实例图:
3.2 Option配置
// 数据模拟
const arr1 = [];
const arr2 = [];
const arr3 = [];
//根据某年某月计算出具体日期
function getDaysInMonth(year, month) {
const daysOfMonth = [];
month = parseInt(month, 10);
const lastDayOfMonth = new Date(year, month, 0).getDate();
for (let i = 1; i <= lastDayOfMonth; i++) {
if (i < 10) {
daysOfMonth.push(`${year}-${month}-0${i}`);
} else {
daysOfMonth.push(`${year}-${month}-${i}`);
}
arr1.push(Math.round(Math.random() * 3000) + 1000);
arr2.push(Math.round(Math.random() * 1000));
arr3.push(Math.round(Math.random() * 1000) + 500);
}
return daysOfMonth;
}
// 模拟日期
const dateArr = getDaysInMonth(2023, 7);
// 配置
const option = {
// 图例
legend: {
top: 10,
icon: 'circle'
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
// 自定义悬浮信息
formatter: (params) => {
const valueArr = params.map((i) => i.value);
let str = `<div><div>${params[0].name}</div>`;
for (let i = 0; i < params.length; i++) {
const item = params[i];
str += `<div><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${
item.color
};"></span>${
item.seriesName
}</div><div style="margin-left:15px;margin-bottom:4px;">${
item.value
}(${this.getPercentWithPrecision(valueArr, i, 2)}%)</div>`;
}
str += '</div>';
return str;
}
},
// x轴保证刻度线和标签对齐
xAxis: { data: dateArr, axisTick: { alignWithLabel: true } },
yAxis: {},
// 滚动条设置
dataZoom: {
type: 'slider',
// zoomLock: true,
height: 20,
start: 0,
end: 35
},
series: [
{
barMinWidth: 20,
barMaxWidth: 40,
name: '指标一',
data: arr1,
type: 'bar',
itemStyle: { color: '#04DEB6' },
emphasis: { focus: 'series' },
stack: '指标分布' // 堆叠组
},
{
name: '指标二',
data: arr2,
type: 'bar',
itemStyle: { color: '#1890FF' },
emphasis: { focus: 'series' },
stack: '指标分布'
},
{
name: '指标三',
data: arr3,
type: 'bar',
itemStyle: { color: '#F1672E' },
emphasis: { focus: 'series' },
stack: '指标分布'
}
]
};
4. 折线图
4.1 分析
需求:
- 自定义悬浮信息;
- 有横向滚动条;
- 折线面积图(设置渐变背景色)
实例图:
4.2 Option配置
// 模拟数据
const arr = [];
const lastMonth = [];
for (var i = 0; i < 30; i++) {
const date = new Date(new Date().setDate(new Date().getDate() - i));
const month =
date.getMonth() + 1 < 9 ? `0${date.getMonth() + 1}` : date.getMonth() + 1;
const day = date.getDate() < 9 ? `0${date.getDate()}` : date.getDate();
lastMonth.unshift(`${month}-${day}`);
arr.push(Math.round(Math.random() * 40) + 10);
}
// 配置
const option = {
xAxis: {
boundaryGap: false, // 起始点设在Y轴
data: lastMonth
},
yAxis: {},
// 自定义展示悬浮信息
tooltip: {
trigger: 'axis',
formatter: '{a}<br />{b}: {c}个',
axisPointer: {
type: 'line',
label: { backgroundColor: '#6a7985' },
lineStyle: { type: 'dashed' }
}
},
// 横向滚动条
dataZoom: {
type: 'slider',
height: 20,
start: 0,
end: 35
},
series: [
{
name: '已发布标签',
data: arr,
type: 'line',
// 线条颜色设置颜色
lineStyle: {
color: '#13C2C2',
width: 3
},
// 线条中的节点设置颜色
itemStyle: { color: '#13C2C2' },
// 面积背景渐变色
areaStyle: {
color: new this.echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(19,194,194, 0.3)'
},
{
offset: 1,
color: 'rgba(19,194,194,0)'
}
])
}
}
]
};
5. 矩形树图
5.1 分析
需求:
- 默认展示第一级内容,点击可下钻到下一级
- 以面积来表示对应值的多少
示例图:


5.2 Option配置
// 模拟数据
const colorList0 = ['#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'];
const colorList1 = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
const colorList2 = ['#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53', '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42'];
const colorList3 = ['#37A2DA', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'];
const dataArr = [
{
name: '集团',
value: 50,
// color,// 当前节点的下级目录下使用的颜色
children: [
{
name: '统一消费者业务',
value: 30,
// color: colorList1,// 当前节点的下级目录下使用的颜色
children: [
{ name: '统一', value: 10 },
{ name: '消费者', value: 6 },
{
name: '业务',
value: 14,
children: [
{ name: '陈平安', value: 9 },
{ name: '剑来', value: 4 },
{ name: '春风', value: 1 }
]
}
]
},
{
name: '国窖会员',
value: 4
},
{
name: '二级目录1',
value: 4
},
{
name: '二级目录2',
value: 4
},
{
name: '沪系会员',
value: 8
}
]
}
];
// option配置
const option = {
series: [
{
name: '标签类目分布', // 顶层名称
type: 'treemap', // 矩形树图
leafDepth: 1,
roam: true, // 可缩放可位移
top: 25,
breadcrumb: { bottom: 10 }, // 顶部面包屑(层级关系)
itemStyle: { normal: { gapWidth: 5 } }, // 矩形间的间隙宽度
// 直接定义每一层次的颜色使用
levels: [
{ color: colorList0 },
{ color: colorList1 },
{ color: colorList2 },
{ color: colorList3 }
],
data: dataArr
}
]
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步