2022.07.26 更新:建立地圖的 function 改用 Leaflet.js v1.8.0 版
本篇要解決的問題
之前有寫過一系列的 Google Maps API 學習筆記。Google Maps 好用,但過了一定的額度會收費,當時就有人留言問說免費地圖的事,有留上了心。
原本是直接找 OpenStreetMap 的 API,後來看到文件上回來的都是用 XML,實在是懶得處理轉 JSON 這段。之後幸運地找到一個可以接 OpenStreetMap 的 Leaflet,一個用 JavaScript 接 API 的開源碼,就翻了一下文件,整理成這篇。
本篇會示範的功能如下:
- 跟使用者請求地點,建立地圖
- 放置 + 客製 marker
- Popup
- Tooltip
- Map click event
- 外部 zoom in、zoom out
- 改變地圖樣式
本篇主要參考文件:Leaflet Quick Start Guide
後續各段會用到的參考文件,將寫在各段之中。
本篇最後會完成的 Demo:
https://letswritetw.github.io/letswrite-leaflet-osm-basic/
請求地點,建立地圖
跟 Google Maps API 一樣,Leaflet 在建立地圖時需要一個中心點。
跟使用者請求所在位置座的座標,需要使用者同意,因此也要先預設一個當使用者拒絕時,或是所擁有的裝置不支援提供所在座標時的地點。
本篇預設地點設為台北市立動物園~ 想去看水豚君啊~~~
關於找地點的座標,August 用的是比較簡單的方法,如果有人有更好的方法歡迎留言提供。
首先進到 Google Maps 的網站,搜尋想要知道座標的地點,我們這邊搜尋「動物園」後,選到動物園,接著按下資料卡片的「分享」:

接著點擊「複製連結」:

然後把複製的網址貼到瀏覽器上打開,短網址會回復成原網址,就能從網址中看見座標,像這樣:

這是 August 知道不用接任何 API 就能找到一個地點座標的方式。
跟使用者要權限
當我們跟使用者要權限時,使用者會看到這樣的請求:

當使用者按下了「允許」,我們就可以得到使用者的座標,程式碼如下:
建立地圖
不管有沒有取到使用者的所在位置,都一樣可以建立 OpenStreepMap 的地圖。
首先先引用 CSS、JS:
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" /> <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
接著在我們要放置地圖的地方,放上一個空 div 並帶上我們指定的 id:
<div id="map"></div>
下一步,給我們的 div 一個高度:
#map { height: 180px; }
高度的部份本篇的 Demo 是用 50vh,實際應用時依各頁面的狀況再作修改。
最後就是用 Leaflet 來建立地圖:
Options 的部份可自行參考 文件,這邊僅列出 August 覺得會用到的。
L.tileLayer
這個是指地圖要讀取哪一個樣式,文件中的預設樣式就是這個:
https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
少了 tileLayer
地圖會是一片灰。
開啟頁面後,地圖就出來了:

放置 Marker
放置 marker 的方式就是新增一個出來後,add 到 map 裡,程式碼如下:
center
就是要放置的座標。
預設的 Maker 樣式如下:

客製 Maker 圖示
Marker 可以用客製的 icon,如下:
我們這邊多放置幾個來看:

一次放置多個可以用迴圈,Demo 的原始檔會附上。
Marker 加上 Popup
Marker 能加上 Popup 跟 Tooltip。
Popup 可以預設打開。
openPopup()
就是打開 Popup。
Popup 長這個樣子:

Marker 加上 Tooltip
Tooltip 就是我們常見的 Tooltip(嗯?有寫跟沒寫一樣)。
一樣可以預設要不要打開,也可以設定顯示的位置:
Tooltip 長這樣:

Map 點擊事件
Leaflet 可以監聽 Map 的點擊。
在官方的範例就有示範點擊地圖後,加上一個 Popup 寫著此處座標,這邊 August 改寫一下:
隨便點擊地可上任一地方,就會出現寫著座標的 Popup:

zoom in, zoom out
除了地圖上預設的功能鍵,也可以用地圖外的按鈕,用 function 執行 zoom in、zoom out。
map.zoomIn(1); map.zoomOut(1);
數字是一次要 zoom 多少,實際測了一下,zoom 的值是 0 – 18。
0 是世界地圖,18 就是到街景了。
改變地圖樣式 Layer
參考:How to change base layer using JS and leaflet layers control
除了預設的地圖樣式,還有蠻多種樣式可以使用的,在 Leaflet Provider Demo 上可以看到多種,大部份也都有附上 Layer 的網址。
不過,有些不確定是否有收費,因為看到需要 token。
改變地圖樣式的按鈕,可以放在地圖之中,也可以在地圖之外放按鈕控制。
在地圖之內
在地圖之內,總覺得樣式有點陽春 XD~
但勝在方便。
把控制選項放在地圖上,長這樣:

Hover 時會秀出選單:

實際使用,覺得切換的時間有點久,大家看 Demo 時要等一下。
最喜歡的是深色的一款 Stadia.AlidadeSmoothDark,不過這款免費使用下有限制,可以看 官網 說明。
在地圖之外
改變 Layer 主要是這行:
L.tileLayer('layer 的 url').addTo(map);
因此要用地圖外面的按鈕來切換地圖的樣式,只需要寫 click 時執行上面那行就行。
本篇 Demo 及原始碼
最後附上本篇的 Demo 網址,及原始碼的 Github 網址。
Demo:https://letswritetw.github.io/letswrite-leaflet-osm-basic/
GitHub:https://github.com/letswritetw/letswrite-leaflet-osm-basic
OSM + Leaflet 學習筆記系列
OSM + Leaflet 學習筆記 1:建地圖、marker、事件、換圖層
OSM + Leaflet 學習筆記 2:移動中心點、抓目前地點
OSM + Leaflet 學習筆記 3:定位、全螢幕、小地圖、列印、客製選單


[…] 跟使用者要權限 的部份,當時用的是 WebAPI 的 Geolocation。這幾天再看了一下 Leaflet […]
使用官方推薦的 unpkg cdn 無法在 Github page 成功顯示後來換個 cdn 就可以了
https://leafletjs.com/download.html
[…] OSM + Leaflet 學習筆記 1:建地圖、marker、事件、換圖層 […]