地図(Google Map)の任意地点に円を描き、人口データの属性を持つ町丁目ポリゴンを取得し、表示する

# 概要説明
Google Mapを使用し、地図の任意地点に円を描き、円内のエリアを人口データの属性を持つ町丁目ポリゴンで表示させ、データを取得してみました。この記事は[Maps JavaScript APIを使ってGoogle Mapに町丁目ポリゴンを表示してみる](https://qiita.com/yan_x/items/c069c8fb7c5d2648fe50)の拡張内容です。Google Mapの地図表示や地図上のポリゴン表示に興味がある方は上記の記事を一読頂ければ幸いです。


## 使用するもの
* Google Map
* Maps JavaScript API
Google Mapで提供されている API の中の一つで、独自のコンテンツと画像を使って地図をカスタマイズして、ウェブページおよびモバイルデバイスに表示できます。

https://developers.google.com/maps/documentation/javascript?hl=ja

* PHP
* JavaScript
* 町丁目ポリゴン（TerraMap API）
町丁目とは行政界の一つで「富士見町3丁目」「広尾1丁目」など「●丁目」で表わされる行政区画のことです。行政界は他には都道府県や市区町村、大字などがあります。
町丁目ポリゴンとは町丁目の境界データであり、e-stat で 小地域（町丁・字等別）という名称で公開されています。

今回使用した町丁目ポリゴンは、TerraMap API からレスポンスされたものです。

https://www.mapmarketing.co.jp/terramap-api?grid=qiita&utm_source=qiita.com&utm_medium=referral&utm_campaign=qiita_gmap-circle_0cf06675739ddcfa3576_01

## Google Mapの任意地点で円を描く
まずはGoogle Mapに任意地点から任意半径の円を描いてみます。
ブラウザに表示されるイメージは以下になります。
![circlearea.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2916958/4da1cab6-af90-a5f5-777f-23f2f01e7432.gif)
今回はGoogle Maps APIのDrawingManagerライブラリで円を描画するため、リクエストパラメータ<font color="Red">libraries=drawing</font>を地図のURLに加える必要があります。

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Google Mapに円を描き、人口データの属性を持つ町丁目ポリゴンを表示する</title>

    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <!--The div element for the map -->
    <div id="map" style="width: 100%; height: 600px;"></div>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_MAP_KEY&libraries=drawing&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>
```

JavaScriptではDrawingManagerを利用し、円を描くツールの設定を行います。
```javascript:index.js
function initMap() {
  // 中心位置
  const centerLocation = { lat: 35.6727, lng: 139.662 };

  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 15,
    center: centerLocation,
  });

  const drawingManager = new google.maps.drawing.DrawingManager({
    drawingControl: true,
    drawingControlOptions: {
      position: google.maps.ControlPosition.TOP_CENTER,
      drawingModes: [google.maps.drawing.OverlayType.CIRCLE],
    },
    circleOptions: {
      fillColor: "#E3E0AD2D",
      fillOpacity: 1,
      strokeWeight: 5,
      clickable: false,
      editable: true,
      zIndex: 1,
    },
  });

  drawingManager.setMap(map);
}

window.initMap = initMap;
```
>コード参考情報
[Maps JavaScript API Samples Drawing Tools](https://developers.google.com/maps/documentation/javascript/examples/drawing-tools)
[描画レイヤ（ライブラリ）](https://developers.google.com/maps/documentation/javascript/drawinglayer)


## 円内の町丁目ポリゴンを表示させ、データを取得する
次に円範囲内の町丁目ポリゴンを表示させた後、描画した町丁目ポリゴンをクリックしたらconsole.log()で町丁目名と人口を表示してみました。
ブラウザに表示されるイメージは以下になります。
![circlearea.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2916958/fbd8e62c-edb7-f853-6825-7808c78e057e.gif)


### 描いた円の半径や中心点座標を取得しサーバーサイドプログラムと通信する
先ほどのindex.jsのinitMapファンクション内に下記コードを追加します。
円描画完了時、event.addListenerで円の半径と中心点座標を取得し、パラメータにセッティングします。
fetchにはTerraMap APIにリクエストを送るサーバーサイドプログラムのURLを指定します。
最後にポリゴン表示のスタイル設定をpolygonStyleOptionsで行います。
```JavaScript:index.js
  google.maps.event.addListener(drawingManager, "circlecomplete", (circle) => {
    const latitude = circle.getCenter().lat();
    const longitude = circle.getCenter().lng();
    const circleRadius = circle.getRadius();

    const params = {
      // 渡したいパラメータをJSON形式で書く
      lat: latitude,
      lng: longitude,
      radius: circleRadius,
    };
    const queryParams = new URLSearchParams(params);
    
    //サーバーサイドプログラムからTerraMap APIへのリクエスト例はページ下部に説明があります
    fetch(`https://YOUR_SERVER_DOMAIN/?${queryParams}`, {
      method: "GET",
    })
      .then((response) => response.json())
      .then((data) => {
        map.data.addGeoJson(data);
      })
      .catch((error) => {
        console.log(error);
      });
  });

  const polygonStyleOptions = {
    strokeColor: "#810FCB",
    strokeOpacity: 1.0,
    strokeWeight: 2.0,
    fillColor: "#810FCB",
    fillOpacity: 0.5,
  };

  map.data.setStyle((feature) => {
    if (feature.getGeometry().getType() === "MultiPolygon") {
      return polygonStyleOptions;
    }
    return null;
  });
```


### PHPでcURL関数を使ってTerraMap APIから町丁目ポリゴン、統計データ、住所を取得する
今回の紹介例はPHPを使用しましたが、他のサーバーサイドプログラムでもTerraMap APIにリクエストすることができます。
```PHP:index.php
<?php

header('Content-Type: application/json');

// URLとapiキーはダミーです
$url = 'https://tmapi.example.jp/api/area';
$apiKey = 'YOUR_TerraMap_API_APIKEY';

// リクエストパラメータからのINPUT
$lat = filter_input(INPUT_GET, 'lat');
$lng = filter_input(INPUT_GET, 'lng');
$radius = filter_input(INPUT_GET, 'radius');

// パラメータをJSON形式でセット
$params = json_encode([
    "layer_id" => "00104",          // レイヤーは町丁目を指定
    "area_type" => "circle",        // エリアタイプは円を指定
    "center_lat" => $lat,           // 中心点緯度
    "center_lng" => $lng,           // 中心点経度
    "radius" => [(float)$radius],                  // 半径
    "output" => "polygon,point,data",       // ポリゴン、住所、データを出力する
    "stats" => [
        array(
            "stat_id" => "001012000",       // 国勢調査2020を指定
            "stat_item_id" => [15776]       // 人口総数20を指定
        )
    ],
]);

$ch = curl_init();
// Content-TypeとAPIキーをセット
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json', 'X-API-KEY: ' . $apiKey]);
// POSTメソッドを指定
curl_setopt($ch, CURLOPT_POST, true);
// パラメータをセット
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
// URLをセット
curl_setopt($ch, CURLOPT_URL, $url);

// レスポンスをブラウザに渡す
curl_exec($ch);

curl_close($ch);
```
>コード参考情報
[指定地点から半径 x メートルに含まれる町丁目ポリゴンを取得する方法　TerraMap APIを使って](https://qiita.com/4gou/items/6fc104ebbb3b9dc51e79)


上記のリクエストを送ることで、TerraMap API は条件に一致した町丁目ポリゴンをGeoJSONとしてレスポンスすることができます。レスポンスはポリゴンの座標値が続いて長くなるので一部のみ掲載します。
<details><summary>GeoJSONレスポンスの抜粋</summary>

```json:response.geojson
{
    "type": "Feature",
    "properties": {
        "area": {
            "area": 0.17709921567249298
        },
        "data": [
            {
                "is_authorized": true,
                "stat_item_id": 15776,
                "stat_id": "001012000",
                "value": "2905"
            }
        ],
        "geocode": "13112002102",
        "points": [
            [
                "東京都",
                "世田谷区",
                "大原２丁目"
            ]
        ]
    },
    "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
            [
                [
                    [
                        139.660779892616,
                        35.6724443495492
                    ],
                    [
                        139.661522331085,
                        35.6710191360481
                    ],
                    [
                        139.661585854616,
                        35.6708598286481
                    ],
```
</details>

### 町丁目ポリゴンの住所、人口データを表示する
index.jsに下記のコードを追加し、サーバーサイドから受け取ったGeoJSONデータからクリックした場所の住所と人口データを取り出しブラウザのconsoleに出力させました。
```JavaScript:index.js
  map.data.addListener("click", (event) => {
    console.log(`住所：${event.feature.getProperty("points")[0]}`);
    console.log(`人口：${event.feature.getProperty("data")[0].value}`);
  });
```
>コード参考情報
[Maps JavaScript APIイベント](https://developers.google.com/maps/documentation/javascript/events)


## おわりに
今回はGoogle Mapを用いてブラウザで地図に円を描画する機能を紹介しました。
そして、TerraMap APIを利用して町丁目ポリゴンや統計データ、住所も簡単に取得することができ、地図上に表示させました。
以上になります。最後まで読んでいただき有難うございました。

https://www.mapmarketing.co.jp/terramap-api?grid=qiita&utm_source=qiita.com&utm_medium=referral&utm_campaign=qiita_gmap-circle_0cf06675739ddcfa3576_02