You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

D3.js伪3D柱状图路径"生长"动画实现问询

实现伪3D柱状图的同步生长动画

这问题问到点子上了!用path做伪3D柱状图的生长动画确实比rect麻烦些,但核心思路很清晰——让三个path的动画基于同一个进度值(0→1)同步更新形状,就能保证正面、顶面、侧面始终维持正确的3D关联。下面给你一步步拆解实现方案:

核心思路

  1. 给每个path定义动态生成路径的函数,函数接收数据和当前动画进度(0到1的数值),返回对应进度下的d属性值;
  2. 用D3的attrTween方法替代普通的attr过渡,在动画过程中实时计算每个进度节点的路径形状,确保三个部分同步变化。

修改后的代码实现

createColumns(bars, data) {
  //...skip code
  const rectW = rectWidth();
  const barDepth = depth; // 提前存好深度值,避免重复调用

  // 正面柱子的生长动画
  bars
    .data(data)
    .append('path')
    .attr('class', 'forward-bar bar')
    // 初始状态:高度为0,是一条水平线
    .attr('d', () => `M 0,0 V 0 H ${rectW} V 0 H 0 Z`)
    .transition()
    .duration(1000) // 动画时长,可根据需求调整
    .attrTween('d', function(d) {
      // 创建高度从0到目标值的插值器
      const heightInterpolator = d3.interpolate(0, rectHeight(d.value));
      return function(t) {
        const currentHeight = heightInterpolator(t);
        // 根据当前进度返回正面柱子的路径
        return `M 0,0 V ${currentHeight} H ${rectW} V 0 H 0 Z`;
      };
    });

  // 顶面梯形的跟随动画
  bars
    .data(data)
    .append('path')
    .attr('class', 'top-bar bar')
    // 初始状态:和正面顶部重合(高度为0)
    .attr('d', () => `M 0,0 L ${rectW},0 L ${rectW + barDepth}, ${-barDepth} H ${barDepth} Z`)
    .transition()
    .duration(1000)
    .attrTween('d', function(d) {
      const heightInterpolator = d3.interpolate(0, rectHeight(d.value));
      return function(t) {
        const currentHeight = heightInterpolator(t);
        // 顶面整体跟着正面高度同步下移(如果你的y轴向上为正,这里要改符号)
        return `M 0,${currentHeight} L ${rectW},${currentHeight} L ${rectW + barDepth}, ${currentHeight - barDepth} H ${barDepth} Z`;
      };
    });

  // 侧面四边形的生长动画
  bars
    .data(data)
    .append('path')
    .attr('class', 'side-bar bar')
    // 初始状态:高度为0,缩成一条斜线
    .attr('d', () => `M ${rectW},0 L ${rectW + barDepth},${-barDepth} V ${-barDepth} L ${rectW} 0 Z`)
    .transition()
    .duration(1000)
    .attrTween('d', function(d) {
      const heightInterpolator = d3.interpolate(0, rectHeight(d.value));
      return function(t) {
        const currentHeight = heightInterpolator(t);
        // 同步修改侧面两个垂直端点的y坐标,保持斜面形状
        return `M ${rectW},0 L ${rectW + barDepth},${-barDepth} V ${currentHeight - barDepth} L ${rectW} ${currentHeight} Z`;
      };
    });
}

关键细节说明

  • 同步进度:三个path的动画共用同一个高度插值器,确保它们的生长节奏完全一致;
  • 初始状态:每个path的初始d都设置为高度为0的形态,让动画从“无”开始生长;
  • 坐标系适配:如果你的SVG是y轴向上为正(SVG默认),只需要把所有高度相关的符号反转即可(比如currentHeight改成-currentHeight),根据你的实际坐标系调整就行。

内容的提问来源于stack exchange,提问作者rocinante

火山引擎 最新活动