LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

echart实现柱状图里的水波效果

liguoquan
2025年8月27日 8:41 本文热度 87
:echart实现柱状图里的水波效果


echart实现柱状图里的水波效果

762阅读5分钟
专栏: 
vue

一、项目介绍

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

思路

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

二、了解renderItem

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

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

参数

renderItem 函数接收两个参数:params 和 api

//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}<br/>已处理: ${data.processed}<br/>未处理: ${data.unprocessed}<br/>总计:${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;  } });

最终效果: 


该文章在 2025/8/27 8:41:26 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved