【问题标题】:How to avoid sluggish d3 force layout on Android?如何避免 Android 上缓慢的 d3 强制布局?
【发布时间】:2015-10-29 22:31:42
【问题描述】:

我们在一个网络应用程序上使用d3.layout.force,我一直在调查一个错误报告,它在 Android 上运行缓慢:与在桌面浏览器上的工作方式相比,感觉节点处于油中,或 iOS。

(顺便说一句,我们只有 4 到 9 个节点,而 4 到 9 之间的缓慢感觉并没有什么不同。)

我们设置size()linkDistance()charge();所以我们使用摩擦力、θ、阿尔法、重力等的默认值。我用这些进行了试验,试图在桌面上重现效果,但不能。 (friction(0.67),而不是默认的 0.9,是最接近的,但不知何故仍然感觉不同。)

然后我设置了一个 FPS 计(基于对 tick() 函数的调用)。我们在台式机上获得 60 fps,在 ipad 上似乎是 40 和 50 年代。但在 Android Chrome(在 Nexus 7 上)上,它的上限似乎为 30fps,而且通常只有一半。 Android Firefox 通常是 20 多岁,但有时会进入 30 多岁。

那么,Android 设备只是速度较慢是一个合理的假设吗? Android Chrome 会不会有 30fps 的上限?

那我该如何解决呢?我相信 d3.js 使用requestAnimationFrame()。通常动画库在调用requestAnimationFrame() 之间需要时间来决定将对象移动多远(因此,当 CPU 过载时,动画会变得更加抖动,但需要相同的时间才能完成)。但似乎 d3.js 并没有这样做,而是按刻度移动所有内容,而不是按经过的时间。我该怎么办?

(理想情况下,我想要一个基于机器的慢/快的解决方案,而不是必须嗅探浏览器。)

【问题讨论】:

  • This questionthis question 可能会有所帮助。
  • @LarsKotthoff 谢谢。我只有几个节点(刚刚更新了问题)。我将在第一个链接中尝试使用requestAnimationFrame()tick() 添加更多调用...所以看看会发生什么会很有趣。

标签: android d3.js force-layout


【解决方案1】:

奇怪的是,在我自己的 requestAnimationFrame() 处理程序中添加更多对 force.tick() 的调用(请参阅 https://stackoverflow.com/a/26189110/841830),确实提高了 FPS。这表明它不受 CPU 限制,而是 Android 正在实施的限制(也许是为了节省电池?)。

这是我正在使用的代码,它试图动态适应当前的 fps;它并不漂亮,但似乎在我的测试 android 设备中完成了工作,而没有改变 iOS 或桌面的行为。

首先,设置force 布局:

var ticksPerRender = 0;
var animStartTime,animFrameCount;

force.on('start',function start(){
  animStartTime = new Date();animFrameCount=0;
  });

requestAnimationFrame(function render() {
  for(var i = 0;i < ticksPerRender;i++)force.tick();
  if(force.alpha() > 0)requestAnimationFrame(render);
  });

上面做了两件事:

  1. 设置 fps 计数器
  2. 设置我们自己的动画回调,默认情况下不执行任何操作(ticksPerRender 从零开始)。

然后在您的tick 处理程序结束时:

++animFrameCount;
if(animFrameCount>=15){ //Wait for 15, to get an accurate count
    var now = new Date();
    var fps = (animFrameCount / (now - animStartTime))*1000;
    if(fps < 30){
        ticksPerRender++;
        animStartTime = now;animFrameCount = 0;  //Reset the fps counter
        }
    if(fps > 60 && ticksPerRender >= 1){
        ticksPerRender--;
        animStartTime = now;animFrameCount = 0;  //Reset the fps counter
        }
    }

这表示如果 FPS 较低(低于 30),请在每个动画帧上额外调用 tick()。如果它变高(超过 60),请移除该额外调用。

每次更改 ticksPerRender 时,我们都会从头开始测量 FPS。

【讨论】:

    猜你喜欢
    • 2013-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-17
    • 1970-01-01
    • 2018-09-20
    • 2013-07-19
    • 1970-01-01
    相关资源
    最近更新 更多