作爲一名GIS開發者,你工作中一定遇到過這種問題,根據業務設計,需要在地圖上添加1萬+條數據,數據或是點、或是線、或是面。但不管哪種,當你添加到5000條時,地圖操作就會出現明顯的卡頓。當你添加超過1萬條時,數據加載就會卡頓,瀏覽器出現卡死的狀態,地圖加載後,每挪動一下地圖,都要耐心的等待上幾秒鐘。
這種交互體驗,用戶是肯定接受不了的,解決方法通常分兩種,一種是去做深入的用戶需求分析,看用戶想一次性加載這麼多數據是爲了看什麼,想看的這個東西,通過其它技術方式能不能實現。另一種就是死磕技術,研究如何提升地圖性能。我們今天只討論第二種情況。
leaflet支持兩種渲染方式,svg 和 canvas,默認是svg渲染,這樣可以兼容低版本的IE瀏覽器。canvas渲染需要IE9+,或谷歌、火狐的高版本瀏覽器。canvas比svg性能好,我自己做了簡單的測試,svg模式加載5000個圖片標記時出現的卡頓情況,用canvas模式,加載10萬條數據時纔會出現。
下面講如何完全切換到canvas模式,共兩步:
一,在初始化地圖時,設置map的 preferCanvas 屬性爲 true,代碼如下:
var map = L.map('map', {
center: [39.905963, 116.390813],
zoom: 13,
preferCanvas: true
});
這個設置只針對繼承了Path類的矢量圖層有效,包括圓點(CircleMarker)、線(Polyline)、面(Polygon)、圓(Circle)、矩形(Rectangle)。針對圖片標記(Marker)沒有作用。
二、藉助插件 Leaflet.Canvas-Markers,提升Marker的顯示性能。插件git地址:https://github.com/eJuke/Leaflet.Canvas-Markers
Leaflet.Canvas-Markers 插件
Leaflet.Canvas-Markers 插件提供了一個 L.canvasIconLayer
類,這個類是一個圖層,將 Marker 添加到這個圖層中時,這個圖層會以 canvas 方式渲染 Marker 中的圖片。
如何使用
在html中引入插件
<script src="leaflet.canvas-markers.js"></script>
創建canvasIconLayer圖層,把圖層添加到地圖,給圖層添加圖片標記。
// 創建圖層,添加到 map
var ciLayer = L.canvasIconLayer({}).addTo(map);
// 定義 Marker
var marker = L.marker([58.5578, 29.0087], {icon: icon});
// 把 Marker 添加到圖層
ciLayer.addMarker(marker);
注意
這個插件有個問題,就是地圖縮放時,添加的數據不跟着同步縮放,而是等到縮放完成後,再去縮放。這樣感覺縮放時,數據在飄着。
不過已經有人對這個問題提出瞭解決方案,並且解決了(鏈接),只是代碼一直沒有被合併。不過這都沒有關係,我們可以去用那份兒已經解決的代碼(鏈接)
解決以後的效果:
完整代碼
注意;這份代碼因爲是引用的在線地址,所以存在上文中說的縮放地圖時感覺飄的問題,
<!DOCTYPE html>
<html>
<head>
<title>leaflet-canvas-marker</title>
<meta charset="utf-8" />
<!-- 引入leafletapi -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<!-- 引入leaflet-canvas-marker插件 -->
<script src="https://unpkg.com/[email protected]"></script>
<style>
body { margin: 0; }
.map {position: absolute; height: 100%; right: 0; left: 0; }
</style>
</head>
<body>
<div class="map" id="map"></div>
<script>
var map = L.map('map',{
center: [39.905963, 116.390813],
zoom: 14,
preferCanvas: true //使用canvas模式渲染矢量圖形
});
//添加底圖
var tiles = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(map);
//使用canvas模式渲染marker
var ciLayer = L.canvasIconLayer({}).addTo(map);
var icon = L.icon({
iconUrl: 'https://ejuke.github.io/Leaflet.Canvas-Markers/examples/img/pothole.png',
iconSize: [20, 18],
iconAnchor: [10, 9]
});
for (var i = 0; i < 10000; i++) {
var lat = 39.905963 + (Math.random()-Math.random()) * 3;
var lng = 116.390813 + (Math.random()-Math.random()) * 3;
var marker = L.marker([lat, lng], { icon: icon })
.bindPopup("I Am " + i); //綁定氣泡窗口
ciLayer.addLayer(marker);
}
</script>
</body>
</html>
總結
- leaflet支持兩種渲染方式,svg 和 canvas,canvas的顯示性能要明顯優於svg。
- IE9之前版本瀏覽器不支持canvas方式渲染。
- 默認是svg方式渲染,要手動切換成canvas方式。
- 渲染方式設置成canvas後,加載矢量圖形性能會提升,加載圖片標記的效率仍然低。
- 通過Leaflet.Canvas-Markers插件來提升圖片標記的顯示效率。
- Leaflet.Canvas-Markers插件在縮放地圖時有bug,需要在github上找已經解決此bug的版本。