偶尔结结巴巴地说“;堆叠的”;translate()上的转换(v4.0.0-alpha40)
Occasional stuttering with "stacked" transitions on `translate()` (v4.0.0-alpha40)
问题:抖动
我有一个D3v4.0.0α.40图,它周期性地(不是在每帧上):
- 获取新的数据点
- 删除旧数据点
- 重置转换并设置
translate(null)
- 启动新的
transition()
new在获取新值时滚动
// Animation
function animateOnce(period) {
// Data: Add new, and remove old
data.unshift(Math.random());
data.pop();
// Do 2 transitions...
path
.attr("d", line)
.transition() /* ...reset */
.attr("transform", null)
.duration(0)
.transition()/* ...scroll across */
.duration(period)
.ease(d3.easeLinear)
.attr("transform", `translate(${x(1)})`)
};
// Animation looper
function animate() {
setTimeout(_=> {
animateOnce(PERIOD);
animate();
},
PERIOD);
}
然而,转换似乎执行得并不干净——每隔几秒钟就会有一次急动。
我以前在D3v3中遇到过这个问题,但我相信我通过添加重置转换(上面的步骤3)解决了这个问题。不幸的是,我没有D3的经验,我不知道如何解决这个问题。
看看吧
这个jsFiddle是我的图的近似值,你应该能够看到偶尔的抖动。
注意:fiddle使用setTimeout
,而我的实际图形是react组件,用componentDidUpdate()
更新。
编辑1:使用中断改进
改进的jsFiddle
在阅读文档时(正如@Ashitaka建议的那样),我发现了interrupt()。这会正确地终止转换,并且可能是实现上述步骤3的"v4方式"(重置转换)。
// Animation
function animateOnce(period) {
// Data: Add new, and remove old
data.unshift(Math.random());
data.pop();
// Do 2 transitions...
path
.attr("d", line)
.interrupt() /* ...reset */
.attr("transform", null)
.transition()/* ...scroll across */
.duration(period)
.ease(d3.easeLinear)
.attr("transform", `translate(${x(1)})`)
};
这改善了急动(我认为是由竞争过渡引起的),将它们变成了小的口吃。
我想了解(我假设是1帧)口吃是在哪里引入的。所以我暂时不谈。
在Mike Bostock的文章《使用过渡》中,他写道:
对于给定的元素,转换是排他的:只有一个转换可以同时在元素上运行。开始新的元素上的转换停止任何已经跑步
现在,我在呈现的代码中检测到两个问题:
-
正在为路径变换重置设置动画(即使具有
0
持续时间)。此新转换将取消上一个转换。这可以通过更改来修复:path .attr("d", line) .transition() .attr("transform", null) .duration(0)
至:
path .attr("d", line) .attr("transform", null)
-
animateOnce
函数的调用周期与D3的转换周期相同,并且转换周期持续约17毫秒。此新转换也取消了以前的转换。这可以通过更改来修复:function animate() { setTimeout(_=> { animateOnce(PERIOD); animate(); }, PERIOD); }
至:
function animate() { setTimeout(_=> { animateOnce(PERIOD); animate(); }, PERIOD + 20); }
可以使用setInterval将其进一步重构为:
function animate() { setInterval(animateOnce, PERIOD + 20, PERIOD); }
这两个更改应该可以解决jank问题。尽管如此,每80毫秒更新一次折线图总是会对某人的电脑或智能手机造成负担。我建议你每200毫秒左右更新一次。
编辑:我做了一些实验,注意到Firefox上仍然有一些jank。因此,还有几点需要考虑:
-
将
transform
属性设置为null
实际上会创建一个新层。这可以通过更改来修复:.attr("transform", null)
至:
.attr("transform", "translate(0)")
-
每次调用
animateOnce
函数时,都会重新创建转换字符串。我们可以在animateOnce
之外预先计算它们,然后重用它们。这可以通过更改来修复:.attr("transform", "translate(0)") .attr("transform", `translate(${x(1)})`)
至:
// outside the animateOnce function: let startStepAttrs = { transform: "translate(0)" }, endStepAttrs = { transform: `translate(${x(1)})` }; // inside the animateOnce function: .attr(startStepAttrs) .attr(endStepAttrs)
- 如何在JavaScript中将字符串转换为函数引用
- 如何在Javascript中将JSon对象转换为数组
- 使用JS将数组转换为json对象
- 如何使用json将对象列表从java转换为javascript
- 偶尔结结巴巴地说“;堆叠的”;translate()上的转换(v4.0.0-alpha40)
- 为什么在单独的函数中应用时转换会闪烁/断断续续(D3)
- 在Javascript中转换对象数组
- 将数字转换为一定数量的硬币
- 将纯文本URL转换为可单击链接
- 当图像转换为本地存储的DataURL时,EXIF被删除
- 如何使用js将SNAPSHOT内部版本号转换为3位数的整数
- 如何将TypeScript对象转换为普通对象
- 检测个位数整数时正在转换毫秒
- 从javascript到jquery的转换
- DOM事件通过JSON转换为java
- 将圆柱体转换为弯管
- 混合 ui-sref 和 $state.go 在 Angular ui-router 中进行状态转换
- JavaScript代码问题:我正在将对象转换为数组
- 如何将字母转换为二进制代码
- 将XML转换为普通的旧JavaScript对象