过渡(Transitions)
D3 过渡可以在不同图表状态之间平滑地制作动画。
-
创建D3过渡:在要转换的和方法之前添加一个
.transition()
调用:.attr
、.style
function update() { d3.select('svg') .selectAll('circle') .data(data) .join('circle') .attr('cy', 50) .transition() .attr('cx', function(d) { return d.x; }) .attr('r', function(d) { return d.r; }) .style('fill', function(d) { return d.fill; }); }
-
持续时间和延迟:可以通过调用
.duration
来更改转换的持续时间。该.duration
方法接受一个参数,该参数以毫秒为单位指定持续时间;延迟通常用于将选择中的每个元素延迟不同的量。可以通过将函数.delay
传入并将延迟设置为元素索引的倍数来创建交错转换d3.select('svg') .selectAll('circle') .data(data) .join('circle') .attr('cy', 50) .attr('r', 40) .transition() .duration(2000) .attr('cx', function(d) { return d; });
d3.select('svg') .selectAll('circle') .data(data) .join('circle') .attr('cy', 50) .attr('r', 40) .transition() .delay(function(d, i) { return i * 75; }) .attr('cx', function(d) { return d; });
-
缓动函数:定义了元素在过渡期间的速度变化。例如,一些缓动函数会导致元素快速启动并逐渐变慢。其他人则相反(开始缓慢并加速),或者是定义特殊效果,例如弹跳。D3 有许多内置的缓动函数。
一般来说,“in”是指运动的开始,“out”是指运动的结束。因此,
easeBounceOut
导致元素在过渡结束时反弹。easeBounceInOut
使元素在过渡的开始和结束时反弹。d3.select('svg') .selectAll('circle') .data(data) .join('circle') .attr('cy', 50) .attr('r', 40) .transition() .ease(d3.easeBounceOut) .attr('cx', function(d) { return d; });
-
链式转换:可以通过添加多个调用链接在一起
.transition
。每个过渡都将轮流进行。(当第一个过渡结束时,第二个将开始,依此类推。)function update() { d3.select('svg') .selectAll('circle') .data(data) .join('circle') .attr('cy', 50) .transition() .attr('cx', function(d) { return d.x; }) .transition() .duration(750) .ease(d3.easeBounce) .attr('r', function(d) { return d.r; }); }
-
.tween:自定义元素所采用的路径(例如沿着大圆的圆周)。需要将一个名称(可以是您喜欢的任何名称)和一个函数传递给
.tween
。该函数会被选择中的每个元素调用一次。它必须返回一个函数,该函数将在转换的每个步骤中被调用。t
将0 到 1 之间的值传递给tween函数。(t
在过渡开始时为 0,在结束时为 1。)let data = [], majorRadius = 100; function updateData() { data = [Math.random() * 2 * Math.PI]; } function getCurrentAngle(el) { // Compute the current angle from the current values of cx and cy let x = d3.select(el).attr('cx'); let y = d3.select(el).attr('cy'); return Math.atan2(y, x); } function update() { d3.select('svg g') .selectAll('circle') .data(data) .join('circle') .attr('r', 7) .transition() .tween('circumference', function(d) { let currentAngle = getCurrentAngle(this); let targetAngle = d; // Create an interpolator function let i = d3.interpolate(currentAngle, targetAngle); return function(t) { let angle = i(t); d3.select(this) .attr('cx', majorRadius * Math.cos(angle)) .attr('cy', majorRadius * Math.sin(angle)); }; }); }