在.each()回调(D3)中触发平滑转换

Smooth transition triggered in .each() callback (D3)

本文关键字:平滑 转换 D3 each 回调      更新时间:2023-09-26

我已经创建了一个在D3的selection.each()中调用的转换,但是在回调和转换之间有轻微的延迟。我希望转换看起来是连续的而不是有轻微的延迟。我尝试过不同的持续时间和延迟值,但无济于事。以下是相关代码。

transition();
function transition() {
    data.map( (d) => {
        d.x = d3.random.normal(d['x'], 5)();
        d.y = d3.random.normal(d['y'], 5)();
        return d;
    });
    g.selectAll('path')
        .data(data)
        .transition()
        .duration(400)
        .attr('d', (d, i) => line( getPath(d, i) ) )
        .each('end', transition);
}

正如您在这个工作的代码依赖中看到的,在转换之间有一个轻微的延迟。我希望过渡看起来是连续的。我怎样才能做到这一点呢?

几个要点…

  1. d3转换的默认缓和不是线性的,所以这就是为什么你会感觉到延迟。
  2. 您实际上是在每个单独的路径转换完成后设置一个新的转换。each方法回调选择中的每个节点,并且在d3转换中没有内置的endall事件,但是,您可以创建一个,如下所示。

第一点可能是最重要的。第二点是避免不必要地重新应用过渡和中断先前应用的过渡。可能感觉不到,但无论如何都是很好的练习。

下面是一个工作示例…

var colors = [
	'#FFAA5C',
	'#DA727E',
	'#AC6C82',
	'#685C79',
	'#455C7B'
]
var line = d3.svg.line()
	.x( (d) => d.x )
	.y( (d) => d.y )
	.interpolate('linear'); 
var svg = d3.select('body').append('svg');
var svgW = d3.select('svg').node().clientWidth;
var svgH = d3.select('svg').node().clientHeight;
var w = svgW/4;
var h = svgH/4;
var data = [ 	{x: -w/2, y: -h/4}, {x: 0, y: -h/2}, {x: w/2, y: -h/4}, 
								{x: w/Math.PI, y:h/2.5}, {x: -w/4, y: h/2.5} ];
var getPath = (d, i) => {
	var path = [];
	
	var startPoint = { x: 0, y: 0 };
	// point 1
	path.push(startPoint);
	// point 2
	path.push(d);
	
	// point 3
	path.push(data[i + 1] || data[0]);
	
	// point 4
	path.push(startPoint);
	
	return path;
}
var g = svg.append('g')
	.attr('transform', 'translate(' + svgW/2 + ',' + svgH/2 + ')');
g.selectAll('path')
	.data(data)
.enter().append('path')
	.attr({
		fill: (d, i) => colors[i]
	});
transition();
function transition() {
	
	data.map( (d) => {
		d.x = d3.random.normal(d['x'], 5)();
		d.y = d3.random.normal(d['y'], 5)();
		return d;
	});
	
	g.selectAll('path')
		.data(data)
		.transition()
		.ease("linear")
		.duration(50)
		.attr('d', (d, i) => line( getPath(d, i) ) )
		.call(endall, function(){window.requestAnimationFrame(transition)});
	
}
  function endall(transition, callback) { 
    if (transition.size() === 0) { callback() }
    var n = 0; 
    transition 
        .each(function() { ++n; }) 
        .each("end", function() { if (!--n) callback.apply(this, arguments); }); 
  }
body {
	background-color: #181818;
	display: flex;
	justify-content: center;
	align-items: center;
	height: 100vh;
	width: 100%;
}
svg {
	overflow: visible;
	width: 100%;
	height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>