自分の町の避難所情報をGoogle Mapsに表示する

オープンデータの活用とGoogle Maps APIの練習を兼ねて自分の町の避難所情報をGoogle Mapに表示してみました。さらに避難所までのルートも表示させてみます。

# 避難所情報の取得

まずは大刀洗町オープンデータカタログ https://odcs.bodik.jp/405035/ から避難所情報を取得してみます。
CKAN Data APIのサンプルを参考に以下のようにAPIにアクセスします。

``` javascript
  $.ajax({
    url: 'https://data.bodik.jp/api/3/action/datastore_search',
    data: { resource_id: '1bb3a1f5-db97-488f-92f4-aa72e497e6d1', limit: 5 },
    dataType: 'jsonp',
    cache: true, // これを付けないと引数のタイムスタンプで何故かエラーが出る
    success: function(data) {
      console.log(data.result)
    }
  });
```
CORSに対応するためにjsonpを使っていたりしますがその辺り今回は割愛。
ブラウザのコンソールにjson情報が表示されたら成功です。

# Googleマップに表示させる

取得したjson情報をGoogleマップに表示させてみましょう。
Google Maps APIを使用するには、
https://cloud.google.com/maps-platform?hl=ja
にてAPIキーを取得しなければなりませんが詳細は割愛します。

<img width="50%" alt="大刀洗町避難所マップ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72890/bcd2b1ff-aae5-6b9b-5673-cb853120f954.png">

緯度と経度を取得してマーカーを立てます。さらにマーカーをクリックしたときに簡単な詳細情報ウィンドウを表示させてみました。

``` html
<!DOCTYPE html>
<html>
  <head>
    <title>大刀洗町避難所マップ</title>
    <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=APIキー&callback=initMap&libraries=&v=weekly"
      defer
    ></script>
    <style type="text/css">
      #map {
        height: 100%;
      }
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script>
      function initMap() {
        const map = new google.maps.Map(document.getElementById("map"), {
          zoom: 14,
          center: { lat: 33.3881, lng: 130.6127},
        });

        // 避難所情報取得
        $.ajax({
          url: 'https://data.bodik.jp/api/3/action/datastore_search',
          data: { resource_id: '1bb3a1f5-db97-488f-92f4-aa72e497e6d1', limit: 30 },
          dataType: 'jsonp',
          cache: true,
          success: function(data) {
            // マーカー
            for (const record of data.result.records) {
              const marker = new google.maps.Marker({
                position: {lat: record.緯度, lng: record.経度},
                map: map,
                title: record.名称,
              });
              marker.addListener('click', function(){
                // 詳細ウィンドウ
                const infoWindow = new google.maps.InfoWindow({
                  content: `<h3>${record.名称}</h3><p>${record.住所表記}<br>${record.避難施設種別}</p>`
                });
                infoWindow.open(map, marker);
              });
            }
          }
        });
      }
    </script>
  </head>
  <body>
    <div id="map"></div>
  </body>
</html>
```

# 避難所までのルートを表示する

これだけだと物足りないので、避難所までのルートを表示させてみましょう。

<img width="50%" alt="ルート表示" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72890/d11d8ad5-8fc7-aeb5-b6e3-19d84e3ba26d.png">

ルート表示を行うためには事前にGoogle Map APIのDirections APIを有効化しておく必要があります。
今回の交通手段はWALKING（徒歩）を設定します。

``` javascript
function initMap() {
  var currentPos = { lat: 33.3881, lng: 130.6127 };
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 14,
    center: currentPos,
  });
  const directionsService = new google.maps.DirectionsService();
  const directionsDisplay = new google.maps.DirectionsRenderer();
  directionsDisplay.setMap(map);

  $.ajax({
    url: 'https://data.bodik.jp/api/3/action/datastore_search',
    data: { resource_id: '1bb3a1f5-db97-488f-92f4-aa72e497e6d1', limit: 30 },
    dataType: 'jsonp',
    cache: true,
    success: function(data) {
      for (const record of data.result.records) {
        const marker = new google.maps.Marker({
          position: {lat: record.緯度, lng: record.経度},
          map: map, 
          title: record.名称,
        });
        marker.addListener('click', function(){
          const infoWindow = new google.maps.InfoWindow({
            content: `<h3>${record.名称}</h3><p>${record.住所表記}<br>${record.避難施設種別}</p>`
          });
          infoWindow.open(map, marker);

          // ルート情報
          var request = {
              origin: currentPos,
              destination: new google.maps.LatLng(record.緯度, record.経度),
              travelMode: google.maps.TravelMode.WALKING
          }
          directionsService.route(request, function(result, status) {
              if (status == google.maps.DirectionsStatus.OK) {
                  directionsDisplay.setDirections(result);
              }
          });
        });
      }
    }
  });
}
```

# さらなる発展
現在位置の取得（navigator.geolocation.getCurrentPosition）を使うとさらに実用的になるのですが、コードが長くなったのでまたの機会に。