實際應用中,經常會出現海量圖層數據導致的頁面性能下降的問題,這裏我提供幾個思路,今天先從Layer層來解決好了。
我們知道,Leaflet支持svg和canvas兩種渲染器。正常來說,svg渲染適合少量的,實時配置的動態活躍圖層,canvas適合大數據量的靜態圖層(兩者都支持圖層響應),兩者在地圖zoom情況下就存在一定區別。默認情況下,Path和Layer層使用svg渲染。
出現性能下降的情況,主要還是由於過多的svg圖層疊加導致,因爲CircleMarker無法自定義圖標,大家自然而然的去選擇Maker圖層進行渲染,而這類圖層默認都是使用svg,優化Marker便是最簡單粗暴的方法了。
以下是優化步驟:
首先,Leaflet原生是不支持Marker使用canvas渲染的,因此我們需要對CircleMarker進行擴展,讓其支持自定義圖標,這裏我就不展開說了,直接給大家推介插件(我還是建議自己去寫)leaflet-canvas-markers 擴展完後,可以根據其案例使用canvasMarker,但問題是,該工具(或者說我們自己拓展的CircleMarker),是需要將Path默認設置爲canvas才能渲染,既preferCanvas: true。這種全局性的設置我是非常不建議的,假設你地圖內存在Path類的動畫(如飛線),或多或少會影響到。所以這時我們需要在不使用preferCanvas的情況下,單獨控制L.canvasMarker,並歸類至自定義Pane(用於控制層級),關於Pane的理解,大家可以看這裏
- 所以,在批量渲染L.canvasMarker之前,我們先創建一個Pane,並設置其層級(避免被svg覆蓋,可根據業務隨時控制):
this.poiPane = this.map.createPane("poi");
this.poiPane.style.zIndex = 450;
- Pane創建後,我們開始創建統一的渲染器,並設置該渲染器的Pane:
const poiRender = L.canvas({
pane: "poi"
});
- 之後給每個新創建的L.canvasMarker指定渲染器:
// 循環內
L.canvasMarker(latLng, {
radius: 18,
img: {
url: iconUrl,
size: iconSize ? iconSize : [36, 36],
popupAnchor: [0, 0]
},
renderer: poiRender
})
之後只要添加到你的LayerGroup或map上就可以了。
---------------------------------------------------分割線-----------------------------------------------------
這裏需要注意,千萬不要在創建L.canvasMarker時創建L.canvas,如
L.canvasMarker(latLng, {
...
renderer: L.canvas()
})
這樣會導致每個圖標對應獨立的渲染器,地圖應用會變得更卡(負優化)。
完成以上步驟,我們的圖標類圖層性能將得到質的飛躍。
等有時間,再和大家分享更多有效的優化方案。
**轉載請務必標註作者Banterise,謝謝。 **