封装echarts组件,更方便使用

文章介绍了如何在Vue项目中创建一个可复用的ChartCard.vue组件,用于初始化Echarts图表,处理画布大小调整,以及如何通过公共配置文件和单独的pie.ts文件来配置和渲染环形图,包括响应式调整和数据绑定。
摘要由CSDN通过智能技术生成

1.定义一个ChartCard.vue文件用来渲染echarts,主要是做echarts的初始化,定义画布大小,移动浏览器窗口大小要重新渲染等这些功能,方便后面直接使用这个组件

<template>
  <div class="chart">
    <div ref="main" :style="_getClsStyle"></div>
    <slot></slot>
  </div>
</template>

<script setup lang="ts">
import { ECharts, init } from "echarts";
import debounce from "lodash-es/debounce";
import {
  ref,
  Ref,
  reactive,
  computed,
  onMounted,
  onBeforeUnmount,
  watch,
  shallowRef,
  nextTick,
  defineExpose,
} from "vue";

const DEFAULT_THEME = reactive({
  categoryAxis: {
    axisLine: { show: false },
    axisTick: { show: false },
    splitLine: { show: false },
  },
  valueAxis: {
    axisLine: { show: false },
  },
  tooltip: {
    borderColor: "#ffffff",
  },
  line: {
    smooth: true,
  },
  grid: {
    containLabel: true,
    left: 10,
    right: 10,
  },
});
const RESIZE_DELAY = ref(200);
const props = withDefaults(
  defineProps<{
    width: string;
    height: string;
    columns: number;
  }>(),
  {
    width: "auto",
    height: "400px",
    columns: 1,
  }
);
const bindResize = ref(false);
const _getClsStyle = computed(() => {
  return { height: props.height };
});

let main: Ref<HTMLElement | any> = ref();
let instance = shallowRef<ECharts | any>(null); // 必须使用shallowRef,不然resize会报错!

const getInstance = () => {
  if (!instance.value) {
    instance.value = init(main.value, DEFAULT_THEME);
  }
  return instance.value;
};
const resize = () => {
  instance.value && instance.value.resize();
};
const resizeHandler = debounce(resize, RESIZE_DELAY.value);

const addResizeListener = () => {
  if (bindResize.value) return;
  window.addEventListener("resize", resizeHandler);
  bindResize.value = true;
};
const removeResizeListener = () => {
  window.removeEventListener("resize", resizeHandler);
  bindResize.value = false;
};
const initChart = () => {
  getInstance();
  addResizeListener();
};

onMounted(() => {
  initChart();
});

const clean = () => {
  if (bindResize.value) removeResizeListener();
  instance.value && instance.value.dispose();
};

// 暴露出去,用于外部使用配置项和控制渲染
const setOption = function () {
  instance.value && instance.value.setOption(...arguments);
};

const nextTickResize = () => {
  nextTick(resize);
};

watch([props.width, props.height, props.columns], nextTickResize);

defineExpose({ setOption, instance });
onBeforeUnmount(() => {
  clean();
});
</script>

<style lang="scss" scoped>
.chart {
  width: 100%;
  height: 100%;
  position: relative;
}
</style>

2.可以定义一个公共配置属性文件chart.ts

export const chartConfig = {
  render: function (instance: any, options: any) {
    instance && instance.setOption(options, true);
    return instance;
  },

  scaleSize: function (level: number, size: number) {
    if (!size) {
      const el = document.querySelector(".chart div");
      if (el) {
        size = el.clientHeight;
      } else {
        return level;
      }
    }
    const baseSize = 400;
    const minSize = 10;
    const num = level * (size / baseSize);
    const result = num % 2 === 0 ? num : num + 1;
    return result < minSize ? minSize : result;
  },

  formatDataZoom: function (data: Array<any>, count: number) {
    const dataZoom = [
      {
        filterMode: "empty", // 设置filterMode: 'empty',防止Y轴数值变化弄丢markline标线
        bottom: 0,
        type: "slider",
        height: "9px",
        show: true,
        zoomLock: true, // 锁上滚动条拉伸功能
        start: 0,
        end: 50,
        backgroundColor: "#FFFFFF", // 滚动槽背景颜色
        borderColor: "#FFFFFF", // 滚动槽边框颜色
        // 滚动条把手样式
        handleStyle: {
          color: "rgba(0,0,0,0)",
        },
        // 滚动条激活标签样式
        textStyle: {
          color: "rgba(0,0,0,0)",
          height: "10px",
        },
        fillerColor: "#EEEEEE", // 滚动条颜色
        dataBackground: {
          // 滚动槽背景填充阴影
          areaStyle: {
            color: "rgba(0,0,0,0)",
          },
          // 滚动槽背景填充线条
          lineStyle: {
            color: "rgba(0,0,0,0)",
          },
        },
      },
    ];
    if (!count) count = 15;
    if (data.length > count) {
      dataZoom[0].show = true;
      //   dataZoom[0].end = (100 / data.length).toFixed(2) * count;
    } else {
      dataZoom[0].show = false;
      dataZoom[0].end = 100;
    }
    return dataZoom;
  },

  formatTooltip: function (newTooltip?: any) {
    const tooltip = {
      trigger: "axis",
      axisPointer: {
        type: "line",
      },
      borderWidth: 0,
      backgroundColor: "rgba(111,111,111,.8)",
      textStyle: {
        color: "#fff",
      },
    };
    return Object.assign({}, tooltip, newTooltip);
  },

  eventXAxis: function (echarts: any, xAxisTip: any) {
    if (!echarts || !xAxisTip) return;
    if (echarts._xAxisMouse) return;
    echarts._xAxisMouse = true;
    echarts.on("mouseover", (params: any) => {
      if (params.componentType === "xAxis") {
        const offsetX = params.event.event.offsetX;
        const offsetY = params.event.event.offsetY;
        xAxisTip.innerText = params.value;
        xAxisTip.style.left = offsetX + "px";
        xAxisTip.style.top = offsetY + 10 + "px";
        xAxisTip.style.display = "block";
      }
    });
    echarts.on("mouseout", () => {
      xAxisTip.style.display = "none";
    });
  },
};

3.单独给某个echarts图配置属性,下面是我想做的环形图配置,定义为pie.ts,与下面那个vue文件搭配,你要做其他什么图,上面两个文件的内容都不需要做什么变化,主要就是单独创建这个文件并写配置和下面vue文件传入对应数据就行了

import { chartConfig } from "@/utils"; // 上面的那个公共配置文件
export default Object.assign({}, chartConfig, {
  getOptions: function (options: any) {
    const { data, color } = options;
    // const tooltip = chartConfig.formatTooltip();
    // const dataZoom = chartConfig.formatDataZoom(labels)
    const grid = {
      left: "1%",
      right: "4%",
      bottom: "8%",
      containLabel: true,
    };
    const series = [
      {
        name: "Access From",
        type: "pie",
        radius: ["50%", "70%"],
        avoidLabelOverlap: false,
        itemStyle: {
          borderRadius: 2,
          borderColor: "#fff",
          borderWidth: 2,
        },
        label: {
          show: false,
          position: "center",
        },
        emphasis: {
          label: {
            show: true,
            fontSize: 40,
            fontWeight: "bold",
          },
        },
        labelLine: {
          show: false,
        },
        data,
      },
    ];
    return { color, grid, series };
  },
});

4.最后一步,就是要实现的环形图,将要用到的数据传给pie.ts就行了

<template>
  <div>
    <chart-card ref="chart" :height="chartHeight">
      <div ref="xAxisTip" class="xAxisTip"></div>
    </chart-card>
  </div>
</template>
<script setup lang="ts">
import ChartCard from "../ChartCard.vue";
import pie from "./pie";
import { ref, nextTick, computed, watch, onMounted } from "vue";
const props = withDefaults(
  defineProps<{
    chartHeight: string;
    data: [];
    color: [];
  }>(),
  {
    chartHeight: "150px",
  }
);
const chart = ref();
onMounted(() => {
  renderChart();
});

const dealChartData = computed(() => {
  return {
    data: props.data,
    color: props.color,
  };
});
const renderChart = async () => {
  await nextTick();
  pie.render(chart.value, pie.getOptions(dealChartData.value));
};
watch(() => props.data, renderChart);
</script>
<style lang="scss" scoped></style>

  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值