如何避免在Android上缓慢的d3力量布局?

时间:2015-10-29 22:31:43

标签: android d3.js force-layout

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

(顺便说一句,我们只有4到9个节点,4到9之间的迟缓感觉不同。)

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

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

那么,一个合理的假设是Android设备只是慢一点吗? Android Chrome可能会有30fps的上限吗?

然后我该如何解决这个问题?我相信d3.js使用requestAnimationFrame()。通常,动画库会在调用requestAnimationFrame()之间花费时间来决定移动对象的距离(因此当CPU过载时,动画会变得更加笨拙,但需要相同的时间才能完成)。但似乎d3.js不会这样做,并且通过刻度而不是经过的时间将所有内容移动相同的数量。我该怎么办?

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

1 个答案:

答案 0 :(得分:0)

奇怪的是,在我自己的force.tick()处理程序中添加了对requestAnimationFrame()的更多调用(请参阅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从零开始)。
  3. 然后在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。