前言

最近剛好要更新地圖應用。先前是直接使用 Mapbox ,但覺得它的 Marker 操作起來不是很彈性。因緣際會下聽說了 Leaflet ,就來試看看吧。

維基百科是這樣說的。

Leaflet是一個開源的JavaScript庫,用於構建Web地圖應用。首次發布於2011年,2它支持大多數移動和桌面平台,支持HTML5和CSS3。

主要內容

安裝方式

本文撰寫時會以 CDN 的方式引入 Leaflet.js,實際使用時筆者是會使用套件管理工具進行安裝。 安裝方式:

1yarn add leaflet

使用 CDN 的方式:

1 <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
2   integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
3   crossorigin=""/>
4   
5<!-- Make sure you put this AFTER Leaflet's CSS -->
6 <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
7   integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
8   crossorigin=""></script>

起手式

在網頁中加入

1<div id="map" style="width:95vw;height:95vh" />

初始化地圖

1var map = L.map('map').setView([34.985851028839406, 135.75788488621308], 10);
2L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}',
3  {
4    foo: 'bar', 
5    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
6  }).addTo(map);
我們的第一張地圖

我們的第一張地圖

如果我們想要使用 Mapbox 的圖資,在已取得存取金鑰之後(Access Toekn),可在建立 titleLayer 時改用下列方式初始化。

 1var map = L.map('map').setView([34.985851028839406, 135.75788488621308], 10);
 2L.tileLayer(''https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}',
 3  {
 4    attribution: '&copy; <a href="https://www.mapbox.com/about/maps/">Mapbox</a> contributors'
 5    maxZoom: 18,
 6    zoomOffset: -1,
 7    tileSize: 512,
 8    id: 'mapbox/streets-v11',
 9    accessToken: token
10  }).addTo(map);
使用 Mapbox 圖資

使用 Mapbox 圖資

如果想要移除預設的 zoom controller 可以在初始化的時候加上 zoomControl: false

1var map = L.map('map', {zoomControl: false}).setView([34.985851028839406, 135.75788488621308], 10);

加上 Marker

在 Leaflet 中加上 marker 就跟呼吸一樣自然。

1L.marker([35.04074994371372, 135.72932367775914]).addTo(map);
2L.marker([34.97374817523019, 135.77195253085293]).addTo(map);
3L.marker([34.99936852552379, 135.7854861479551]).addTo(map);
加上 marker

加上 marker

如果想要改變樣式,可以透過 icon 或是 iconDiv 來更改。

 1var myIcon = L.icon({
 2    iconUrl: 'marker.png',
 3    iconSize: [100, 95],
 4    iconAnchor: [22, 94],
 5    popupAnchor: [-3, -76],
 6    shadowUrl: 'my-icon-shadow.png',
 7    shadowSize: [68, 95],
 8    shadowAnchor: [22, 94]
 9});
10L.marker([34.70432671595862, 135.50096236284378], {
11	icon: myIcon
12}).addTo(map);
1var myDivIcon = L.divIcon({
2    className:'my-div-icon-wrapper',
3    html:`<div>這是 Div Icon </div>`
4});
5L.marker([34.68985107822455, 135.5253549268327], {
6	icon: myDivIcon
7}).addTo(map);
1.my-div-icon-wrapper div{
2    width: 100px;
3    background-color: #060390;
4    color: #eee;
5    text-align: center;
6}
加上 marker

加上 marker

來畫線吧

1var latlngs = [
2    [35.02537491062854, 135.7438607946139],
3    [34.88948810597932, 135.8076289149232],
4    [34.961035819215525, 135.65613226663768],
5    [34.976863645786004, 135.82695459531024],
6    [34.88036360232042, 135.7002729085305],
7    [35.02537491062854, 135.7438607946139],
8];
9L.polyline(latlngs, {color: 'red'}).addTo(map);
來個封印陣吧!

來個封印陣吧!

群組化並加上控制項

我們可以把想要歸在一起的東西放到同一個群組,這樣在接下來要分層顯示的時候,會更簡便一些。

讓我們稍微調整一下程式碼。

 1...
 2
 3let layer1 = L.layerGroup([
 4    L.marker([35.04074994371372, 135.72932367775914]),
 5    L.marker([34.97374817523019, 135.77195253085293]),
 6    L.marker([34.99936852552379, 135.7854861479551])
 7]).addTo(map);
 8
 9...
10
11let layer2 = L.layerGroup([
12    L.marker([34.70432671595862, 135.50096236284378], { icon: myIcon }),
13    L.marker([34.68985107822455, 135.5253549268327], { icon: myDivIcon })
14]).addTo(map);
15
16...
17
18let layer3= L.layerGroup([
19    L.polyline(latlngs, {color: 'red'})
20]).addTo(map);

將我們群組化後的 Layer 加入控制項中。

1let controller = L.control.layers().addTo(map);
2controller.addOverlay(layer1,"Marker");
3controller.addOverlay(layer2,"自定的Marker");
4controller.addOverlay(layer3,"封印陣");
5controller.expand();
加入控制項

加入控制項

補充一下,如果想移除各個 Layer 的話可以透過下列方式,移除

 1map.value.eachLayer((layer) => {
 2    if (layer instanceof L.Marker) {
 3        map.value.removeLayer(layer);
 4    }
 5});
 6
 7
 8// or 
 9
10layer1.remove();

20210808 新增 - geoJSON Layer

測試資料可以到政府開放資料平台取得。

 1
 2let data = {"type":"FeatureCollection", "features": [
 3"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[121.543841724,25.0449066970000,...................... ]]]
 4]}
 5
 6function onEachFeature(feature, layer) {
 7  if (feature.properties && feature.properties.TOWNNAME) {
 8    layer.bindPopup(feature.properties.TOWNNAME);
 9  }
10}
11
12L.geoJSON(data, {
13    onEachFeature: onEachFeature,
14    filter: function(feature, layer) {
15        return feature.properties.TOWNNAME == '大安區';
16    },
17    style: function(feature) {
18        switch (feature.properties.TOWNNAME) {
19            case '大安區': return {color: "#00ff00",weight:1};
20            default: return {color: "#333333",weight:1,opacity:0.5 };
21        }
22    }
23}).addTo(map);
使用 geolayer

使用 geolayer

成果

小結

使用 Leaflet 之後,不管是在操作 Marker 還是要建立 Path 都變得更加容易了。只能說是相見恨晚!

參考連結