2015-10-29 73 views
1

我們在一個網絡應用上使用了一個d3.layout.force,我一直在研究一個在Android上很慢的錯誤報告:它感覺像節點在石油中,相比它在桌面瀏覽器或iOS上的工作方式。如何避免Android上呆滯的d3強制佈局?

(順便說一句,我們永遠只能有節點4和9之間,而呆滯不覺得不同的4間9)

我們設置size()linkDistance()charge();所以我們使用默認的摩擦力,theta,alpha,gravity等。我嘗試用這些來嘗試在桌面上重現效果,但是不能。 (friction(0.67),而不是0.9默認情況下,最接近的,但還是覺得不同的,不知何故。)

然後我建立了一個FPS儀(基於呼叫的tick()功能)。我們在桌面上獲得60fps,而在40年代和50年代似乎在ipad上。但在Android Chrome上(在Nexus 7上),它似乎限制在30fps,而且通常只有這一半。 Android的Firefox通常在20幾歲,但有時到了30多歲。

那麼,這是一個合理的假設,Android設備只是慢? Android Chrome可以有30fps的上限嗎?

那麼我該如何解決這個問題?我相信d3.js使用requestAnimationFrame()。通常,動畫庫在調用requestAnimationFrame()之間的時間來決定移動對象的距離(因此,當CPU過載時,動畫變得更加快速,但需要花費相同的時間才能完成)。但看起來d3.js不會這樣做,並且會通過打勾而不是按照已用時間移動所有內容。我能做些什麼呢?

(理想情況下,我想一個解決方案基於如何快/慢的機器,而不是來嗅探瀏覽器。)

+0

[這個問題](https://stackoverflow.com/questions/18311818/speed-up-d3-force-layout-with-many-nodes-and-links)和[這個問題](https://開頭stackoverflow.com/questions/26188266/how-to-speed-up-the-force-layout-animation-in-d3-js)可能會有幫助。 –

+0

@LarsKotthoff感謝。我只有幾個節點(只是更新了問題)。我會盡力在第一環節的想法有關使用'requestAnimationFrame()'添加到'剔更多的呼叫()'...如果我是CPU綁定,因爲()''中剔花的時間,我想這沒有什麼區別;所以看到會發生什麼會很有趣。 –

回答

0

奇怪的是,在我自己的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。