[筆記]Web地圖開發工作坊


Posted by yuhantaiwan on 2020-02-16

by 廖洧杰 / 六角學院校長

2020/02/07

共筆文件:Leaflet + OpenStreetMap (OSM) 特訓班

直播錄影:Leaflet + OpenStreetMap 地圖應用開發


前言

Leaflet (Js 框架)

Leaflet 是一套開放原始碼的輕量級 JavaScript 網頁地圖函式庫。主要特色:簡單、方便、跨平台

  • 載入圖資(地圖資料)
  • 標示點(Maker)
  • 官網

OpenStreetMap (圖資--地圖資料)

OpenStreetMap (開放街圖,簡稱OSM) 採用類似Wiki的協作編輯以及開放的授權與格式,因而被稱之為「維基版的地圖」,也被視為Google最強大的競爭者。

補充資料:OpenStreetMap 台灣

地圖圖層概念

地圖由多個圖層組成,又每個圖層由多個圖磚(PNG 圖片)所組成

補充資料:圖層示意圖

實作

1. 載入地圖

先載入其 css 與 js

var map = L.map('map', {
    center: [22.604799,120.2976256],
    zoom: 3
});
// 設定地圖,把map定位在 #map,先定位在 center 座標,其縮放等級為 3

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
  • L 表示 Leaflet的所有應用服務
  • 使用 map 這個函式,傳入兩個參數:1. id為map的字串;2. 物件{地圖中心:[緯度, 經度], 縮放等級}
  • tileLayer 內放入要用誰的圖資

2. 建立 UI Layer Marker

建立圖標 (Marker)

L.marker([22.604799,120.2976256]).addTo(map)
    .bindPopup('<h1>測試藥局</h1><p>成人口罩:50<br>兒童口罩:50</p>')
    .openPopup();
// 我要加上一個 marker,並設定他的座標,同時將這個座標放入對應的地圖裡
  • 把圖標(Marker)加入圖層中
  • 彈跳方框(bindPopup)內可放入 HTML 標籤
  • openPopup => 滑鼠滑過去就會顯示 Popup

改變 Marker 顏色

https://github.com/pointhi/leaflet-color-markers

var greenIcon = new L.Icon({
  iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
  shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34],
  shadowSize: [41, 41]
});

L.marker([51.5, -0.09], {icon: greenIcon}).addTo(map);

兩個點以上 Marker

L.marker([22.604799,120.2976256], {icon: greenIcon}).addTo(map)
    .bindPopup('<h1>測試藥局</h1><p>成人口罩:50<br>兒童口罩:50</p>')

L.marker([22.6066728,120.3015429]).addTo(map)
    .bindPopup('<h1>IKEA</h1><p>成人口罩:50<br>兒童口罩:50</p>')

建立兩個 marker 物件

利用for迴圈建立多個 Marker

var data = [
  {'name':'軟體園區',lat:22.604799,lng:120.2976256},
  {'name':'ikea',lat:22.6066728,lng:120.3015429}
]
for(var i =0;data.length>i;i++){
  L.marker([data[i].lat,data[i].lng], {icon: greenIcon}).addTo(map)
    .bindPopup('<h1>'+ data[i].name +'</h1>')
}

效能處理

1.載入額外的Js插件 Leaflet.markercluster => 讓 Marker 群組化

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/MarkerCluster.css"></link> 
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/MarkerCluster.Default.css"></link> 

<div id="map"></div>

<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/leaflet.markercluster.js"></script>

2.新增一圖層,這圖層專門放 Marker 群組

var markers = new L.MarkerClusterGroup().addTo(map);;

3.在該圖層上放入各個 Marker

for(let i =0;data.length>i;i++){
  console.log(data[i].name)
  markers.addLayer(L.marker([data[i].lat,data[i].lng], {icon: greenIcon}));
// add more markers here...
  // L.marker().addTo(map)
  //   )
}
map.addLayer(markers);

3. 載入真實資料

var markers = new L.MarkerClusterGroup().addTo(map);;

// 開啟一個網路請求
var xhr = new XMLHttpRequest();
// 準備跟某伺服器要什麼資料
xhr.open("get","https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json");
// 執行要資料的動作
xhr.send();
// 當資料回傳時,下面語法就會自動觸發
xhr.onload = function(){
 // 把字串String轉成物件陣列的Json格式,我要的是features內的陣列資料
 var data = JSON.parse(xhr.responseText).features
 // 依序把 marker 放入圖層內
 for(let i =0;data.length>i;i++){ markers.addLayer(L.marker([data[i].geometry.coordinates[1],data[i].geometry.coordinates[0]], {icon: greenIcon}).bindPopup(data[i].properties.name));
 }
 map.addLayer(markers);
}
  • ajax撈回來的資料都是字串String格式,所以一定要做 JSON.parse

4. 下if判斷式

下判斷,若無剩餘口罩,就顯示為紅色Marker,若還有則是綠色Marker

var map = L.map('map', {
    center: [22.604799,120.2976256],
    zoom: 16
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var greenIcon = new L.Icon({
  iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
  shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34],
  shadowSize: [41, 41]
});
var redIcon = new L.Icon({
  iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png',
  shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34],
  shadowSize: [41, 41]
});

var markers = new L.MarkerClusterGroup().addTo(map);;

var xhr = new XMLHttpRequest();
xhr.open("get","https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json");
xhr.send();
xhr.onload = function(){
 var data = JSON.parse(xhr.responseText).features
 for(let i =0;data.length>i;i++){
  var mask;
 if(data[i].properties.mask_adult == 0){
   mask = redIcon;
 }else{
   mask = greenIcon;
 } markers.addLayer(L.marker([data[i].geometry.coordinates[1],data[i].geometry.coordinates[0]], {icon: mask}).bindPopup('<h1>'+data[i].properties.name+'</h1>'+'<p>成人口罩數量'+data[i].properties.mask_adult+'</p>'));
// add more markers here...
  // L.marker().addTo(map)
  //   )
 }
 map.addLayer(markers);
}

5. Geolocation (地理位置定位)

HTML5 提供了 Geolocation API 讓使用者可以由 Web Apps 取得目前的位置。而基於隱私權的考量,這些 Web Apps 均必須取得使用者的許可之後,才能發佈位置資訊。

參考資料:MDN Web APIs-Geolocation
參考資料:認識 HTML5 Geolocation API
參考資料:[30apis] Day 2 : Google Map Geolocation API

資料參考

額外補充


#w3HexSchool #線上直播







Related Posts

loading畫面 skeleton

loading畫面 skeleton

P/NP 問題(P versus NP problem)

P/NP 問題(P versus NP problem)

 Day 171

Day 171


Comments