Google Maps Geocoding APIのJavaScriptを解説

## はじめに

先日Railsで制作したポートフォリオにGoogle Maps APIを取り入れて地図表示機能を実装したのですが、
そこで書いたJavaScriptのコードの理解が曖昧だったので、記事にまとめてみました。

この記事ではGoogle Maps APIの導入方法ではなく、JavaScriptのコードにフォーカスして解説します。
APIの導入の仕方についてはこちらの記事では解説しませんので、知りたい方は以下の記事をご覧ください。
[【Rails6 / Google Map API】初学者向け！Ruby on Railsで簡単にGoogle Map APIの導入する](https://qiita.com/nagaseToya/items/e49977efb686ed05eadb#%E6%A4%9C%E7%B4%A2%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%8B%E3%82%89%E4%BD%8F%E6%89%80%E3%82%92%E7%89%B9%E5%AE%9A%E3%81%97%E3%83%94%E3%83%B3%E3%82%92%E5%88%BA%E3%81%99)

「ネットにある記事をコピペしたら何となくできたけどコードの内容が理解できない」
という方がいましたら読んでいただければと思います。

## 前提知識
住所や地名を緯度や経度などの地理座標に変換することを「ジオコーディング」と言います。
Google MapsのGeocoding APIは、ジオコーディングをするAPIです。

## 完成イメージ

先日旅行をしたい人がツアーガイドを募集できるアプリを制作し、
旅行したい場所として入力した場所が地図に表示されるように実装しました。

この記事では、このアプリのイメージのもとで解説します。

![スクリーンショット 2020-10-24 13.16.03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665045/f38e70f1-370f-dd02-1fb7-31e1b3c85d6c.jpeg)


## ソースコード
ビューのソースコードは以下のとおりで、
旅行したい場所を表示する箇所に`address`のidを、地図を表示する場所に`map`のidを付与しています。

```show.html.haml
    .Post_main__Box
      .Post_show_title
        = @post.title
      .Post_table.Text
        %table
          %tr
            %th 旅行したい場所
            -# ここに住所を表示
            %td#address
              = @post.region
          %tr
            %th 希望日時
            %td
              = @post.datetime
          %tr
            %th 希望料金
            %td
              = @post.charge
          %tr
            %th お支払い方法
            %td
              = @post.payment
      .Post_head
        = "-リクエスト内容-"
      .Post_content
        = simple_format(@post.content)
      .Post_head
        = "-地図-"
      -# ここに地図を表示
      .Post_map#map
```

さらに、JavaScriptのソースコードは以下のとおりです。

```map.js
// HTMLの読み込みが終わった後に処理が行われるように設定
document.addEventListener('DOMContentLoaded', () => {
  const inputAddress = document.getElementById('address').textContent;    //①
  const target = document.getElementById('map');    //②
  geocoder = new google.maps.Geocoder();   // ③

  geocoder.geocode( { address: inputAddress}, (results, status) => {  // ④
    if (status == 'OK') {  // ⑤
      const map = new google.maps.Map(target, {  // ⑥
        center: results[0].geometry.location,   // ⑦
        zoom: 13  // ⑧
      });
      new google.maps.Marker({  // ⑨
          map: map,  // ⑩
          position: results[0].geometry.location  // ⑪
      });
    } else {   // ⑫
      document.getElementById('map').style.height = '20px'   // ⑬
      document.getElementById('map').innerHTML = '該当する場所が見つかりませんでした。'   // ⑭
    }
  });   
})
```

## 解説

上記のJavaScriptのコードについて解説していきます。

**▼①と②について**

```js
const inputAddress = document.getElementById('address').textContent;   //①
const target = document.getElementById('map');   //②
```
①では`address`のidを持った要素の中にある文字列（ここでは住所）を取得し、`inputAddress`に代入しています。
②では`map`のidを持った地図を表示する領域のdiv要素のオブジェクトを`target`に代入しています。

**▼③について**

```js
geocoder = new google.maps.Geocoder();
```
この記述では、Googleサーバーと通信するために必要な`google.maps.Geocoder`のオブジェクト（インスタンス）を生成しています。
APIには、このオブジェクトを通してアクセスします。


**▼④について**

```js
geocoder.geocode( { address: inputAddress}, (results, status) => {   
```
ここではまず、①で生成した`geocoder`オブジェクトに`geocode()`メソッドを用いることで,
ジオコーディングをするためのリクエストを送信しています。

リクエストを送信するときは、APIの仕様で`address`か`location`か`placeId`のどれかの値を渡さなくてはならず、
上記のコードでは`address`のプロパティに①で定義した`inputAddress`の値を入れてパラメーターとして渡しています。

リクエストが完了すると結果（`results`）とステータス（`status`）が返ってくるので、
それらを取得して処理するために、`results`と`status`を引数にコールバック関数を記述します。


**▼⑤について**

```js
if (status == 'OK')
```
リクエストの結果として返されるステータスでは、ジオコーディングが成功した場合には`OK`が返され、
成功しなかった場合には`ERROR`などといったコードが返されます。
上記の記述では、ジオコーディングが成功した場合のことを表しています。

**▼⑥〜⑧について**

```js
const map = new google.maps.Map(target, {  // ⑥
  center: results[0].geometry.location,   // ⑦
  zoom: 13  // ⑧
});
```
⑥では、`new google.maps.Map`で地図を生成し、`map`に代入しています。
`google.maps.Map`クラスのコンストラクタでは、1番目の引数には地図を表示するdiv要素を指定します。
ここでは、②で定義した`target`を指定しています。
また、2番目の引数には、地図の座標やズームレベルを設定するオブジェクトを指定します。

⑦では、`results[0].geometry.location`でリクエストの結果の中から経度と緯度の情報を取得し、
その地理座標を地図の真ん中に表示するように記述しています。
ちなみに、リクエストの結果は配列で返されるため`results[0]`と記述しています。

さらに⑧でズームレベルを指定しています。
この数値が大きければ大きいほど地図は拡大して表示されます。



**▼⑨〜⑪について**

```js
new google.maps.Marker({  // ⑨
    map: map,  // ⑩
    position: results[0].geometry.location  // ⑪
});
```
ここでは、地図上にマーカー（赤いピン）を表示させる記述をしています。
⑨でマーカーのオブジェクトを生成し、引数にオプションとして`map`と`position`の指定をしています。
⑩ではマーカーを表示する地図を指定しており、ここでは⑥で定義した`map`を指定しています。
また、⑪ではマーカーを表示する位置をリクエストの結果から得られた地理座標で指定しています。

ちなみに、オプションで`animation: google.maps.Animation.DROP`を追加すると、
マーカーが上から落ちてくるようなアニメーションを追加できます。

**▼⑫〜⑭について**

```js
} else {   // ⑫
  document.getElementById('map').style.height = '20px'   // ⑬
  document.getElementById('map').innerHTML = '該当する場所が見つかりませんでした。'   // ⑭
}
```
ここでは、ジオコーディングが成功しなかった場合の処理を記述しています。
⑬で地図を表示させるdiv要素の高さを変更し、⑭でHTMLの中身を文字に書き換えています。
このように記述すると、以下のように表示されます。
![スクリーンショット 2020-10-24 13.16.20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665045/8a42c6cf-66d1-f1d6-253f-ba2923eefe07.jpeg)


## 参考にした記事
この記事を投稿するにあたり、以下の記事を参考にさせていただきました。
以下の記事ではもっと詳細に書かれているので、詳しく知りたい方はご覧ください。
[Geocoding Service  |  Maps JavaScript API  |  Google Developers](https://developers.google.com/maps/documentation/javascript/geocoding?hl=ja#GeocodingResults)
[Google Maps API の使い方 利用方法 / Web Design Leaves](https://www.webdesignleaves.com/pr/plugins/googlemap_01.html)
[ジオコーディング - マッピィ Google Maps API JavaScriptの使い方 -](https://www.google-mapi.com/event-data-processing/geocoding/)
[Google Maps JavaScript API入門](https://www.javadrive.jp/google-maps-javascript/)