mapboxgl - 用webgl展示海量數據,是否可行?


下面的代碼可以在我的Github中找到:https://github.com/QingyaFan/data-visualization

Openlayers憋了好久,終於憋出了WebGL的渲染器,然而只支持點要素類型,要是線和麪類型的要素,數據量級一上去,就沒法用了。我們看看隔壁的Mapboxgl,誕生之日起就是WebGL渲染,而且openlayers新出的WebGLPoint Layer使用的WebGL渲染樣式規則也借鑑了Mapboxgl的表達式(Expression)。所以,爲什麼不用mapboxgl呢?當我想到這個想法的時候,真香定理彷彿在向我招手。於是我掏出壓箱底的321萬的線要素數據 ⚡️ 來一場硬核的測試。

線要素321萬

1、初始化一幅地圖

Mapbox的一些理念和Openlayers不太一樣,在使用之前,我們要看有哪些異同。

Mapbox中數據源(Source)不從屬於圖層(Layer),而是直接由Map對象管理
Layer可以選擇要渲染的Source,所以我們很自然想到,是否可以多個Layer使用一個Source呢?當然可以!Openlayers中也可以,只不過我們之前沒那麼做過
Mapbox中樣式是Paint表示,Openlayers中是Style
在用321萬的數據之前,我們先來一波常規操作,用19萬的全球城市點數據熟悉一下mapbox的流程:

let url = 'http://localhost:8000/world-cities.geojson';
this.map.addSource('cities-population', { type: 'geojson', data: url });
this.map.addLayer({
    'id': 'cities-population',
    'type': 'circle',
    'source': 'cities-population',
    'paint': {
        'circle-radius': [
            "interpolate",
            ["linear"],
            ["get", "population"],
            40000, 2,
            2000000, 12
        ],
        'circle-color': [
            "interpolate",
            ["linear"],
            ["get", "population"],
            40000, 'DarkSlateGrey',
            2000000, 'DarkSlateGray'
        ],
        'circle-opacity': 0.6
    }
    
});
this.map.addLayer({
    'id': 'cities-population-heatmap',
    'type': 'heatmap',
    'source': 'cities-population',
    'paint': {
        'heatmap-radius': [
            "interpolate",
            ["linear"],
            ["get", "population"],
            40000, 2,
            2000000, 12
        ],
        'heatmap-intensity': 0.5
    }
    
});

我們用世界城市人口數據渲染了兩個圖層,一個普通的根據人口數量決定點半徑大小的圖層,另一個是根據人口數量決定熱度的熱度圖。效果還不錯,在圖上,我們可以明顯看出印度的人口密度是真的大,日本也毫不遜色,西歐也想勇爭第一,再看咱中國,胡煥庸線非常明顯,人口密度大的城市都集中在了東部。所以這個熱力圖還是很有用的,不是隻圖個好看。

世界人口熱度圖

2、硬核的來了

好了,是時候祭出321萬的道路數據了,我先描述一下這個數據,避免後面的結果對我們打擊太大:

路

寫個代碼,滿懷期待 🌝:

let url = 'http://localhost:8000/roads.geojson';
this.map.addSource('roads', { type: 'geojson', data: url });
this.map.addLayer({
    'id': 'roads',
    'type': 'line',
    'source': 'roads',
    'paint': {
        'line-color': 'DarkViolet',
        'line-opacity': 0.6
    }
    
});

然而,瀏覽器直接崩了 🌚,加載數據到 800 M 就崩了,有時候1G,什麼時候崩,也要看你同時打開了多少網頁,chrome佔用的總內存是有限制的,比如你看着直播,可能載入800M就崩了,你同時打開了幾個文字網頁,可能1G多崩:

崩潰
很顯然,就算WebGL再強,瀏覽器本身加載數據量有限制,佔用機器的內存也不會無限大。讀過《深入淺出Nodejs》的可能知道,Nodejs的Javascript運行時是V8,而V8本來就用在了Chrome上,V8的內存限制導致瀏覽器不能加載特別大的Javascript對象,所以整體加載並不能解決大數據量的渲染問題。解決這個問題也有一些思路,比如:

  1. 對數據化簡,讓數據沒有那麼大的體積。這個思路需要注意,數據在不同的縮放級別下應該是不一樣的化簡程度,高縮放級別下,可多化簡,反之少化簡。這其實就是GIS中常說的術語:LOD(Level Of Details)細節層次模型,不同縮放級別對展現的細節程度要求是不一樣的。比如,你離着一棵樹500米,你可能只關注樹的外形和全貌,5米時,你可能關注樹有幾個樹杈,10cm時,你就會想看樹葉的紋理;
  2. 借鑑切片的思想,對數據分塊,不加載用不到的數據。這裏需要注意的是不同的縮放級別切片的內容也不一樣,對每個級別都需要重新切片。

兩個思路各有優缺點,實際我們會把兩個方案結合起來,就是現在最常用的切片方案,每個級別首先化簡,然後切片。在 Openlayers圖層詳解 裏我們在聊Openlayers的WebGLPointLayer時也提過服務器端渲染和瀏覽器端渲染各自的優劣勢:

那麼有的同學會問,我在服務器端渲染不比webgl性能高,它不香嗎?香是香,但是服務器與客戶端是1對多的關係,每個客戶端都需要服務器渲染,併發量高了,服務器垮不垮?又有小夥伴說了,切片不就是解決這個問題的嗎?對,但現在需求往往是樣式隨時會變,緩存了切片,樣式一變,又要重新切,意義不大。矢量切片出現不就是這個問題的證據麼?

所以,如果我們既能解決大數據量的問題,又能把瀏覽器端渲染的優勢融合進來,不就是一個很理想的方案嗎?Mapbox想在了我們前面,在2014年4月份就發佈了他們的方案:矢量瓦片(Vector Tiles),感興趣的童鞋們去看下他們的 initial commit

3、我們先拉回來

聊了比較理想的方案,咱們現在還是測測WebGL的極限吧,雖然2G的GeoJSON不行,我們搞一個數據量稍微小一點的數據。這裏跟童鞋們說一下:看數據量的大小,不能只看要素的數量,比如,一個100萬的點要素和10萬的線要素,哪個數據量大?稍微複雜一點的數據,一般一條線上會有幾十甚至上百上千個點,所以要素類型也需要關注。

這裏我們來一個複雜的線數據:

line

let url = 'http://localhost:8000/lines.geojson';
this.map.addSource('lines', { type: 'geojson', data: url });
this.map.addLayer({
    'id': 'lines',
    'type': 'line',
    'source': 'lines',
    'paint': {
        'line-color': 'DarkViolet',
        'line-opacity': 0.6,
        'line-width': .9
    },
    'layout': {
        'line-cap': 'round',
    }
    
});

看效果,效果還行(臺灣省的數據沒搞到,所以一片空白,各位同學見諒),

roads

但是在看到這個效果之前,我等了19秒,聽到了電腦呼呼叫,還看到了這樣的景象:

cpu usage

4、所以怎麼渲染海量數據?

通過上面的測試我們也看到了,渲染比較大量的數據,在前端WebGL渲染,一有文件大小的限制,二有渲染性能的極限。在第二節我們也討論了兩個常見的解決措施,最終覺得矢量瓦片可能是我們的救星,那矢量瓦片效果咋樣呀?最近在寫一個Shapefile轉換Vector Tile的工具,寫成之日,就是321萬線數據重現之時。

上面的代碼可以在我的Github中找到:https://github.com/QingyaFan/data-visualization

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章