D3.js + SVG 如何可視化出幾萬甚至幾十萬的數據量爽锥?
別無他法涌韩,想都不用想了,答案是可視化不出來
當然氯夷,如果你堅持的話臣樱,如果你非要...你愣是...你霸蠻...你...,你還是能可視化出來 “幻燈片” 一樣的結果的,但是如果要交互呢雇毫?
穩(wěn)住老鐵奢啥,有辦法,唯一的辦法就是嘴拢,減少可視化的數據量桩盲,從幾十萬數據量中挑選少量數據可視化,并且要滿足一個關鍵條件席吴,挑選出來的少量數據畫出來的圖和完整數據畫出來的圖效果應該是差不多的
那有沒有辦法挑選出這部分少量的數據呢赌结? 有的
經過多次查閱資料后,發(fā)現有一種 “遮擋剔除” 算法孝冒,我大致把他理解為柬姚,在游戲場景中,你的視線范圍內看不見的庄涡,被其他物體擋住視線的物體量承,通過算法找出這些物體,并且隱藏這些物體穴店。
那么對應到 D3.js + SVG 的場景中撕捍,你可以想象為,你需要在有限寬度的屏幕上顯示 10w 個小圓點泣洞,無論是樹狀圖還是散點圖還是其他圖忧风,通常這些小圓點肯定會存在重疊十分嚴重的區(qū)域,這些區(qū)域看起來密密麻麻一片球凰,甚至一點縫隙都不留狮腿,那么,我們就可以通過方法找出這些區(qū)域中被重疊遮住了的小圓點呕诉,從而在畫圖的時候就不畫這些小圓點缘厢。
在下面 圖1 中,我們需要找出黃色的小圓點(小圓A)甩挫,類似于這樣的黃色小圓點就可以過濾掉贴硫,通常這樣的黃色小圓點畫出來也沒有意義,只會拖慢頁面速度捶闸,因為它完全被其他圓遮蓋住了夜畴,它既不能被看到拖刃,也無法被交互删壮,這樣的節(jié)點即使過濾掉不顯示出來,頁面上顯示的效果也不會有任何差別兑牡,對吧央碟?
這樣看起來就能實現 “遮擋剔除” 了,但是就憑我腦子里的這點知識儲備,這樣的邏輯我真不知道該如何下手寫代碼~
但是亿虽,但是我有了另一種思路菱涤,這回我甚至都沒來得及查資料,我的靈感就瞬間爆發(fā)出來了~
自創(chuàng)獨門絕技
首先我將這種算法稱之為 “擁擠過濾”(但凡事我想一件事情洛勉,我先給它取個名字)粘秆,看起來像是 “遮擋剔除” 的簡易版
這種算法的思路大致是這樣的:
給定的窗口大小,對于擁擠在同一個窗口中的節(jié)點收毫,只允許顯示一個節(jié)點攻走,窗口內的其他節(jié)點不顯示
在下面 圖2 中,窗口大小為 3x3此再,在 3x3 大小的窗口中只允許顯示其中一個點(藍色的圓)昔搂,窗口中其余的圓將被隱藏(黃色的圓),注意:判斷圓是不是在該窗口內時输拇,以圓心的位置為準摘符。當然圖中只是示例數據,實際數據中可能重疊的更厲害策吠,而且窗口大小和圓的半徑都需要根據實際情況來定逛裤。根據我的經驗來看,窗口大小定義為比圓直徑稍微小時猴抹,效果是最好的别凹。反之如果圓不擁擠(重疊),那自然就不會被過濾洽糟。如果擁擠的越嚴重炉菲,那么這種方法的優(yōu)化效果越明顯
過濾掉黃色圓點之后,我們就得到 圖3 的效果了坤溃,實際情況肯定會不一樣拍霜,但是能過濾掉一大部分節(jié)點,并且最終效果和使用完整數據畫出來的效果是差不多的(需要根據場景不同調整窗口大行浇椤)
當前上面幾張演示圖我為了方便理解祠饺,所以圖片看起來效果不怎么理想,如果調整窗口大小和圓半徑為合適的值的話(把窗口大小定義為比圓直徑稍微兄)道偷,效果看起來就好很多了,比如下面的 圖4
有個可以優(yōu)化的點记劈,或許你沒有想到:
- 使用 Promise勺鸦,將畫圖過程拆分多個方法,比如畫線目木、畫點换途、畫...,將這些方法包裝成 Promise,同時執(zhí)行這些 Promise 可以加快畫圖的速度
- 或許你可以考慮以下 PIXI 之類的技術路線
我已經將其封裝為一個方法军拟,待項目開放之后我再將代碼傳上來