本篇會寫兩個用 Google Maps API 會遇到的狀況,就是目前使用者的所在位置,以及所在位置到目的地的距離。
目前所在位置
抓使用者目前所在位置,用的是瀏覽器本身的 geolocation。
在使用 navigator.geolocation
時,有 2 個步驟:
- 確認使用者的裝置支援
navigator.geolocation
- 跟使用者要索取目前位置的權限
確認支援 geolocation
程式碼如下:
if(navigator.geolocation) { // 執行要權限的function } else { alert('Sorry, 你的裝置不支援地理位置功能。') }
跟使用者要位置的權限
基本上所在位置是隱私的一部份,所以要拿使用者所在位置時,各瀏覽器一定會在使用者允許的狀態下才執行。
會跟使用者要權限的狀況,我們一般在操作 Google Map 的頁面或 App 時就會看到,像這樣:
要注意的是,要位置資訊權限的部份,只能在 https 下執行,如果網址是 http 就無法。
要位置權限的 code 在 MDN:地理位置定位 (Geolocation) 這邊就寫的很完整了,本篇這段就做個簡單的整理:
當使用者允許後,回傳的資料如下:
latitude、longitude,這 2 個值就是經緯度。
計算到各點距離 Distance Matrix Service
計算一個點到其它點的距離,在 Google Maps API 上的功能就叫 Distance Matrix Service。
要使用 Distance Matrix Service,必須先到 GCP 上開啟 API 的權限。
開啟權限
進到 Google Cloud Platform Console 的頁面,接著選取要開通 Distance Matrix API 權限的專案,就會看見後台介面的上面有一個「啟用 API 和服務」,點下去後會進到 Google API 的頁面:
在搜尋框中搜尋 Distance Matrix API,就會看見有一項結果:
按下後,進到 Distance Matrix API 的介紹頁面,再按下「啟用」:
啟用後,就可以使用 Distance Matrix API 了。
Distance Matrix API 限制
Google Maps API 每月有 200 美金的額度,超過後就會收費,用多少算多少。
一些限制在官方文件中有提到,比較要注意的是這點:
Maximum of 25 origins and 25 destinations per server-side request
Pricing and policies
根據本人實際使用的經驗,這句白話就是,每調用一次 API 去計算一個點到其它點的距離時,最多就是計算 25 個點的距離,超過 25 個點就會失敗。
使用 Distance Matrix API
以下官方文件上的範例:
這邊說明一下參數的意思,下一段會示範從使用者所在地,去計算與其它點的距離當實際範例。
origins
就是起點,原始點,用起點去抓與 destinations 那些點的距離,下一段的範例中就會是使用者的所在地點。
destinations
要計算距離的點,下一段的範例中會先設好市政府附近的 5 個點,然後抓與所在地的距離。
travelMode
交通方式,不同的交通方式會回傳不同的所需時間,有以下 4 個值:
- DRIVING 開車,預設值
- BICYCLING 自行車
- TRANSIT 大眾運輸
- WALKING 走路
unitSystem
計算距離的單位,有以下 2 個值:
- METRIC 公里,預設值
- IMPERIAL 哩
avoidHighways、avoidTolls
是否避開高速公路、是否避開收費路線
API 回傳的值
Distance Matrix API 在 callback 會回傳的資料如下:
rows 是一個陣列,origins 裡有幾個值,rows 就會有幾個。API 會把 origins 裡的地點一個個去跟 destinations 陣列裡的每一個地點去計算距離。
跟每一個地點的距離,會回傳距離、到達所需時間。還很貼心的分成數值跟文字,這樣在排列的時候,就可以用距離/時間去排列。
實際應用:所在地與其它地點的距離
本篇接下來會寫一個範例,就是跟使用者要完所在地的經緯度後,呼 API 去計算市府附近 5 個地點的距離,最後會附上原始碼的網址。
跟使用者要所在地的經緯度,前面幾段就寫好了,這邊接著寫要完經緯度後做的事。
首先,就是把所在地經緯度設成 origins:
let originPosition = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
接著,把設定好的 5 個地點,他們的經緯度 push 進 destinations 裡:
// 5個地點的資料在features裡 let destinations = []; Array.prototype.forEach.call(features, f => { destinations.push(new google.maps.LatLng(f.geometry.coordinates[0], f.geometry.coordinates[1])); });
API 的 callback,就是把收回來的資料,依序塞進 5 個點的資料中:
function callback(response, status) { for(let i = 0, len = features.length; i < len; i++) { features[i].properties.distance = response.rows[0].elements[i].distance.value; features[i].properties.distance_text = response.rows[0].elements[i].distance.text; features[i].properties.distance_time = response.rows[0].elements[i].duration.text; } }
最後把 features 的 5 個地點資料,再按照距離排序就行了:
features = features.sort((a, b) => { return a.properties.distance > b.properties.distance ? 1 : -1; });
本篇配合 Vue.js,加上 Bootstrap 的 UI,完成後看到的截圖如下:
範例的原始碼也放在 GitHub上了,歡迎取用:
https://github.com/letswritetw/letswrite-google-map-api-5