echarts柱状图组件

<script setup>
import {
  ref, onMounted, onUnmounted, nextTick, watch, computed,
} from 'vue';
// eslint-disable-next-line import/no-extraneous-dependencies
import * as echarts from 'echarts';
import dayjs from 'dayjs';
import './flexible.js';
import enums from '@/utils/enums.js';

const props = defineProps({
  x: { // 是否使用月作为X坐标系
    type: Boolean,
    default: false,
  },
  unit: {
    type: String,
    default: '次',
  },
  name: {
    type: String,
    default: '',
  },
  data: {
    type: Array,
    default: () => [],
  },
  overlayData: {
    type: Array,
    default: () => [],
  },
  average: {
    type: Number,
    default: 0,
  },
  max: {
    type: Number,
    default: 0,
  },
  isSop: {
    type: Boolean,
    default: false,
  },
});

const chartDom = ref(null);
const chartInstance = ref(null);
function getDaysInCurrentMonth() {
  const firstDayOfMonth = dayjs().startOf('month');
  const daysInMonth = firstDayOfMonth.daysInMonth();
  const days = [];
  for (let i = 1; i <= daysInMonth; i++) {
    days.push(i);
  }
  return days;
}

const daysInCurrentMonth = getDaysInCurrentMonth();
const yearMonth = `${dayjs().year()}/${dayjs().month() + 1}/`;
const weekList = ['一', '二', '三', '四', '五', '六', '日'];
const dataOverlayData = computed(() => props.overlayData);
async function initPage() {
  await nextTick(); // 确保DOM已经渲染完成
  if (chartInstance.value) {
    chartInstance.value.dispose();
  }
  chartInstance.value = echarts.init(chartDom.value);
  const tooltip = {
    formatter: params => `<div style="display: flex;align-items: center;gap: 10px;">
            <div>${props.x ? yearMonth : '星期'}${params.name}</div>
            <div>${params.data}${props.unit}</div>
        </div>`,
  };
  const option = {
    // 这里是ECharts的配置项,可以根据需要绘制不同类型的图表
    grid: {
      top: '10', // 距离容器上边界的距离
      right: '  0', // 距离容器右边界的距离
      bottom: '0', // 距离容器下边界的距离
      left: '0', // 距离容器左边界的距离
      containLabel: true, // 包含标签的绘图区域
    },
    tooltip: props.isSop ? tooltip : {
      formatter: params => `
  <div>
    <div>${params.seriesName}</div>
    <div style="display: flex;align-items: center;gap: 10px;">
        <div style="width: 10px;height: 10px;border-radius:50%;background-color: ${params.color}"></div>
        <div style="display: flex;align-items: center;gap: 10px;">
            <div>${props.x ? yearMonth : '星期'}${params.name}</div>
            <div>${params.data}${props.unit}</div>
        </div>
    </div>
  </div>`,
    },
    xAxis: {
      type: 'category',
      data: props.x ? daysInCurrentMonth : weekList,
      axisTick: {
        alignWithLabel: true,
        show: false, // 不显示刻度线
      },
      axisLine: {
        show: false, // 不显示横坐标轴线
      },
      splitLine: {
        show: true,
        lineStyle: {
          type: 'dashed',
          color: '#F1F1F1',
        },
      },
      axisLabel: {
        formatter(value) {
          return value;
        },
      },
    },
    yAxis: {
      type: 'value',
      position: 'right',
      boundaryGap: [0, 0.01],
      axisTick: {
        alignWithLabel: true,
      },
      axisLabel: {
        // show: false,
        formatter: `{value}${props.unit}`,
      },
      // min: 0,
      // max: props.max,
    },
    series: [
      {
        name: props.name,
        data: props.data,
        type: 'bar',
        stack: 'total', // 添加堆积效果
        barWidth: '50%', // 调整柱子宽度
        itemStyle: {
          borderRadius: [0, 0, 0, 0], // 只有顶部圆角
          color: enums.COLOR_LIST[0], // 设置柱子颜色、枚举数组
        },
      },
      ...dataOverlayData.value,
      {
        name: '平均线',
        type: 'line',
        showSymbol: false,
        smooth: true,
        markLine: {
          silent: true,
          symbol: ['none', 'none'], // 去掉箭头
          data: [
            {
              type: 'average',
              name: '平均值',
              lineStyle: {
                color: '#00B42A', // 线条颜色
                type: 'dashed', // 线条类型,可选 'solid', 'dashed', 'dotted'
                width: 2, // 线条宽度
              },
              label: {
                show: true, // 显示标签
                position: 'end', // 标签位置
                formatter: '平均', // 标签格式
                color: '#00B42A', // 线条颜色
              },
            },
          ],
        },
        yAxisIndex: 0,
        xAxisIndex: 0,
        data: [
          props.average,
        ],
        stack: '总量', // 注意:虽然 line 类型不支持 stack,但这里设置是为了逻辑清晰
      },
    ],
  };
  chartInstance.value.setOption(option);
}
const X = computed(() => props.x);
watch(X, value => {
  // initPage();
});
// 初始化ECharts实例并设置配置项(这里以折线图为例,但可灵活替换)
onMounted(async () => {
  // await initPage();
});

// 销毁ECharts实例
onUnmounted(() => {
  window.removeEventListener('resize', () => {
    if (chartInstance.value) {
      chartInstance.value.resize();
    }
  });
  if (chartInstance.value != null && chartInstance.value.dispose) {
    chartInstance.value.dispose();
  }
});
window.addEventListener('resize', () => {
  if (chartInstance.value) {
    // chartInstance.value.resize();
    initPage();
  }
});

defineExpose({
  initPage,
});
</script>

<template>
  <div ref="chartDom" style="width: 25.1875rem; height: 17.0625rem;"></div>
</template>

<style scoped lang="less">

</style>

在父组件中使用:

<DataVisualization
              ref="DataVisualizationRef"
              :name="props.data.name"
              :x="props.data.x"
              :data="props.data.data"
              :unit="props.data.unit"
              :average="props.data.average"
              :overlay-data="props.data.overlayData"
              :max="props.data.max"
              :isSop="props.isSop"
            />

 

效果图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值