iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 4
3
Modern Web

我每天都接一個API系列 第 4

[30apis] Day 3 : Mapbox GL JS & Mapbox Direction API

Mapbox 介紹

說到接 API , 大家一定都會使用到的就是地圖相關的服務了吧?而通常這個被用到的服務都是 Google Map。看了一些接 Google Map 的應用教學,老實說,我覺得有點無聊,不想跟別人做一樣的東西。而說到其他知名的地圖服務,大概就是 Mapbox 跟 OpenStreetMap 了,基本上 Mapbox 也是從 OpenStreetMap 衍生出來的一個地圖服務新創。幾年前注意到 Mapbox 這個新創的時候,就對他們 Demo 上的漂亮地圖感到驚豔,所以不管怎樣都想要用用看。

在搜尋 Mapbox 相關的中文教學時,我注意到簡體中文的教學相當多,而台灣本地的繁體教學寥寥無幾,希望這篇簡易教學可以拋磚引玉、增加一點繁體中文的資源。

Mapbox Studio

Mapbox 為人所喜愛的主要原因,就是因為他有個地圖編輯器,讓使用者可以依照自己需求客製化不同樣貌的地圖,選擇想要顯示的元素(公車路線、大樓、道路等)塗上自己喜歡的顏色。

在Mapbox Studio 裡面取得 Access Token 跟管理地圖樣式 (Styles) 跟其他自訂資料:

Create Style 裡面的地圖編輯器:

Mapbox GL JS

Mapbox GL JS 是利用 WebGL 技術繪製互動式地圖的 JS Library ,在做出客製化的地圖 Styles 之後,我們就要利用這個 library 來在網頁上呈現地圖。
順帶一提,Mapbox GL JS 跟 Mapbox.js 是兩個不同的 library,前者的地圖是向量,基本上是要取代使用點陣地圖的後者,兩者不相容。在這邊不多贅述兩者差異。

因為這個部分跟 API 的主題比較沒關聯,而是在簡單介紹 Mapbox 跟為後面的 Direction API 做準備,我們直接拿範例來改:

實作如下

// 改自 Mapbox GL JS 的範例

<html>
  <head>
    <!--在 HTML Head 裡面置入 mapbox-gl.js 跟 mapbox-gl.css --> 
    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.42.2/mapbox-gl.js'></script>
    <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.42.2/mapbox-gl.css' rel='stylesheet' />
  </head>
  
  <body>
    <!--放一個有 id 的 container,等等用 script 載入地圖,要記得指定寬跟高 --> 
    <div id='map' style='width: 400px; height: 300px;'></div>
    
    <script>
      // 在 Mapbox Studio 裡面得到的 Access Token 放在下方
      mapboxgl.accessToken = 'pk.eyJ1IjoiY2hyeXNvcGh5dGEiLCJhIjoiY2piZnVhOXFyMnhicjMybnoyOG5ueW43cCJ9.i6e5n-YiCbVQG-dvJAdkQQ';
      var map = new mapboxgl.Map({
        container: 'map',
        // 在 Mapbox Studio 裡面製作的 Style 得到的 Style Url
        style: 'mapbox://styles/chrysophyta/cjbfwi7c60m0w2smz9hwekkxv'
        });
    </script>
  </body>
</html>

最後得到了一個復古小地圖

Mapbox web service APIs - Direction

上面做了一個地圖,實在說不上是接了一支 API 吧。所以從 Mapbox 提供的相關服務 API 裡面,挑了一個 Direction API 來試試。我想要使用這個 API 在我剛剛做好的地圖上畫上一個路線圖。
(雖然說,Mapbox GL JS 裡面本來就有 mapbox-gl-directions 的 plugin 可以用,但這邊的目的是練習)

先來看 Direction API 的文件

如果覺得看文件感覺有些複雜,不如把 Direction API 的 API Playground 打開來玩一玩,就會覺得清楚許多。

Direction API 的呼叫方法是

'GET', 'https://api.mapbox.com/directions/v5/{profile}/{coordinates}'

如上所述,他的 URL 需要以下參數:

  • profile 交通模式:有 mapbox/driving-trafficmapbox/drivingmapbox/walking 、跟 mapbox/cycling 四種可以選

  • coordinates 座標:是 2 ~ 25 組的 經度,緯度 。經跟緯用逗號(%2C)分開、每組座標以 semi-colon (%3B) 分隔。

  • 還有理所當然的你的 Access Token

此時我們就來寫一個基礎的 XMLHttpRequest 然後將 API Playground 裡面的 Request URL 放進 .open() 裡面

function getDirection() {
  var xhr = new XMLHttpRequest();
  xhr.open(
    "GET",
    "https://api.mapbox.com/directions/v5/mapbox/walking/-73.989%2C40.733%3B-74%2C40.733.json?access_token=pk.eyJ1IjoiY2hyeXNvcGh5dGEiLCJhIjoiY2piZnVhOXFyMnhicjMybnoyOG5ueW43cCJ9.i6e5n-YiCbVQG-dvJAdkQQ"
  );
  xhr.onload = function() {
    var response = JSON.parse(this.responseText);
    console.log(response);
  };
  xhr.send();
}
getDirection();

就會得到跟 API Playground 裡面的 Response 一模一樣的 object 。(這不是廢話嗎)

讓我們來研究一下這個 Response 到底在寫什麼。
一個 Direction Response Object 裡面會有三個物件:coderouteswaypoints

  • code 基本上會標明這個 request 有沒有成功
  • routes 會給出最多兩組的路線,包含各個步驟的座標跟指示敘述
  • waypoints 會給出路線中的停頓點

雖然得到了這些 data,但其實我並不知道我需要哪些來在地圖上畫圖。回去看 GL JS 的文件,裡面有一項是「使用GeoJSON在地圖上畫線」,也就是說我們需要得到 GeoJSON 格式的 data。
而前面呼叫 API 時,有個 geometries=geojson 的參數可以使用,他會傳回 GeoJSON 格式的 response 。
geometries=geojson 加上 request URL 之後,來比對一下新的 response 長得跟 「使用GeoJSON在地圖上畫線」範例裡面所需要的 data 是不是很相似:

看起來大部分都挺相似的,畢竟是大家都是自己人(?),Direction API 就是給 GL JS Library 拿去用的嘛。

來實作吧

// Provide your access token
mapboxgl.accessToken =
  "pk.eyJ1IjoiY2hyeXNvcGh5dGEiLCJhIjoiY2piZnVhOXFyMnhicjMybnoyOG5ueW43cCJ9.i6e5n-YiCbVQG-dvJAdkQQ";

// Create a map in the div #map
var map = new mapboxgl.Map({
  container: "map",
  center: [-73.993, 40.733],
  style: "mapbox://styles/chrysophyta/cjbfwh87t036h2smvxox647hp",
  zoom: 14
});

function getDirection() {
  var xhr = new XMLHttpRequest();
  xhr.open(
    "GET",
    "https://api.mapbox.com/directions/v5/mapbox/walking/-73.989%2C40.733%3B-74%2C40.733.json?access_token=pk.eyJ1IjoiY2hyeXNvcGh5dGEiLCJhIjoiY2piZnVhOXFyMnhicjMybnoyOG5ueW43cCJ9.i6e5n-YiCbVQG-dvJAdkQQ&geometries=geojson"
  );
  
  
  xhr.onload = function() {
    var response = JSON.parse(this.responseText);
    var routeGeometries = response.routes[0].geometry;
    
    //這邊的 code 改自 add a line with GeoJSON 的範例
    map.on("load", function() {
      map.addLayer({
        id: "route",
        type: "line",
        source: {
          type: "geojson",
          data: {
            type: "Feature",
            properties: {},
            geometry: {
              type: "LineString",
              // 把 coordinates 改成從 Direction API 拿回來的座標
              coordinates: routeGeometries.coordinates
            }
          }
        },
        layout: {
          "line-join": "round",
          "line-cap": "round"
        },
        paint: {
          "line-color": "#000",
          "line-width": 3
        }
      });
    });
  };
  xhr.send();
}
getDirection();

路線出現了,好感人啊。

今天的 API 教學在此告一段落,Demo 在這邊
寫得好累。(抹臉)


上一篇
[30apis] Day 2 : Google Map Geolocation API
下一篇
[30apis] Day 4 : News API
系列文
我每天都接一個API30

2 則留言

0
小松菜奈
iT邦研究生 4 級 ‧ 2018-07-19 21:32:18

滿猛的,正好最近要接觸到這個

0
cjk
iT邦新手 5 級 ‧ 2018-10-23 17:32:57

謝謝分享!想問國內是不是有此類 Web GIS 的討論社群?

我要留言

立即登入留言