如果我理解正确(我可能没有正确理解),则没有开箱即用的解决方案,而无需深入了解。但是,如果selection.interrupt() 是您正在寻找的形式,我相信您可以以相对简单的方式构建功能。
为此,您需要为访问转换数据的 d3 选择创建一个新方法(位于:selection.node().__transition)。过渡数据包括关于补间、计时器和其他过渡细节的数据,但最简单的解决方案是将持续时间设置为零,这将强制过渡结束并将其置于结束状态:
__transition 数据变量可以有空槽(可变编号),这可能会在 Firefox 中引起悲伤(据我所知,在使用 forEach 循环时),所以我使用了键方法获取包含转换的非空槽。
d3.selection.prototype.finish = function() {
var slots = this.node().__transition;
var keys = Object.keys(slots);
keys.forEach(function(d,i) {
if(slots[d]) slots[d].duration = 0;
})
}
如果使用延迟,您还可以使用以下内容触发计时器回调:if(slots[d]) slots[d].timer._call();,因为将延迟设置为零不会影响过渡。
使用此代码块调用selection.finish(),这将强制转换到其结束状态,单击一个圆圈来调用该方法:
d3.selection.prototype.finish = function() {
var slots = this.node().__transition;
var keys = Object.keys(slots);
keys.forEach(function(d,i) {
if(slots[d]) slots[d].timer._call();
})
}
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500);
var circle = svg.selectAll("circle")
.data([1,2,3,4,5,6,7,8])
.enter()
.append("circle")
.attr("cx",50)
.attr("cy",function(d) { return d * 50 })
.attr("r",20)
.on("click", function() { d3.select(this).finish() })
circle
.transition()
.delay(function(d) { return d * 500; })
.duration(function(d) { return d* 5000; })
.attr("cx", 460)
.on("end", function() {
d3.select(this).attr("fill","steelblue"); // to visualize end event
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.12.0/d3.min.js"></script>
当然,如果您想保留方法 d3-ish,请返回选择,以便您可以在之后链接其他方法。为了完整起见,您需要确保有一个过渡要完成。添加这些内容后,新方法可能如下所示:
d3.selection.prototype.finish = function() {
// check if there is a transition to finish:
if (this.node().__transition) {
// if there is transition data in any slot in the transition array, call the timer callback:
var slots = this.node().__transition;
var keys = Object.keys(slots);
keys.forEach(function(d,i) {
if(slots[d]) slots[d].timer._call();
})
}
// return the selection:
return this;
}
这是这个更完整实现的bl.ock。
以上内容适用于 D3 的第 4 版和第 5 版。在版本 3 中复制这一点有点困难,因为在版本 4 中对计时器和转换进行了一些重新设计。在版本 3 中,它们不太友好,但只需稍作修改即可实现该行为。为了完整起见,here's a block 是一个 d3v3 示例。