Google Maps API - 顯示海拔高度

除了基本的地圖使用,Google Maps API 也有提供海拔高度的服務,雖然在地形圖的檢視模式下,可以看到山脈的高低起伏,但海拔高度服務卻能查詢某個位置的高度資料,這個服務目前常見於一些導航或運動類的應用程式 ( 現在其實不少偵測高度的裝置是使用氣壓計來量測 )。

啟用 Google Maps Elevation API

要使用海拔高度服務,首先要啟用 Google Maps Elevation API,前往 Google Console,選擇和自己的 Google Maps JavaScript API 同樣的專案,進入專案後點選「啟用 API 和服務」。

進入後搜尋 Google Maps Elevation API,搜尋到了之後就將其啟用。

依據 Google 的限制規範,Google Maps Elevation API 的標準方案 ( 免費版 ) 每天可以有 2500 個免費 request,每個秒可以有 50 個 request,而每個 request 可以有 512 個位置,此外若使用 ElevationService,Google 也有限制不得用於 Google 地圖以外的地方,如果是開發應用程式服務,也必須標註相關使用條款與隱私權政策。

顯示地形圖

回顧 Google Maps (2) - 使用地圖與基本設定 ,只要將地圖的 mapTypeId 屬性修改為 terrain,就能在地圖上同時顯示街道與地形,接下的範例就會先把地圖變更為地形圖模式。( 其實也不見得要用地形圖,只是覺得如果偵測海拔高度,用地形圖比較應景 )

範例:Google 地圖顯示地形

var map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10,
    center: {
      lat: 25.0336962,
      lng: 121.5643673
    },
    mapTypeId:'terrain' //設定為'terrain'
  });
}

如何使用

使用海拔高度前,要先宣告 ElevationService,宣告的方法很簡單,一行程式碼就搞定。

var elevator = new google.maps.ElevationService;

宣告後,就能使用 callback 的方法,這裡有兩種方法可以使用:

  • getElevationForLocations():位置高度要求,指定一個或多個位置然後回傳對應高度。
  • getElevationAlongPath():路徑高度要求,指定一段路徑上的樣本數,回傳對應高度。

再來就看看回傳的內容,包含一組 ElevationStatus 物件和 ElevationResult 物件,ElevationStatus 表示呼叫高度服務後的狀態,總共有五種代碼狀態,基本上只要是 OK 就表示呼叫成功。

  • OK:指出服務要求成功
  • INVALID_REQUEST:指出服務要求的格式錯誤
  • OVER_QUERY_LIMIT:指出要求者已超過配額
  • REQUEST_DENIED:指出服務沒有完成要求,原因可能是因為參數無效
  • UNKNOWN_ERROR:指出不明錯誤

呼叫成功後,callback 內的函式變數 results 就包含 ElevationResult 物件,ElevationResult 有三個元素,這也是到時候結果要顯示的內容。

  • location:正在計算高度資料的地點,回傳經緯度。
  • elevation:該位置的海拔高度 ( 以公尺為單位 )。
  • resolution:以內插計算高度的兩個資料點之間的最大距離 ( 以公尺為單位,如果解析度為未知,則不會有此屬性 )。

顯示位置上的海拔高度 ( getElevationForLocations() )

getElevationForLocations() 的用法:

getElevationForLocations({
  locations[]: LatLng
},callback(results, status));

下面這段程式碼,首先使用addListener監聽 map 的滑鼠點擊事件,在點擊的當下,取得滑鼠的經緯度,接著把經緯度拋給 ElevationService,透過 getElevationForLocations() 獲得該經緯度的海拔高度,並顯示在瀏覽器的 console 裏頭,以下方的例子,當我點擊「松山文創園區」,就能看到它的海拔高度約為 11.186 公尺。

範例:Google 地圖顯示某個位置的海拔高度

var map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    zoom: 13,
    center: {
      lat: 25.0336962,
      lng: 121.5643673
    },
    mapTypeId: 'terrain'
  });

  var elevator = new google.maps.ElevationService;

  map.addListener('click', function(event) {
    displayLocationElevation(event.latLng, elevator);
  });

  function displayLocationElevation(location, elevator) {
    elevator.getElevationForLocations({
      'locations': [location]
    }, function(results, status) {
      console.log(results, status);
    });
  }
}

如果不想用瀏覽器的 console 顯示,也可以使用 Google 地圖的資訊視窗 infowindow 來顯示滑鼠點擊地點的海拔高度,下面的例子在地圖上先宣告一個 infowindow,然後在滑鼠點擊的當下,由results[0].location取的經緯度,由results[0].elevation取得海拔高度,並轉換為小數點兩位的數字,最後透過 infowindow 呈現。

範例:Google 地圖資訊視窗某個位置的海拔高度

var map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    zoom: 13,
    center: {
      lat: 25.0336962,
      lng: 121.5643673
    },
    mapTypeId: 'terrain'
  });

  var elevator = new google.maps.ElevationService;
  var infowindow = new google.maps.InfoWindow();

  map.addListener('click', function(event) {
    displayLocationElevation(event.latLng, elevator);
  });

  function displayLocationElevation(location, elevator) {
    elevator.getElevationForLocations({
      'locations': [location]
    }, function(results, status) {
      var coordinate = {
        lat: results[0].location.lat(),
        lng: results[0].location.lng()
      };
      var elevation = Math.round(results[0].elevation * 100) / 100;
      infowindow.setPosition(coordinate);
      infowindow.setContent('<h2>海拔:' + elevation + ' 公尺</h2>');
      infowindow.open(map);
    });
  }
}

顯示路徑上的海拔高度 ( getElevationAlongPath() )

getElevationAlongPath() 的用法:

getElevationAlongPath({
  path[]: LatLng,
  samples: Number
},callback(results, status));

getElevationAlongPath() 顧名思義就是沿著一個形狀的海拔高度,所以要先在地圖上繪製一段折線 ( 參考 Google Maps (9) - 繪製折線 ( Polyline ) ),並定義取樣的數量,應該就可以在瀏覽器的 console 裡看到折線中每個取樣點的海拔高度,以下面的例子來說,我在龍山寺到指南宮之間繪製一條直線,中間取樣 100 個點,透過 console 就能看到中間的高度變化。

範例:顯示路徑上每個點的海拔高度

var map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    zoom: 12,
    center: {
      lat: 25.0336962,
      lng: 121.5643673
    },
    mapTypeId: 'terrain'
  });

  var elevator = new google.maps.ElevationService;
  var polylinePathPoints = [{
    lat: 25.037113,
    lng: 121.499916
  }, {
    lat: 24.979854,
    lng: 121.587109
  }];

  var polylinePath = new google.maps.Polyline({
    map: map,
    path: polylinePathPoints,
    strokeColor: '#ff0000',
    strokeOpacity: 0.8,
    strokeWeight: 10
  });

  displayPathElevation(polylinePathPoints,elevator);

  function displayPathElevation(path, elevator) {
    elevator.getElevationAlongPath({
      'path': path,
      'samples': 100
    }, function(results, status){
      console.log(results, status)
    });
  }
}

如果你會使用像是 Google Charts 之類的工具來繪製折線圖,你就可以把這些數值傳出來畫圖,看來彷彿就是這條線上的地形頗面圖,操作方式也很容易,只需要改寫剛剛執行的流程,把繪製折線圖的函式加進去即可。

範例:繪製路徑海拔折線圖

function displayPathElevation(path, elevator) {
  elevator.getElevationAlongPath({
    'path': path,
    'samples': 100
  }, function(results, status) {
    // 將 results 轉換為 Google 折線圖的資料格式
    var arr = [];
    arr.push(['number','elevation']);
    for (let i = 0; i < results.length; i++) {
      arr.push([i, results[i].elevation]);
    }
    // Google Chart 繪製折線圖函式
    google.charts.load('current', {
      'packages': ['corechart']
    });
    google.charts.setOnLoadCallback(function() {
      var data = google.visualization.arrayToDataTable(arr);
      var chart = new google.visualization.LineChart(document.getElementById('draw-chart'));
      var options = {
        legend: {
          position: 'bottom'
        }
      };

      chart.draw(data, options);
    });
  });
}

參考

有興趣瞧瞧其他新文章嗎?