2022.07.27 更新:Leaflet.js 改用 v1.8.0。修正更新位置會讓 zoom 重置的問題。
本篇要解決的問題
在上一篇有寫到 跟使用者要權限 的部份,當時用的是 WebAPI 的 Geolocation。這幾天再看了一下 Leaflet 的文件,發現裡面也有跟使用者要地理位置的 locate,就花時間研讀並實作一個頁面出來。
另外,之前在寫 Google Maps API 時,有用到移動地圖中心點的功能,正好抓使用者位置後,如果使用者移動了,也需要改變地圖的中心點,就一起整理在這一篇。
本篇最後會完成的 Demo:
https://letswritetw.github.io/letswrite-leaflet-osm-locate/
原始碼部份最後一段會附上。
如果是想看怎麼用 Leaflet 建立 OpenStreetMap 地圖,這部份都寫在上一篇了,一些基本使用本篇會快速的帶過,各位捧油們有興趣的話可以先看上一篇:
OSM + Leaflet 學習筆記 1:建地圖、marker、事件、換圖層
移動中心點
參考文件:Methods for modifying map state
Leaflet 移動地圖中心點的功能有二種,主要是移動的效果有所不同。
panTo
是平行移動,flyTo
是具有縮放效果,效果可以從 Demo 頁上看差異,flyTo
把距離拉遠一點會更明顯。
另外還有一個 panBy
,可以指定移動多少 X 軸及 Y 軸的距離。
panTo、flyTo
map.panTo(latlng, [options]) map.flyTo(latlng, [options])
latlng
就是要移成中心點的緯度跟經度,可以有以下幾種寫法(文件):
map.panTo([50, 30]); map.panTo({lon: 30, lat: 50}); map.panTo({lat: 50, lng: 30}); map.panTo(L.latLng(50, 30));
options
是選填,共有 4 個參數可填(文件):
animate:Boolean; //要不要有動畫效果。 duration:Number; // 移動的時間,預設是 0.25 秒。 easeLinearity:Number; // 0-1 之間的值,1 代表線性,數字愈小曲線愈彎。 noMoveStart:Boolean; // 預設為 false。
panBy
panBy(point, [options])
point
就是填要位移多少距離,有以下二種寫法(文件):
map.panBy([200, 300]); map.panBy(L.point(200, 300));
options
跟上面的 panTo、flyTo 相同。
抓取使用者位置並讓 Marker 跟隨移動
這段其實就是在模仿我們平常手機用 Google Maps 時,在我們移動後,地圖的中心點跟顯示我們所在地的小藍圈也會跟著移動。
小藍圈的部份直接用 Adobe Ai 繪製的,就真的是一個藍圓圈包一層半透明的藍圓圈,不像 Google Maps 還有個探照燈的圖示表示朝哪邊。
抓取使用者位置
參考文件:Leaflet on Mobile、Geolocation methods
抓取使用者的位置,在 Leaflet 上就叫 locate
。
map.locate({ setView: false, // 是否讓地圖跟著移動中心點 watch: true, // 是否要一直監測使用者位置 maxZoom: 18, // 最大的縮放值 enableHighAccuracy: true, // 是否要高精準度的抓位置 timeout: 10000 // 觸發locationerror事件之前等待的毫秒數 });
可用參數的部份還有一個:maximumAge。因為看文件說明看不懂,就不列上去。
當用了 locate,使用者開啟頁面後一樣會出現確認視窗:

使用者按下「允許」,會觸發 locationfound
事件。
使用者按下「封鎖」,會觸發 locationerror
事件。
知道會觸發何種事件,就可以針對事件來做處理。
locationfound
function foundHandler() { // 這邊寫抓到使用者位置後要做什麼事 } map.on('locationfound', foundHandler);
本篇的 Demo 處理抓到位置後的事,主要就是移動 Marker,原始碼如下:
主要是用 marker.setLatLng(latlng)
來移動 Marker。
locationerror
function errorHandler() { // 這邊寫抓不位置的話要做什麼事 } map.on('locationfound', errorHandler);
本篇 Demo 是直接設一個預設的地點當中心點(動物園),並且跳一個 alert 告知使用者。
大家可以開啟 Demo 頁實測,會發現……就還是沒有 Google Maps 好看 XD~ 畢竟那是有收費的。
而且,不確定是不是因為位置一直抓不精確,所以地圖顯示的範圍常常會很大,幾乎都要顯示完一個區了~
只有偶爾幾次抓到很精準的,zoom 才會顯示到街道的大小。
本篇的範例碼,locate
時的 setView
設為 false
,因為如果 setView
為 true
,但地圖重新抓中心點時,zoom
的值也會跟著是預設值,變成使用者如果手動調過 zoom
會被蓋過去,會看見地圖一直放大又縮小,跟跳恰恰一樣,因此這邊設 setView
為 false
,接著在抓到使用者座標後,用 panTo
移動地圖的中心點。
本篇 Demo 及原始碼
最後附上本篇的 Demo 網址,及原始碼的 Github 網址。
Demo:https://letswritetw.github.io/letswrite-leaflet-osm-locate/
GitHub:https://github.com/letswritetw/letswrite-leaflet-osm-locate
OSM + Leaflet 學習筆記系列
OSM + Leaflet 學習筆記 1:建地圖、marker、事件、換圖層
OSM + Leaflet 學習筆記 2:移動中心點、抓目前地點
OSM + Leaflet 學習筆記 3:定位、全螢幕、小地圖、列印、客製選單

