实战篇:(七)Vue2项目中使用 echarts(5.2.2)图表组件含代码

1.图表预览

2.注释说明

Vue 的组件开发

  • 通过 props 定义外部传入的属性,例如 classNamewidthheightautoResizechartData 等。
  • 使用 Vue 的生命周期钩子函数 mounted 进行 ECharts 的实例化,确保组件加载完毕后才初始化图表。
  • 通过 watch 监听 chartData 数据的变化,自动更新图表。

ECharts 实例化和配置

  • 使用 echarts.init(this.$el) 创建图表实例,绑定到 Vue 组件的 DOM 元素上。
  • this.chart.setOption(option, true) 更新 ECharts 图表的配置。
  • 定义了自适应窗口大小的功能,监听 window.onresize,动态调整图表大小。

计算方法和自定义配置

  • fontSize(res) 根据窗口宽度动态计算字体大小,用于图表的响应式布局。
  • getPie3D(pieData, internalDiameterRatio)getParametricEquation() 是生成 3D 饼图的关键函数,使用数学公式构建 3D 饼图的曲面方程,并自定义了饼图的大小、半径、角度、选中效果等。
  • formatter 函数用于自定义图表的 legendtooltip 显示格式,返回带有富文本样式的字符串。

3.页面引入

<div class="com-view-body c-dis-flex-col c-hidden">
    <div class="c-width c-flex c-dis-flex-col c-hidden">
       <ChartView :chart-data="riskChartData"></ChartView>
    </div>
</div>

import { randomNum } from '@/utils/index.js'
import ChartView from '@/components/Charts/ChartView.vue'


 riskChartData: {
        name: "风险总数",
        color: ["#ED6F81", "#F3843D", "#4B64F7", "#34C294"],
        legend: ['二级风险', '三级风险', '四级风险', '五级风险'],
        data: [
          { name: "二级风险", value: 0, unit: "个" },
          { name: "三级风险", value: 0, unit: "个" },
          { name: "四级风险", value: 0, unit: "个" },
          { name: "五级风险", value: 0, unit: "个" },
        ],
},

4.图表组件 

<template>
  <div :class="className" :style="{ height: height, width: width }" />
</template>

<script>
import * as echarts from 'echarts'; // 导入 echarts 库
import "echarts-gl"; // 导入 echarts 的 3D 图表支持
import resize from '@/components/mixin/resize'; // 导入窗口 resize 相关的 mixin

export default {
  mixins: [resize], // 引入 mixin
  props: {
    className: {
      type: String,
      default: 'chart', // 默认样式名为 'chart'
    },
    width: {
      type: String,
      default: '100%', // 默认宽度为 100%
    },
    height: {
      type: String,
      default: '100%', // 默认高度为 100%
    },
    autoResize: {
      type: Boolean,
      default: true, // 默认启用自动调整大小
    },
    chartData: {
      type: Object,
      default: () => { } // 默认空对象,存储图表数据
    }
  },
  data() {
    return {
      chart: null, // 存储 echart 实例
      chartColor: {
        text: '#ffffff', // 文字颜色
        bg: '#02456b', // 背景色
        color: ['#06DEF3', '#1779CE', '#FAD961', '#F76B1C'], // 数据颜色
      },
      hoveredIndex: '', // 记录鼠标悬浮的索引
      option: null // 存储图表配置
    }
  },
  mounted() {
    // DOM 渲染后初始化图表
    this.$nextTick(() => {
      this.chart = echarts.init(this.$el); // 初始化 echart 实例
      this.initChart(); // 调用初始化方法
    });
  },
  watch: {
    chartData: {
      deep: true, // 深度监听 chartData
      handler(val) {
        this.initChart(); // 当 chartData 发生变化时,重新初始化图表
      },
    },
  },
  methods: {
    /**
     * 根据屏幕大小调整字体大小
     * @param {Number} res 原始字体大小
     * @return {Number} 调整后的字体大小
     */
    fontSize(res) {
      let clientWidth =
        window.innerWidth ||
        document.documentElement.clientWidth ||
        document.body.clientWidth;
      if (!clientWidth) return;
      let fontSize = clientWidth / 1920; // 按 1920 设计稿宽度计算比例
      return res * fontSize;
    },

    /**
     * 初始化图表,设置图表配置项
     */
    initChart() {
      let that = this;
      const series = this.getPie3D(this.chartData.data, 0.85); // 生成3D饼图的系列
      series.push({
        name: "pie2d", // 2D饼图,用于3D饼图视觉对齐
        type: "pie",
        labelLine: { length: 0, length2: 0 },
        startAngle: 2, // 起始角度
        clockwise: false, // 逆时针旋转
        radius: ["0%", "0%"], // 饼图半径
        center: ["0%", "0%"], // 饼图中心位置
        data: this.chartData.data,
        itemStyle: { opacity: 0 } // 设置透明度
      });

      let rich = { name: { fontSize: this.fontSize(12), color: "#fff" } };
      // 动态生成 rich 配置,用于自定义图例文本样式
      for (let i = 0; i < 7; i++) {
        rich[`name${i}`] = {
          fontSize: this.fontSize(i === 1 ? 16 : 20),
          align: 'left',
          padding: [0, 0, 0, this.fontSize(10)],
          fontWeight: i === 1 ? 900 : 600,
          color: i !== 0 ? this.chartData.color[i - 2] : 'rgba(130, 159, 179, 1)'
        };
      }

      // 动态为每个数据项添加样式
      this.chartData.data.map((item, index) => {
        let style = {
          fontSize: this.fontSize(16),
          padding: [0, 5, 0, 5],
          color: this.chartData.color[index],
        };
        this.$set(rich, `value${index}`, style);
      });

      // 定义图表配置项
      let option = {
        color: this.chartData.color,
        legend: {
          show: true,
          orient: 'vertical',
          right: '5%',
          top: 'center',
          itemWidth: this.fontSize(16),
          itemHeight: this.fontSize(4),
          textStyle: {
            fontWeight: 400,
            color: '#CEE8F8',
            fontSize: this.fontSize(14),
            lineHeight: this.fontSize(26),
            rich: rich,
          },
          formatter: function (name) {
            let res = that.chartData.data.find(v => v.name === name);
            return `{name1|${res.name}}{name${that.chartData.data.indexOf(res) + 2}|${res.value}}{name0|${res.unit}}`;
          },
        },
        tooltip: {
          formatter: function (optionsData) {
            let value = that.chartData.data.find(v => v.name === optionsData.seriesName)?.value || 0;
            return `${optionsData.seriesName}: ${value}`;
          },
          borderColor: this.chartColor.bg,
          backgroundColor: this.chartColor.bg,
          textStyle: {
            color: '#fff',
            fontSize: this.fontSize(12),
            rich: rich
          },
        },
        title: {
          text: that.chartData.name,
          textAlign: 'center',
          left: '30%',
          top: '43%',
          textStyle: { color: "#fff", fontSize: this.fontSize(14) },
        },
        series: series,
      };

      this.chart.setOption(option, true); // 设置图表配置项
      this.chart.resize(); // 图表自适应
      window.onresize = () => this.chart.resize(); // 监听窗口大小变化
    },

    /**
     * 生成扇形的参数方程
     * @param {Number} startRatio 扇形起始比例
     * @param {Number} endRatio 扇形结束比例
     * @param {Boolean} isSelected 是否选中
     * @param {Boolean} isHovered 是否悬浮
     * @param {Number} k 辅助参数
     * @param {Number} height 扇形高度
     * @param {Number} i 当前序号
     * @return {Object} 曲面参数方程
     */
    getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, height, i) {
      // 曲面参数方程的实现,计算每个扇形的坐标和大小
      // ...
    },

    /**
     * 生成模拟 3D 饼图的配置项
     * @param {Array} pieData 饼图数据
     * @param {Number} internalDiameterRatio 内环直径比
     * @return {Array} 图表 series 配置项
     */
    getPie3D(pieData, internalDiameterRatio) {
      let series = [];
      let sumValue = pieData.reduce((sum, data) => sum + data.value, 0); // 计算总值
      let startValue = 0;

      pieData.forEach((data, i) => {
        let endValue = startValue + data.value;
        let seriesItem = {
          name: data.name || `series${i}`,
          type: "surface",
          parametric: true,
          pieData: data,
          pieStatus: { selected: false, hovered: false, k: (1 - internalDiameterRatio) / (1 + internalDiameterRatio) }
        };
        seriesItem.parametricEquation = this.getParametricEquation(
          startValue / sumValue,
          endValue / sumValue,
          false,
          false,
          seriesItem.pieStatus.k,
          10,
          i
        );
        startValue = endValue;
        series.push(seriesItem);
      });

      return series;
    },
  },
}
</script>

上一篇:

实战篇:(六)创建属于自己的 Vue 3 组件库:主题切换与样式管理

下一篇:
实战篇:(八)Vue2项目中使用 echarts(5.2.2)图表组件含代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈探索者chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值