echarts堆叠柱状图

<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>

效果图

这世界很喧嚣,做你自己就好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值