使用echart实现柱状图里的水波效果示例代码

 更新时间:2026年05月23日 09:46:16   作者:前端灵派派  
这篇文章主要介绍了使用echart实现柱状图里水波效果的相关资料,主要通过renderItem函数方法,返回每个数据项对应的图形元素,包括一个矩形和一个波浪路径,需要的朋友可以参考下

一、项目介绍

最近做项目,甲方要求在柱状图里加上水波图的效果,真是太有趣了,太有创意啦。马上动手实现。

思路

echart提供了一个renderItem方法,可以帮助我们自定义每个series的配置。我们分析柱状图跟水波图,就是由一个矩形跟一个波浪路径组成,因此我们可以返回一个图形数组来表现当前项。

二、了解renderItem

renderItem 函数是自定义系列的核心,它负责将数据项(dataItem)转换为可视化的图形元素。ECharts 会为 series.data 中的每个数据项调用一次 renderItem 函数。主要优势在于:

  1. 可以自由绘制各种图形元素
  2. ECharts 会自动管理图形的创建、删除、动画等细节
  3. 可以与其他组件(如 dataZoom、visualMap)无缝联动

参数

renderItem 函数接收两个参数:paramsapi

//params 包含当前数据信息和坐标系信息:
{
    context: {},       // 可供开发者暂存东西的对象
    seriesId: string,  // 本系列 ID
    seriesName: string, // 本系列名称
    seriesIndex: number, // 本系列索引
    dataIndex: number,  // 数据项在原始数据中的索引
    dataIndexInside: number, // 数据项在当前可见数据窗口中的索引
    dataInsideLength: number, // 当前可见数据长度
    coordSys: {        // 坐标系信息,类型不同结构也不同
        type: 'cartesian2d' | 'polar' | 'geo' | 'calendar' | 'singleAxis',
        // 不同坐标系下的具体属性...
    }
}

api 参数提供了一系列方法:

  • api.value(index) - 获取数据项中指定维度的值
  • api.coord(valueArray) - 将数据值转换为坐标系上的点
  • api.size(valueArray) - 获取坐标系上一段数值范围对应的像素长度
  • api.style(styleOverrides) - 获取或覆盖默认样式

返回值

renderItem 函数需要返回一个图形元素定义对象

{
    type: string,       // 图形类型,如'rect','circle','sector','polygon'等
    shape: object,      // 图形形状定义
    style: object,      // 图形样式
    extra: object,      // 额外信息,可在事件处理器中访问
    children: array,    // 子图形(当type为'group'时)
    // 其他可选属性...
}

三、实现

首先要实现基本配置,柱子的高度为数据的总数,水波的位置为已处理数据,提示窗展示名称、已处理、未处理、总数等数据。

// 数据配置 - 包含已处理和未处理的数据
const chartData = [
  { name: "车辆只进不出", processed: 60, unprocessed: 62, total: 122 },
  { name: "预警模型2", processed: 72, unprocessed: 82, total: 154 },
  { name: "预警模型3", processed: 71, unprocessed: 91, total: 162 }
];
// 创建水波柱状图配置
const createOption = () => {
  return {
    backgroundColor: 'transparent', //echart背景为透明
    animation: false,
    tooltip: { //提示窗配置
      trigger: 'axis',
      axisPointer: {
        type: 'shadow'
      },
      formatter: function(params) {
        const data = chartData[params[0].dataIndex];
        return `${params[0].name}
已处理: ${data.processed}
未处理: ${data.unprocessed}
总计:${data.total}`;
      }
    },
    grid: { //图表位置占比配置,尽量居中
      left: '3%',
      right: '4%',
      bottom: '12%',
      top:'5%',
      containLabel: true
    },
    xAxis: {  //配置x轴
      type: 'category',
      data: chartData.map(item => item.name),
      axisLabel: {
        color: '#fff',
        fontSize: 12
      },
      axisLine: {
        lineStyle: {
          color: '#fff'
        }
      }
    },
    yAxis: { //配置y轴
      type: 'value',
      axisLabel: {
        color: '#fff',
        fontSize: 12,
      },
      axisLine: {
        lineStyle: {
          color: '#fff'
        }
      },
      splitLine: {
        lineStyle: {
          color: 'rgba(255, 255, 255, 0.1)'
        }
      }
    },
    series:series //配置数据项
  };
};

自定义数据项,通过rederItem方法返回一个矩形跟一个波浪路径

// 水波动画时间
let animationTime = 0;
let series = [
{
    name: '水波柱状图',
    type: 'custom',
    renderItem: (params, api) => {
      const categoryIndex = api.value(0); //当前项索引
      const totalValue = api.value(1); //当前项的值
      const processedValue = chartData[categoryIndex].processed; //已完成的值
      const start = api.coord([api.value(0), 0]); //开始的坐标位置,返回[x,y]坐标
      const end = api.coord([api.value(0), totalValue]); //结束的坐位位置
      const height = end[1] - start[1]; //高度
      const width = 40; //宽度
      const rectShape = {  //定义矩形的形状
        x: start[0] - width / 2, 
        y: start[1],
        width: width,
        height: height
      };
      // 计算水波位置 - 基于已处理数量占总数的比例
      const waterLevel = processedValue / totalValue;
      const wavePath = createWavePath(rectShape, waterLevel, animationTime);
      return { //返回值
        type: 'group',
        children: [
          {
            type: 'rect',  //矩形
            shape: rectShape,
            style: {
              fill: {
                  type: 'linear',
                  x: 0,
                  y: 0,
                  x2: 0,
                  y2: 1,
                  colorStops: [
                    { offset: 0, color: 'rgba(24, 144, 255, 0.8)' },
                    { offset: 0.5, color: 'rgba(64, 169, 255, 0.6)' },
                    { offset: 1, color: 'rgba(9, 109, 217, 0.4)' }
                  ]
                },
              stroke: 'rgba(24, 144, 255, 0.3)',
              lineWidth: 1
            }
          },
          {
            type: 'path',  //水波路径
            shape: {
              pathData: wavePath
            },
            style: {
              fill: {
                type: 'linear',
                x: 0,
                y: 0,
                x2: 0,
                y2: 1,
                colorStops: [
                  { offset: 0, color: 'rgba(24, 144, 255, 0.8)' },
                  { offset: 0.5, color: 'rgba(64, 169, 255, 0.6)' },
                  { offset: 0.5, color: 'rgba(64, 169, 255, 0.6)' },
                  { offset: 1, color: 'rgba(9, 109, 217, 0.4)' }
                ]
              }
            },
            z: 10
          }
        ]
      };
    },
    data: chartData.map(item => item.total),
    z: 10
  }
]

实现水波的方法,生成一个svg的路径。SVG 路径字符串是描述矢量图形的重要方式,下面我将详细介绍如何生成 SVG 路径字符串

基本 SVG 路径命令

命令含义示例
M移动到 (MoveTo)M 10,20
L直线到 (LineTo)L 30,40
C三次贝塞尔曲线 (Cubic Bezier)C x1,y1 x2,y2 x,y
Q二次贝塞尔曲线 (Quadratic Bezier)Q x1,y1 x,y
Z闭合路径 (ClosePath)Z
// 创建水波路径
const createWavePath = (rect, waterLevel, time) => {
  const { x, y, width, height } = rect;
  const waterHeight = height * waterLevel; //水波的高度=柱子高度*百分比
  const waterY = y + height - waterHeight; //水波的y轴位置
  
  const waveLength = width;
  const waveHeight = 3;
  const frequency = 1;
  
  // 从底部开始绘制路径
  let path = `M ${x} ${y + height}`;
  
  // 绘制左侧边线到水波位置
  path += ` L ${x} ${waterY}`;
  
  // 绘制水波顶部
  for (let i = 0; i <= width; i += 2) {
    const waveX = x + i;
    // 使用正弦函数计算Y坐标
    const waveY = waterY + Math.sin((i / waveLength) * Math.PI * frequency + time) * waveHeight;
    path += ` L ${waveX} ${waveY}`;
  }
  
  // 绘制右侧边线回到底部
  path += ` L ${x + width} ${y + height}`;
  
  // 闭合路径
  path += ` Z`;
  
  return path;
};

创建echart图标,并实现水波的动画效果

// 创建图表
const createChart = () => {
  const container = chartRef.value;
  chartInstance = echarts.init(container);
  
  chartInstance.setOption(createOption());
  
  // 启动水波动画
  const animate = () => {
    animationTime += 0.1;
    if (chartInstance) {
      chartInstance.setOption({series:series});
    }
    
    requestAnimationFrame(animate);
  };
  
  animate();
};

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

onUnmounted(() => {
  if (chartInstance) {
    chartInstance.dispose();
    chartInstance = null;
  }
});

最终效果:

总结 

到此这篇关于使用echart实现柱状图里水波效果的文章就介绍到这了,更多相关echart柱状图水波效果内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 支付宝小程序从手动埋点到自动埋点的实现过程

    支付宝小程序从手动埋点到自动埋点的实现过程

    埋点的意思是在你想要的数据节点出进行设置,可以方便进行采集,下面这篇文章主要给大家介绍了关于支付宝小程序从手动埋点到自动埋点的相关资料,需要的朋友可以参考下
    2022-03-03
  • 判断iOS、Android以及PC端的示例代码

    判断iOS、Android以及PC端的示例代码

    这篇文章主要给大家介绍了关于如何判断iOS、Android以及PC端的相关资料,主要是利用navigator.userAgent来实现,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2018-11-11
  • VSCode 配置uni-app的方法

    VSCode 配置uni-app的方法

    这篇文章主要介绍了VSCode 配置uni-app的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • 微信小程序实现锚点跳转

    微信小程序实现锚点跳转

    这篇文章主要为大家详细介绍了微信小程序实现锚点跳转,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • JavaScript处理解析JSON数据过程详解

    JavaScript处理解析JSON数据过程详解

    JSON 是 JavaScript 原生格式,也就是说在 JavaScript 中处理 JSON 数据不需要任何特殊的 API 或工具包。接下来,本文给大家介绍JavaScript处理解析JSON数据过程详解,感兴趣的朋友快来了解了解吧
    2015-09-09
  • 使用JavaScript实现一个简单的哈希映射功能

    使用JavaScript实现一个简单的哈希映射功能

    哈希表大家应该都经常用到吧,那么大家有没有想过哈希表是怎么实现的呢,本文我们就来从一道简单的题目来了解一下哈希表的简单原理和实现吧
    2024-02-02
  • JavaScript数组对象赋值用法实例

    JavaScript数组对象赋值用法实例

    这篇文章主要介绍了JavaScript数组对象赋值用法,涉及javascript用户交互及针对数组的排序技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-08-08
  • JS验证字符串功能

    JS验证字符串功能

    这篇文章主要介绍了JS验证字符串功能实例代码,代码简单易懂,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-02-02
  • 函数式编程入门实践(一)

    函数式编程入门实践(一)

    这篇文章主要介绍了Javascript函数式编程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • JavaScript实现跨浏览器的添加及删除事件绑定函数实例

    JavaScript实现跨浏览器的添加及删除事件绑定函数实例

    这篇文章主要介绍了JavaScript实现跨浏览器的添加及删除事件绑定函数,采用纯javascript实现jquery的bind及unbind添加与删除事件绑定的技巧,具有很好的浏览器兼容性,需要的朋友可以参考下
    2015-08-08

最新评论