Skip to content

vue3 echarts 波浪球进度条例子

一效果演示

0.35

二、安装 echarts echarts-liquidfill

bash
npm install echarts echarts-liquidfill -S

三、Vue3 组件代码

WaveProgress.vue

查看 WaveProgress.vue 源码
vue
<template>
  <div class="chart-wrap">
    <div ref="chartRef" class="chart-container"></div>
  </div>
</template>
<script setup>
// 引入 Vue 的 ref、onMounted、onBeforeUnmount、watch 函数,用于响应式数据、组件挂载、卸载生命周期及侦听属性变化
import { ref, onMounted, onBeforeUnmount, watch } from "vue";

// 定义从父组件传入的属性 value,默认为 0,取值范围0-1
const props = defineProps({
  value: { type: Number, default: 0 },
});

// 按需引入 ECharts 的核心模块以及所需的渲染器和组件
import * as echarts from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { TooltipComponent } from "echarts/components";

// 注册 ECharts 组件
echarts.use([CanvasRenderer, TooltipComponent]);

// 引入水球图插件(liquidfill)
import "echarts-liquidfill";

// 使用 ref 引用 DOM 元素,用于渲染图表
const chartRef = ref(null);

// 存储 ECharts 实例和 ResizeObserver 实例
let myChart = null;
let resizeObserver = null;

/**
 * 封装获取 ECharts 配置项的函数
 * @param {Number} value 图表要展示的值(0-1之间)
 * @returns {Object} ECharts 配置对象
 */
function getOption(value) {
  return {
    backgroundColor: "#fff", // 图表背景色
    series: [
      {
        type: "liquidFill", // 使用水球图
        radius: "100%", // 水球图的半径
        center: ["50%", "50%"], // 图表中心位置
        data: [value], // 显示的数值(即水位)
        color: ["#3399FF"], // 水球的颜色
        outline: {
          show: false, // 不显示轮廓外线
        },
        itemStyle: {
          opacity: 1, // 水球不透明度为1
          shadowBlur: 0, // 无阴影模糊
          shadowColor: "transparent", // 无阴影颜色
        },
        backgroundStyle: {
          color: "#ffffff", // 水球底色为白色
          shadowBlur: 0,
          shadowColor: "transparent",
        },
        label: {
          // 使用富文本显示标题和数值
          formatter: `{title|磁盘空间剩余}\n{value|${
            (value * 100).toFixed(0) + "%"
          }}`,
          rich: {
            title: {
              fontSize: 14,
              color: "#7b7b7b",
            },
            value: {
              fontSize: 24,
              color: "#000",
              padding: [14, 0, 0, 0],
            },
          },
        },
        amplitude: 10, // 波浪振幅
        waveLength: "80%", // 波长
        phase: 0, // 波的初相位
        period: 2000, // 波的动画周期(毫秒)
      },
    ],
  };
}

// 组件挂载后初始化图表和监听器
onMounted(() => {
  // 初始化 ECharts 实例
  myChart = echarts.init(chartRef.value);
  // 设置初始图表数据
  myChart.setOption(getOption(props.value));

  // 创建 ResizeObserver,当容器大小变化时自动调整图表
  resizeObserver = new ResizeObserver(() => {
    myChart && myChart.resize();
  });
  // 开始观察引用的 DOM 元素大小变化
  resizeObserver.observe(chartRef.value);
});

// 组件卸载前清理资源
onBeforeUnmount(() => {
  // 停止观察
  if (resizeObserver) {
    resizeObserver.disconnect();
  }
  // 销毁图表实例,释放资源
  if (myChart) {
    myChart.dispose();
    myChart = null;
  }
});

// 监听传入的 value 值的变化,一旦变化即更新图表数据
watch(
  () => props.value,
  (newVal) => {
    if (myChart) {
      // 当 value 改变时,重新设置图表选项
      myChart.setOption(getOption(newVal));
    }
  }
);
</script>

<style scoped lang="scss">
.chart-wrap {
  display: inline-flex;
  border: 2px solid #3399ff;
  border-radius: 50%;
  padding: 2px;
  box-sizing: border-box;
}
.chart-container {
  width: var(--chart-size, 200px);
  height: var(--chart-size, 200px);
  border-radius: 50%;

  overflow: hidden;
  cursor: default;
}
</style>

服务端渲染,ssr 或者 ssg 可能会出现下面错误

✓ building client + server bundles...
⠸ rendering pages...ReferenceError: self is not defined
    at Object.<anonymous> (D:\project\vite-docs\node_modules\echarts-liquidfill\dist\echarts-liquidfill.js:10:4)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:169:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25)
✖ rendering pages...
build error:
self is not defined
ReferenceError: self is not defined
    at Object.<anonymous> (D:\project\vite-docs\node_modules\echarts-liquidfill\dist\echarts-liquidfill.js:10:4)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:169:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25)
PS D:\project\vite-docs>

解决办法,改为动态引入 import('echarts-liquidfill')

查看修改后的 WaveProgress.vue 源码
vue
<template>
  <div class="chart-wrap">
    <div ref="chartRef" class="chart-container"></div>
  </div>
</template>
<script setup>
// 引入 Vue 的 ref、onMounted、onBeforeUnmount、watch 函数,用于响应式数据、组件挂载、卸载生命周期及侦听属性变化
import { ref, onMounted, onBeforeUnmount, watch } from "vue";

// 定义从父组件传入的属性 value,默认为 0,取值范围0-1
const props = defineProps({
  value: { type: Number, default: 0 },
});

// 按需引入 ECharts 的核心模块以及所需的渲染器和组件
import * as echarts from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { TooltipComponent } from "echarts/components";

// 注册 ECharts 组件
echarts.use([CanvasRenderer, TooltipComponent]);

// 引入水球图插件(liquidfill)
// import "echarts-liquidfill";
// https://github.com/ecomfe/echarts-liquidfill/issues/147#issuecomment-984211663

function isClient() {
  return typeof window !== "undefined";
}

// 使用 ref 引用 DOM 元素,用于渲染图表
const chartRef = ref(null);

// 存储 ECharts 实例和 ResizeObserver 实例
let myChart = null;
let resizeObserver = null;

/**
 * 封装获取 ECharts 配置项的函数
 * @param {Number} value 图表要展示的值(0-1之间)
 * @returns {Object} ECharts 配置对象
 */
function getOption(value) {
  return {
    backgroundColor: "#fff", // 图表背景色
    series: [
      {
        type: "liquidFill", // 使用水球图
        radius: "100%", // 水球图的半径
        center: ["50%", "50%"], // 图表中心位置
        data: [value], // 显示的数值(即水位)
        color: ["#3399FF"], // 水球的颜色
        outline: {
          show: false, // 不显示轮廓外线
        },
        itemStyle: {
          opacity: 1, // 水球不透明度为1
          shadowBlur: 0, // 无阴影模糊
          shadowColor: "transparent", // 无阴影颜色
        },
        backgroundStyle: {
          color: "#ffffff", // 水球底色为白色
          shadowBlur: 0,
          shadowColor: "transparent",
        },
        label: {
          // 使用富文本显示标题和数值
          formatter: `{title|磁盘空间剩余}\n{value|${
            (value * 100).toFixed(0) + "%"
          }}`,
          rich: {
            title: {
              fontSize: 14,
              color: "#7b7b7b",
            },
            value: {
              fontSize: 24,
              color: "#000",
              padding: [14, 0, 0, 0],
            },
          },
        },
        amplitude: 10, // 波浪振幅
        waveLength: "80%", // 波长
        phase: 0, // 波的初相位
        period: 2000, // 波的动画周期(毫秒)
      },
    ],
  };
}

// 组件挂载后初始化图表和监听器
onMounted(async () => {
  if (isClient()) {
    // require("echarts-liquidfill");
    await import("echarts-liquidfill");
    // 初始化 ECharts 实例
    myChart = echarts.init(chartRef.value);
    // 设置初始图表数据
    myChart.setOption(getOption(props.value));

    // 创建 ResizeObserver,当容器大小变化时自动调整图表
    resizeObserver = new ResizeObserver(() => {
      myChart && myChart.resize();
    });
    // 开始观察引用的 DOM 元素大小变化
    resizeObserver.observe(chartRef.value);
  }
});

// 组件卸载前清理资源
onBeforeUnmount(() => {
  // 停止观察
  if (resizeObserver) {
    resizeObserver.disconnect();
  }
  // 销毁图表实例,释放资源
  if (myChart) {
    myChart.dispose();
    myChart = null;
  }
});

// 监听传入的 value 值的变化,一旦变化即更新图表数据
watch(
  () => props.value,
  (newVal) => {
    if (myChart) {
      // 当 value 改变时,重新设置图表选项
      myChart.setOption(getOption(newVal));
    }
  }
);
</script>

<style scoped lang="scss">
.chart-wrap {
  display: inline-flex;
  border: 2px solid #3399ff;
  border-radius: 50%;
  padding: 2px;
  box-sizing: border-box;
}
.chart-container {
  width: var(--chart-size, 200px);
  height: var(--chart-size, 200px);
  border-radius: 50%;

  overflow: hidden;
  cursor: default;
}
</style>

四、Vue3 使用代码

查看源码
vue
<template>
  <div style="--chart-size: 500px;">
    <WaveProgress :value="diskUsageValue" />
  </div>
</template>

<script setup>
import { ref } from "vue";
import WaveProgress from "./WaveProgress.vue";

const diskUsageValue = ref(0.7);

// 模拟异步修改值
setTimeout(() => {
  diskUsageValue.value = 0.5;
}, 2000);
</script>

五、html 代码

WaveProgress.html

查看源码
html
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>波浪球进度条示例</title>
    <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/echarts-liquidfill/dist/echarts-liquidfill.min.js"></script>
  </head>
  <body>
    <div id="main" style="width: 400px; height: 400px"></div>
    <script>
      // 基于准备好的dom,初始化echarts实例
      var myChart = echarts.init(document.getElementById("main"));

      // 假设进度值为0.6即60%
      var value = 0.9;

      var option = {
        backgroundColor: "#fff", // 背景色可根据需求调整
        series: [
          {
            type: "liquidFill",
            radius: "100%", // 控制球体的大小
            center: ["50%", "50%"],
            data: [value], // 数据数组中第一个值就是显示的进度值(0~1)
            color: ["#3399FF"], // 波浪颜色
            outline: {
              show: false,
            },
            label: {
              formatter: `{title|磁盘空间剩余}\n{value|${
                (value * 100).toFixed(0) + "%"
              }}`,
              rich: {
                title: {
                  fontSize: 20,
                  color: "#000",
                },
                value: {
                  fontSize: 40,
                  color: "#000",
                  padding: [14, 0, 0, 0], // 上、右、下、左四方向padding
                },
              },
            },
            backgroundStyle: {
              color: "#f2f2f2", // 球体背景色
            },
            // 下方选项可根据美观需求自行调整
            amplitude: 10, // 波浪振幅
            waveLength: "80%", // 波长
            phase: 0, // 波的初相
            period: 2000, // 波的动画周期(ms)
          },
        ],
      };

      // 使用指定的配置项和数据显示图表
      myChart.setOption(option);
    </script>
  </body>
</html>