vue3 + echarts 实现横向柱形图

<template>
  <div ref="barChart" :style="{ width: '100%', height: height + 'px' }"></div>
</template>

<script lang="ts">
  import { defineComponent, ref, onMounted, onUnmounted, watch, PropType } from 'vue';
  import * as echarts from 'echarts';

  export default defineComponent({
    name: 'HorizontalBarChart',
    props: {
      data: {
        type: Array as PropType<{ name: string; value: number }[]>,
        required: true,
      },
      height: {
        type: Number,
        default: 300,
      },
      // 可自定义柱形颜色
      barColor: {
        type: String,
        default: '#409EFF',
      },
      // 可自定义X轴分割线颜色
      xSplitLineColor: {
        type: String,
        default: '#F0F2F5',
      },
    },
    setup(props) {
      const barChart = ref<HTMLDivElement | null>(null);
      let chartInstance: echarts.ECharts | null = null;

      const initChart = () => {
        if (barChart.value && !chartInstance) {
          chartInstance = echarts.init(barChart.value);
        }

        if (chartInstance) {
          const option = {
            // 悬浮提示框配置
            tooltip: {
              trigger: 'item',
              backgroundColor: 'rgba(255, 255, 255, 0.9)',
              borderColor: '#EEEEEE',
              borderWidth: 1,
              padding: 10,
              textStyle: {
                color: '#333333',
                fontSize: 14,
              },
              formatter: function (params: any) {
                return `
                  <div style="font-weight: 500;">${params.name}</div>
                  <div>数据:${params.value}</div>
                `;
              },
              position: function (point: number[], params: any, dom: any, rect: any, size: any) {
                let x = point[0];
                let y = point[1];
                const viewWidth = size.viewSize[0];
                const viewHeight = size.viewSize[1];
                const domWidth = dom.offsetWidth;
                const domHeight = dom.offsetHeight;

                if (x + domWidth > viewWidth) {
                  x = x - domWidth - 10;
                }
                if (y + domHeight > viewHeight) {
                  y = y - domHeight - 10;
                }
                return [x, y];
              },
            },
            grid: {
              left: '1%',
              right: '4%',
              bottom: '2%',
              top: '10%',
              containLabel: true,
            },
            xAxis: {
              type: 'value',
              // 添加X轴分割线(横向分割线)
              splitLine: {
                show: true,
                lineStyle: {
                  color: props.xSplitLineColor,
                  width: 1,
                  type: 'solid', // 实线分割
                },
              },
              axisLabel: {
                formatter: '{value}',
                margin: 15,
              },
            },
            yAxis: {
              type: 'category',
              data: props.data.map((item) => item.name),
              inverse: true,
              axisLine: {
                show: false,
              },
              axisTick: {
                show: false,
              },
              textStyle: {
                fontSize: 12,
                color: '#606266',
              },
              // 去掉Y轴分割线
              splitLine: {
                show: false,
              },
              axisLabel: {
                margin: 15,
              },
            },
            series: [
              {
                type: 'bar',
                data: props.data.map((item) => item.value),
                itemStyle: {
                  color: props.barColor,
                  borderRadius: [0, 4, 4, 0],
                },
                barWidth: 15,
                emphasis: {
                  itemStyle: {
                    color: `${props.barColor}CC`,
                  },
                },
              },
              {
                type: 'bar',
                data: props.data.map((item) => item.value),
                barWidth: 0,
                label: {
                  show: true,
                  position: 'right',
                  formatter: '{c}',
                  color: '#606266',
                  fontSize: 12,
                  distance: 5,
                },
              },
            ],
          };
          chartInstance.setOption(option);
        }
      };

      const handleResize = () => {
        if (chartInstance) {
          chartInstance.resize();
        }
      };

      onMounted(() => {
        setTimeout(initChart, 0);
        window.addEventListener('resize', handleResize);
      });

      onUnmounted(() => {
        window.removeEventListener('resize', handleResize);
        if (chartInstance) {
          chartInstance.dispose();
          chartInstance = null;
        }
      });

      watch(
        () => props.data,
        () => {
          initChart();
        },
        { deep: true },
      );

      watch(
        () => [props.barColor, props.xSplitLineColor, props.height],
        () => {
          initChart();
        },
      );

      return {
        barChart,
      };
    },
  });
</script>

页面引入

<HorizontalBar :data="chartData" :height="260"  />

import HorizontalBar from '@/components/Echatrs/HorizontalBar.vue';

  const chartData = ref([
    { name: '企业名E', value: 180 },
    { name: '企业名D', value: 70 },
    { name: '企业名C', value: 230 },
    { name: '企业名B', value: 170 },
    { name: '企业名A', value: 195 },
  ]);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值