刷新 d3 v4 转换
Flush a d3 v4 transition
有人知道 'flush' 过渡的方法吗?
我有一个定义如下的转换:
this.paths.attr('transform', null)
.transition()
.duration(this.duration)
.ease(d3.easeLinear)
.attr('transform', 'translate(' + this.xScale(translationX) + ', 0)')
我知道我可以做到
this.paths.interrupt();
停止过渡,但这并没有完成我的动画。我希望能够 'flush' 立即完成动画的过渡。
如果我理解正确(但我可能没有理解正确),则没有开箱即用的解决方案,无需深入了解一下。但是,如果 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,return 选择以便您可以在之后链接其他方法。为了完整性,您需要确保有一个过渡到完成。添加这些内容后,新方法可能类似于:
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 示例。
很棒。然而,出于好奇,我相信它可以在不扩展原型的情况下完成,使用 .on("interrupt"
作为监听器。
在这里,我无耻地复制了 Andrew 的转换代码和 来获取目标属性。
selection.on("click", function() {
d3.select(this).interrupt()
})
transition.on("interrupt", function() {
var elem = this;
var targetValue = d3.active(this)
.attrTween("cx")
.call(this)(1);
d3.select(this).attr("cx", targetValue)
})
这是演示:
var svg = d3.select("svg")
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).interrupt()
})
circle
.transition()
.delay(function(d) {
return d * 500;
})
.duration(function(d) {
return d * 5000;
})
.attr("cx", 460)
.on("interrupt", function() {
var elem = this;
var targetValue = d3.active(this)
.attrTween("cx")
.call(this)(1);
d3.select(this).attr("cx", targetValue)
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="500"></svg>
PS:与 不同,因为我在这里使用 d3.active(node)
,只有在转换 已经开始 时点击才有效.
有人知道 'flush' 过渡的方法吗? 我有一个定义如下的转换:
this.paths.attr('transform', null)
.transition()
.duration(this.duration)
.ease(d3.easeLinear)
.attr('transform', 'translate(' + this.xScale(translationX) + ', 0)')
我知道我可以做到
this.paths.interrupt();
停止过渡,但这并没有完成我的动画。我希望能够 'flush' 立即完成动画的过渡。
如果我理解正确(但我可能没有理解正确),则没有开箱即用的解决方案,无需深入了解一下。但是,如果 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,return 选择以便您可以在之后链接其他方法。为了完整性,您需要确保有一个过渡到完成。添加这些内容后,新方法可能类似于:
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 示例。
.on("interrupt"
作为监听器。
在这里,我无耻地复制了 Andrew 的转换代码和
selection.on("click", function() {
d3.select(this).interrupt()
})
transition.on("interrupt", function() {
var elem = this;
var targetValue = d3.active(this)
.attrTween("cx")
.call(this)(1);
d3.select(this).attr("cx", targetValue)
})
这是演示:
var svg = d3.select("svg")
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).interrupt()
})
circle
.transition()
.delay(function(d) {
return d * 500;
})
.duration(function(d) {
return d * 5000;
})
.attr("cx", 460)
.on("interrupt", function() {
var elem = this;
var targetValue = d3.active(this)
.attrTween("cx")
.call(this)(1);
d3.select(this).attr("cx", targetValue)
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="500"></svg>
PS:与 d3.active(node)
,只有在转换 已经开始 时点击才有效.