D3.js伪3D柱状图路径"生长"动画实现问询
实现伪3D柱状图的同步生长动画
这问题问到点子上了!用path做伪3D柱状图的生长动画确实比rect麻烦些,但核心思路很清晰——让三个path的动画基于同一个进度值(0→1)同步更新形状,就能保证正面、顶面、侧面始终维持正确的3D关联。下面给你一步步拆解实现方案:
核心思路
- 给每个path定义动态生成路径的函数,函数接收数据和当前动画进度(0到1的数值),返回对应进度下的
d属性值; - 用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




