2011-11-23 29 views
5

修訂問題 我已經更新了這一點更簡潔..:到〜3000拉斐爾對象一次順利動畫屬性發生變化

在這種提琴:http://jsfiddle.net/pX2Xb/4/我有借鑑一些3000拉斐爾代碼圈到頁面。然後嘗試在10秒內一次對所有圓圈進行動畫處理(更改填充顏色),這會產生笨重的視覺動畫。將圓圈數量更改爲20以查看比較平滑的動畫。

我的問題是(a)是否有可能對3000個元素進行更新,並且(b)如果是,那麼代碼的做法是什麼?

一些注意事項:

  • 我願意拿小定時打,如果有一些方法來解決這個優化,但是,例如,我想所有界至少已經更新無論動畫時間設置爲1.5倍。所以,如果動畫是10秒,所有圈子應該已經改變了15.
  • 3000個元素大致是我目前的限制,所以我會很高興它爲此工作:)在說,如果解決方案可以有效地處理更多的事情,對於一般情況來說,這真的很棒。

舊的細節,在情況下,它可以幫助

我創建一個大圖美縣,其中有超過3000的;我使用this Wikipedia svg file來獲取相關的SVG路徑來創建地圖,並使用RaphaelJs來渲染地圖。

因此,我結束了類似下面的3000語句:

var cc_02130 = rsr.path("M 140.66674,.... 320.11635"); // county path 
    cc_02130.attr({id: '02130',.. .."marker-start": 'none'}); // init attrs 

我也創造了Paper.set()對象來保存所有這些元素:

var myset = paper.set([cc_56039, cc_56040, cc_56041 ...]) 

忘記了在這裏實際生成的文件非常大,我非常感謝的建議,我可以如何將更改應用到上面詳述的對象的體積,這既快又合理確定CPU聰明 (可能是一個很大的問題)。

我絕對會改變我的代碼/對象的結構,只要我可以單獨更改特定縣的屬性。 例如,我希望能夠在一秒或兩次(全部3000+)中爲每個路徑內容應用不同的顏色。

我面臨的挑戰不是如何應用顏色變化,動畫等,而是如何快速高效地完成這一任務。現在,如果我循環並對3000多個對象應用更改,我的機器就會尖叫我;作爲替代方案,我使用setTimeout將更改分解爲更小的塊(也許10個一次,延遲40 ms)。超過3000個項目,這變得很慢,並仍然使用大量的CPU。

感謝, OLI

+1

我的猜測是,你的延遲來自你更新對象觸發的大量重繪,而不是從對象本身的變化觸發。即使在慢速機器上,3000個函數調用也應該在一秒鐘內完成。你可以衡量一下,如果你觸發了每次更改的重繪? 如果是,請查看是否有方法在重繪之前阻止重繪或批量更新。 – Munter

+0

我同意@Munter - 我現在明白我的問題是關於所有這些形狀的實際重繪/渲染,而不是實際的函數調用。考慮到這一點,我仍然在某種程度上確保我能夠改善_this_問題。相應地更新我的問題。 – oli

+0

如果您有能力損失非svg瀏覽器,那麼您的問題更適合d3.js。這裏是你的jsfiddle由d3處理的動畫:http://jsfiddle.net/ekMd6/ – Duopixel

回答

10

我不知道爲什麼,但是D3.js在同時動畫大量元素時效率更高。

Raphael.st.nodes = function() { 
    var elements = []; 
    this.forEach(function (i) { 
    elements.push(i.node); 
    }); 
    return elements; 
} 

然後你讓D3從那裏

//circleholder is a Raphael set 
elements = circleholder.nodes() 
d3.selectAll(elements) 
    .transition() 
    .attr("fill", function(d,i){return colours[randomNum(14)]}) 
    .duration(ANIMATION_DELAY) 

這裏:您可以通過創建一個接收一組,並返回要進行動畫處理的HTML對象拉斐爾功能讓他們都工作無縫是jsfiddle:http://jsfiddle.net/mFecs/

+2

使用D3和Raphael的非常漂亮的例子。絕對是一個想法,我會爲未來的項目竊取! – slebetman

+0

@slebetman您是否知道竊取代碼違反了StackOverflow的使用條款? – ajax333221

+0

由於@Duopixel非常感謝你的多重輸入。我將使用你的實現 - 在這一點上,我正在考慮在D3中重新實現它,但是我們會看到 - 無論哪種方式,我一定會在將來使用這個庫 - 所以謝謝! – oli

0

。我不認爲目前熟悉Rapael。js,我只是建議用一種通用的JavaScript方式,你可以創建一個changeRaphaelPathAttributeEvent,每次你想改變路徑時發出一個改變,將屬性改變作爲所述事件的參數。然後將事件處理程序附加到將執行屬性更改的每個路徑(如果可能的話)。

這樣就可以解決循環訪問所有路徑變量並同步更改屬性的問題(這會直接影響頁面在處理過程中的響應);該方法對用戶體驗的性能影響較小。

注意:這只是解決即時性能問題的解決方案。也許還有其他的解決方案可以最大限度地減少訪問所需的對象數量,你也應該考慮(並且我不能告訴你,因爲我不知道拉斐爾那麼好)。

+0

謝謝@Sune,我正試圖實現這個權利。我還沒有完成,但是,我擔心它仍然會遇到同樣的問題,即瀏覽器試圖一次性將更改應用到所有這些svg對象。 – oli

0

您是否手動編寫了所有路徑?如果你把所有的路徑放在一個對象中,我認爲更好。然後,您可以迭代對象並使用所有路徑,例如for in。在這個過程中,您可以使用element.id = 'name'爲每個路徑提供一個內部ID。一旦你把所有的內部ID's和路徑drawed,您可以使用getById方法:getById('pathId')如果你要使用集我建議你使用Clousures,可以先聲明變量

var setName = Paper.Set() 

和那麼,如果你想一些屬性應用於元素推入另一個循環

for (countie in Lousiana){ 
    setName.push(countie) 
} 

然後你有一個像Paper.forEach()方法的路徑。或者Set.FotEach()。兩者都採用參數等回調函數,然後在每次迭代中執行該函數。

如果你想分享你的代碼,這對我來說不會是一個問題,我可以檢查一下,並且告訴我如何解決一些情況。我也在開發地圖,我正在開發一個教育視頻遊戲,如果你願意,我也可以和你分享我的代碼,但是關於拉斐爾的文檔沒有那麼多,所以這對我來說很有用,看看如何你使用它,也許你也一樣。

再見!

+0

感謝您的建議,我已經實現了你現在提到的許多東西(特別喜歡漂亮的element.id/getById的東西 - 不知道你可以做到這一點)。不幸的是我仍然有一個問題加快速度,但很快就會在這裏發佈代碼。 – oli

-1

說實話,改變3000個物品的屬性對於任何電腦都應該很容易。 Raphael爲每個動畫元素使用setInterval。元素屬性更改後,瀏覽器重新繪製整個頁面。這是2999次不必要的重新抽獎。

這是我會做的:不使用拉斐爾動畫,而是使用循環來更改每個元素。這有點複雜,但速度更快。另外,您可以更改每秒的步驟。如果您的動畫運行速度太慢,只需減少每秒的步數。

下面是一個例子:http://jsfiddle.net/dqJps/25/

希望這有助於。

+0

謝謝@Joel。我沒有機會嘗試這一點,因爲我不知道如何將其全部應用於它(例如,使用動畫函數,它隨着時間逐漸改變屬性)。我相應地更新了我的問題,感謝您的幫助。 – oli

+0

直到JavaScript代碼停止執行(瀏覽器進入事件循環),重繪纔會發生,因此在循環中調用3000'changeAttribute()'只會導致重繪。 – slebetman

+0

@slebetman - 我同意你的意見,但我的觀點是,拉斐爾設置了3000個setIntervals。這些變化永遠不會出現在循環中。當每個間隔完成時,瀏覽器檢測到HTML更改並重新繪製頁面(或頁面的相關部分)。 – Joel