前言
最近剛好要更新地圖應用。先前是直接使用 Mapbox ,但覺得它的 Marker 操作起來不是很彈性。因緣際會下聽說了 Leaflet ,就來試看看吧。
維基百科是這樣說的。
Leaflet是一個開源的JavaScript庫,用於構建Web地圖應用。首次發布於2011年,2它支持大多數移動和桌面平台,支持HTML5和CSS3。
主要內容
安裝方式
本文撰寫時會以 CDN 的方式引入 Leaflet.js,實際使用時筆者是會使用套件管理工具進行安裝。
安裝方式:
使用 CDN 的方式:
1
2
3
4
5
6
7
8
| <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/>
<!-- Make sure you put this AFTER Leaflet's CSS -->
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
|
起手式
在網頁中加入
1
| <div id="map" style="width:95vw;height:95vh" />
|
初始化地圖
1
2
3
4
5
6
| var map = L.map('map').setView([34.985851028839406, 135.75788488621308], 10);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}',
{
foo: 'bar',
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);
|
如果我們想要使用 Mapbox 的圖資,在已取得存取金鑰之後(Access Toekn),可在建立 titleLayer 時改用下列方式初始化。
1
2
3
4
5
6
7
8
9
10
| var map = L.map('map').setView([34.985851028839406, 135.75788488621308], 10);
L.tileLayer(''https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}',
{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> contributors'
maxZoom: 18,
zoomOffset: -1,
tileSize: 512,
id: 'mapbox/streets-v11',
accessToken: token
}).addTo(map);
|
如果想要移除預設的 zoom controller 可以在初始化的時候加上 zoomControl: false
1
| var map = L.map('map', {zoomControl: false}).setView([34.985851028839406, 135.75788488621308], 10);
|
加上 Marker
在 Leaflet 中加上 marker 就跟呼吸一樣自然。
1
2
3
| L.marker([35.04074994371372, 135.72932367775914]).addTo(map);
L.marker([34.97374817523019, 135.77195253085293]).addTo(map);
L.marker([34.99936852552379, 135.7854861479551]).addTo(map);
|
如果想要改變樣式,可以透過 icon
或是 iconDiv
來更改。
1
2
3
4
5
6
7
8
9
10
11
12
| var myIcon = L.icon({
iconUrl: 'marker.png',
iconSize: [100, 95],
iconAnchor: [22, 94],
popupAnchor: [-3, -76],
shadowUrl: 'my-icon-shadow.png',
shadowSize: [68, 95],
shadowAnchor: [22, 94]
});
L.marker([34.70432671595862, 135.50096236284378], {
icon: myIcon
}).addTo(map);
|
1
2
3
4
5
6
7
| var myDivIcon = L.divIcon({
className:'my-div-icon-wrapper',
html:`<div>這是 Div Icon </div>`
});
L.marker([34.68985107822455, 135.5253549268327], {
icon: myDivIcon
}).addTo(map);
|
1
2
3
4
5
6
| .my-div-icon-wrapper div{
width: 100px;
background-color: #060390;
color: #eee;
text-align: center;
}
|
來畫線吧
1
2
3
4
5
6
7
8
9
| var latlngs = [
[35.02537491062854, 135.7438607946139],
[34.88948810597932, 135.8076289149232],
[34.961035819215525, 135.65613226663768],
[34.976863645786004, 135.82695459531024],
[34.88036360232042, 135.7002729085305],
[35.02537491062854, 135.7438607946139],
];
L.polyline(latlngs, {color: 'red'}).addTo(map);
|
群組化並加上控制項
我們可以把想要歸在一起的東西放到同一個群組,這樣在接下來要分層顯示的時候,會更簡便一些。
讓我們稍微調整一下程式碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| ...
let layer1 = L.layerGroup([
L.marker([35.04074994371372, 135.72932367775914]),
L.marker([34.97374817523019, 135.77195253085293]),
L.marker([34.99936852552379, 135.7854861479551])
]).addTo(map);
...
let layer2 = L.layerGroup([
L.marker([34.70432671595862, 135.50096236284378], { icon: myIcon }),
L.marker([34.68985107822455, 135.5253549268327], { icon: myDivIcon })
]).addTo(map);
...
let layer3= L.layerGroup([
L.polyline(latlngs, {color: 'red'})
]).addTo(map);
|
將我們群組化後的 Layer 加入控制項中。
1
2
3
4
5
| let controller = L.control.layers().addTo(map);
controller.addOverlay(layer1,"Marker");
controller.addOverlay(layer2,"自定的Marker");
controller.addOverlay(layer3,"封印陣");
controller.expand();
|
補充一下,如果想移除各個 Layer 的話可以透過下列方式,移除
1
2
3
4
5
6
7
8
9
10
| map.value.eachLayer((layer) => {
if (layer instanceof L.Marker) {
map.value.removeLayer(layer);
}
});
// or
layer1.remove();
|
20210808 新增 - geoJSON Layer
測試資料可以到政府開放資料平台取得。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
let data = {"type":"FeatureCollection", "features": [
"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[121.543841724,25.0449066970000,...................... ]]]
]}
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.TOWNNAME) {
layer.bindPopup(feature.properties.TOWNNAME);
}
}
L.geoJSON(data, {
onEachFeature: onEachFeature,
filter: function(feature, layer) {
return feature.properties.TOWNNAME == '大安區';
},
style: function(feature) {
switch (feature.properties.TOWNNAME) {
case '大安區': return {color: "#00ff00",weight:1};
default: return {color: "#333333",weight:1,opacity:0.5 };
}
}
}).addTo(map);
|
成果
小結
使用 Leaflet 之後,不管是在操作 Marker 還是要建立 Path 都變得更加容易了。只能說是相見恨晚!
參考連結