GoogleAPIを初心者が使ってみて～ランニングコース生成編～

この記事はウェブクルー　Advent Calender 2018　9日目の記事です。
昨日は　@m-hosokawa　さんの「コマンドvimについて(初歩的な部分)」でした。
#はじめに
　新卒の総合演習でランニングコースを生成するWebアプリを生成しました。その際に使ってみたGoogleのAPIをどのような用途でどのように使用したのかについて紹介させていただきたいと思います。GoogleのAPIをまだ触ったことの無い方に少しでも興味をいだいていただけたら有り難いです。

#今回紹介していくAPI
　・Directions API
　・Geocording API(おまけ)

##Directions API
これは、ルートを生成する際に、必ずと言っていいほど使うAPIで、主な役割として2点間を結ぶ最適経路を求めるものです。
下記のコードを用いて説明していきます。

```Javascript
var directionsService = new google.maps.DirectionsService();//最適な経路を描くオブジェクト
var directionsRenderer = new google.maps.DirectionsRenderer(); // ルート描画するオブジェクト

var startPoint = new google.maps.LatLng(35.170662,136.923430);
var goalPoint = new google.maps.LatLng(35.191662,136.925430);

var mapOptions = { 
     center: startPoint, 
     zoom: 11, 
}; 
var map = new google.maps.Map(document.getElementById('maps'), mapOptions); |

var request = { 
     origin: new google.maps.LatLng(startPoint.lat(),startPoint.lng()),                  
     destination: new google.maps.LatLng(goalPoint.lat(),goalPoint.lng()), 
     travelMode: google.maps.TravelMode.WALKING// 交通手段(歩行)     
} 

directionsService.route(request, function (result, status) { 
     if (status == google.maps.DirectionsStatus.OK) {  
         directionsRenderer.setDirections(result); 
         directionsRenderer.setMap(result); 
     }
});
```

**上記コードの主な流れ**
 1. 出発地点や到着地点、交通手段などのルートを生成する上で必要な事前情報を与える
 2. その事前情報で生成できるルートがあるのかを調べる
 3. 生成できるルートがある場合に、ルート情報を取り出し、地図上に表示

###google.maps.Map()
これは、マップを表示するオブジェクトを生成するものです。
今回は2つのパラメータを使用しています。
1. `document.getElementById('maps')`では、HTML上で表示する領域を指定しています。(今回はid名がmapsであるところに表示するように設定)
2. mapOptionsでは、今回、二つのメソッドを指定しており、centerPointでは、マップを表示する際の中心となるポイントを指定しております。zoomでは、地図の拡大縮小率を指定しております。

###google.maps.LatLng()
これは、緯度と経度を設定するオブジェクトを生成するものです。必須となるパラメータは、緯度と経度の2つです。
    1. 緯度に関しては、-180〜180での数字を指定することができます。
    2. 経度に関しては、-90〜90の値を指定することができます。

###google.maps.DirectionsService() 
この機能は、ルートを計算することができるものです。
ここでは、requestという変数を与えています。この変数では、3つの値が必須となっています。
    1. origin：ルートの計算開始位置を指定します。今回のコードでは、緯度と経度の値を`google.maps.LatLng()`で与えています。
    2. destination：ルートの計算終了位置を指定します。今回のコードでは、緯度と経度の値を`google.maps.LatLng()`で与えています。
    3. travelMode：交通手段を与えています。交通手段としては、下記のものがあります。
    
|travelMode|交通手段|
|-------|---------|
|WALKING |歩行者|
|BICYCLING|自転車|
|DRIVING|自動車|
|TRANSIT|電車|

###google.maps.DirectionsRenderer()

これはルート検索結果表示用のオブジェクトを生成するもので、ルート情報は、変数の`request`にあります。
今回2つのメソッドを使用しており、ルートを描画する`.setDirections()`と描画したルートをマップ上で表示する`.setMap()`のみです。

###今回用いた方法
今回ランニングルートを表示した際の手順を下記に示します。
1. スタート地点からランダムな点までルート情報を`google.maps.DirectionsService()`で求める
2. 変数resultの`routes[0].legs[0].steps[i].distance`メソッドに格納されているそれぞれのアクションまでの距離を足し合わせていく(例：200m進み左に曲がる、30mの横断歩道渡るなど　→　200m + 30m = 230m)
3. 足し合わせていった距離が、走りたい距離に近いポイントをランニングコースのゴールとして再定義
4. スタート地点から再定義したゴール地点までのランニングルートを`google.maps.DirectionsRenderer()`と`.setMap(result)でマップ上で表示

##Geocording API
このAPIは、住所から緯度経度、または緯度経度から住所を取得することができるAPIです。
その中でも私は、逆ジオコーディング(緯度経度から住所を取得)を使用し、ランダムにとった点に対して、そこが海か、海でないかというものを判断出来るのではないかと思い、使用しました。今回その際、学んだ逆ジオコーディング(緯度経度から住所)について説明します。

```Javascript
var geocoder = new google.maps.Geocoder();

var randomPoint = new google.maps.LatLng(35.191662,136.925430);//東京タワーの緯度、経度

geocoder.geocode({latLng: randomPoint}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
    	console.log(results);
    }
});
```
**上記コードの主な流れ**
1.  住所を調べたい、緯度経度を定義
2.  `.geocode()`メソッドに緯度経度を入力
3.  緯度経度から住所の解析が成功(ジオコードが1つ以上返ってくる)したかを判断
4.  その結果を表示

結果は、下記の通りになりました
<pre>
(11) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {address_components: Array(8), formatted_address: "日本、〒105-0011 東京都港区芝公園４丁目２−８", geometry: {…}, place_id: "ChIJCewJkL2LGGAR3Qmk0vCTGkg", plus_code: {…}, …}
1: {address_components: Array(8), formatted_address: "日本、〒105-0011 東京都港区芝公園４丁目２−８", geometry: {…}, place_id: "ChIJL9dIIZeLGGARMHFc9xtDEhM", plus_code: {…}, …}
2: {address_components: Array(8), formatted_address: "Unnamed Road, ４丁目-２ 芝公園 港区 東京都 105-0011 日本", geometry: {…}, place_id: "ChIJzbdsl72LGGAROkrWzzoB6jw", types: Array(1)}
3: {address_components: Array(7), formatted_address: "日本、〒105-0011 東京都港区芝公園４丁目２", geometry: {…}, place_id: "ChIJdfuTmr2LGGARaTKLAeANTgM", types: Array(3)}
4: {address_components: Array(6), formatted_address: "日本、〒105-0011 東京都港区芝公園４丁目", geometry: {…}, place_id: "ChIJx7nxGLyLGGARTSquSCzKviY", types: Array(3)}
5: {address_components: Array(5), formatted_address: "日本、〒105-0011 東京都港区芝公園", geometry: {…}, place_id: "ChIJ_8MpkL6LGGARP200oln5XGs", types: Array(3)}
6: {address_components: Array(5), formatted_address: "日本 〒105-0011", geometry: {…}, place_id: "ChIJpey8VL-LGGAR-Q_v2eSzcfQ", types: Array(1)}
7: {address_components: Array(3), formatted_address: "日本、東京都港区", geometry: {…}, place_id: "ChIJ8yIZtLuLGGARrGzw8nX96zM", types: Array(2)}
8: {address_components: Array(3), formatted_address: "日本、東京都東京", geometry: {…}, place_id: "ChIJXSModoWLGGARILWiCfeu2M0", types: Array(3)}
9: {address_components: Array(2), formatted_address: "日本、東京都", geometry: {…}, place_id: "ChIJ51cu8IcbXWARiRtXIothAS4", types: Array(3)}
10: {address_components: Array(1), formatted_address: "日本", geometry: {…}, place_id: "ChIJLxl_1w9OZzQRRFJmfNR1QvU", types: Array(2)}
length: 11
__proto__: Array(0)
</pre>

配列の値が小さいところほどより詳細な住所を見ることが出来ています。なので住所の結果を表示したい場合は、`console.log`の値を`results[0].formatted_address`に変更すれば、取得できます。
今回、その詳細の度合いを使用して、海か海でないかを判断するように`results.length`が3以下のものを海と判定しようとしていました。今回の例であると、日本の東京としか判定出来ないぐらいの詳細度。(結果としては、海でも詳細度が3以上になってしまったりして上手く出来ませんでした。。。)

#さいごに
いかがだったでしょうか？
GoogleのAPI自体まだまだ数多くあるので色々と試してみてください。

今回、GoogleのAPIどころかAPI自体を使用したのも初めてでした。しかし今回、時間をかけて、APIに向き合ったことにより、自分自身が出来る幅が広げることができたなと感じました。何事も「初めて」というのものは、時間がかかったり、億劫になってしまうことが多くあると思いますが、まずは「初めて」を挑戦してみてください。それによって得ることができるものは、思っている以上に数多くのものとなると思います。

明日は@piwiさんです。
よろしくおねがいします。