<template>
<div ref="barChartRef" class="bar-container" :style="{ height: height }"></div>
</template>
<script setup lang="ts">
import * as echarts from "echarts";
import { ref, onMounted, nextTick, markRaw, watch } from "vue";
const props = defineProps({
xData: {
type: Array,
default: () => [],
},
yData: {
type: Array,
default: () => [],
},
height: {
type: String,
default: "420px",
},
chartGrid: {
type: Object,
default: () => ({
top: "20px",
left: "80px",
right: "36px",
}),
},
});
const barChartRef = ref();
const myChart = ref();
const colorList: string[] = [
"#081C70",
"#0E2987",
"#163CA7",
"#1E51C8",
"#2A6AE9",
"#5C95F1",
"#7DAFF8",
"#A9CEFC",
"#bed5f1",
"#d2ddeb",
"#879bb5",
"#768291",
"#797d83",
];
onMounted(() => {
nextTick(() => {
initChart();
});
});
// 监听 props.xData 变化
watch(
() => props.xData,
(newVal) => {
if (myChart.value) {
// 销毁原来的图重新创建
myChart.value.dispose();
initChart();
}
},
{ deep: true }
);
const getSeriesData = () => {
let seriesTempArr: any = [];
props.yData.forEach((v: any, i) => {
const key = Object.keys(v)[0]; // 获取键名
const values = v[key]; // 获取值
seriesTempArr.push({
name: key,
type: "bar",
stack: "total",
barWidth: "37px",
data: values,
itemStyle: {
borderColor: colorList[i],
color: colorList[i],
borderRadius: i === props.yData.length - 1 ? [8, 8, 0, 0] : [0, 0, 0, 0],
},
});
});
let totalArr = sumArraysByPosition(props.yData); //求和
seriesTempArr.push({
name: "总和",
type: "bar",
stack: "sum",
barWidth: "37px",
data: totalArr,
barGap: "-100%",
itemStyle: {
color: "transparent",
},
label: {
show: true,
position: "top",
},
});
return seriesTempArr;
};
const initChart = () => {
const seriesData = getSeriesData();
const lengendData = seriesData.map((v: any) => v.name).slice(0, -1);
myChart.value = markRaw(echarts.init(barChartRef.value));
let option = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
formatter: function (params: any) {
// 自定义内容(左对齐)
let result = '<div style="text-align: left;">';
params.forEach((item: any) => {
if (item.seriesName === "总和") return;
result += `${item.marker} ${item.seriesName}: ${item.value}<br/>`;
});
result += "</div>";
return result;
},
},
legend: {
itemWidth: 8,
itemHeight: 8,
itemGap: 20,
bottom: 0,
data: lengendData,
textStyle: {
color: "#303133",
},
selectedMode: false, //取消图例上的点击事件
},
grid: props.chartGrid,
dataZoom: [
{
type: "inside",
start: 0,
end: 100,
},
],
xAxis: {
type: "category",
data: props.xData,
axisLine: {
lineStyle: {
color: "#7e7d8a",
width: 1,
},
},
axisTick: {
show: false,
},
axisLabel: {
show: true,
textStyle: {
fontSize: 12,
color: "#303133",
},
},
},
yAxis: {
type: "value",
name: "",
nameTextStyle: {
color: "#fff",
fontSize: 20,
align: "right",
},
nameGap: 20,
axisLine: {
show: false,
},
axisTick: {
show: false,
},
splitLine: {
show: true,
lineStyle: {
type: "dashed",
color: "#d9d9dd",
width: 1,
},
},
axisLabel: {
show: true,
textStyle: {
fontSize: 12,
color: "#303133",
},
},
},
series: seriesData,
};
option && myChart.value.setOption(option);
window.addEventListener("resize", function () {
myChart.value.resize();
});
};
// 按年份统计各品类和
const sumArraysByPosition = (arr: any) => {
// 检查输入是否为空
if (!arr || arr.length === 0) return [];
// 提取所有数组并计算总和
let newArr = arr
.map((obj: any) => Object.values(obj)[0]) // 获取每个对象的值数组
.reduce(
(sumArray: any, currentArray: any) =>
sumArray.map((num: any, index: any) => num + (currentArray[index] || 0)), // 对应位置相加
new Array(arr[0][Object.keys(arr[0])[0]].length).fill(0) // 初始化求和数组
);
return newArr;
};
</script>
<style lang="less" scoped>
.bar-container {
padding-top: 20px;
}
</style>
效果图
这世界很喧嚣,做你自己就好