LeafletでGeoJSONファイルを読み込み、人口で色分けを行ってみる

## はじめに
[弊社の記事](https://qiita.com/organizations/mapmarketing)では、いろいろな地図ライブラリでGeoJSONのポリゴンを表示してきました。今回は、Leafletを用いて地図上に町丁目ポリゴンを表示し、人口総数によって色分けを行いたいと思います。

## 表示する町丁目ポリゴン（GeoJSON）
人口総数を属性に持つ町丁目ポリゴンについては、[TerraMap API](https://www.mapmarketing.co.jp/terramap-api?grid=qiita&utm_source=qiita.com&utm_medium=referral&utm_campaign=qiita_leaflet_chomoku_population_colors_e15987624aa614faba36_01)から取得できるものを利用しました。

一部省略しておりますが、以下のようなGeoJSONファイルになります。
`features[0].properties.data[0].value` が人口総数の値になっています。
```ChoPolygon.geojson
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "area": {
          "area": 0.23232962656232412
        },
        "data": [
          {
            "is_authorized": true,
            "stat_item_id": 15776,
            "stat_id": "001012000",
            "value": "1301"
          }
        ],
        "point_coordinates": [
          139.67882,
          35.662
        ],
        "geocode": "13110000104",
        "points": [
          [
            "東京都",
            "目黒区",
            "駒場４丁目"
          ]
        ]
      },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [
                139.674866628,
                35.664159828
              ],
              [
                139.675069068,
                35.664075835
              ],
              
              .... 座標を省略しています
              
            ]
          ]
        ]
      }
    },

    .... featureを省略しています
  ]
}
```
## HTML
```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>
      Leafletで地図に町丁目ポリゴンを表示し、人口総数で色分けを行ってみる
    </title>
    <link
      rel="stylesheet"
      href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
      integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
      crossorigin=""
    />
    <script
      src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
      integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
      crossorigin=""
    ></script>
    <link rel="stylesheet" type="text/css" href="./style.css" />
  </head>
  <body>
    <div id="map" style="width: 100%; height: 95vh"></div>
    <script src="./index.js"></script>
  </body>
</html>
```
参考情報
https://leafletjs.com/examples/quick-start/

## ポリゴン表示まで
OpenStreetMapの地図上に町丁目ポリゴンを表示し、クリックすることで人口総数をPopup表示させます。JavaScriptのコードは以下のようになります。

```index.js
const map = L.map("map").setView([35.6727, 139.662], 13);

// 背景地図はOpenStreetMap
const tiles = L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
  maxZoom: 19,
  attribution:
    '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);

// GeoJSONのスタイル
const geoJsonStyle = {
  color: "#7a7a7a",
  fillColor: "#9a9a9a",
  fillOpacity: 0.5,
};

// onEachFeatureオプションを利用して属性データをPopup表示できるようにする
function onEachFeature(feature, layer) {
  // 属性データはfeature.propertiesの構成に従って参照する必要があります
  const prop = `住所：${feature.properties.points[0].join("")}<br>人口：${
    feature.properties.data[0].value
  }`;
  layer.bindPopup(prop);
}

// GeoJSONの内容を取得
fetch(`ChoPolygon.geojson`)
  .then((response) => response.json())
  .then((data) => {
    // GeoJSONのレイヤー
    L.geoJSON(data, {
      style: geoJsonStyle,
      onEachFeature, // 上記関数とリンク
    }).addTo(map);
  });
```
表示結果
![ChoPolygon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2893989/a8244cce-7b42-4cde-12e5-fa0bfb87c6f6.png)

参考情報
https://leafletjs.com/examples/geojson/

## ポリゴンの色付け
続きまして、人口総数の値によってポリゴンの色分けを行います。基本的には [Interactive Choropleth Map](https://leafletjs.com/examples/choropleth/) を参考にして作成しました。

index.jsのgeoJsonStyle宣言部分を以下のように差し替えます。
```js
// 人口総数による配色
function getColor(d) {
  return d > 7000
    ? "#800026"
    : d > 6000
    ? "#BD0026"
    : d > 5000
    ? "#E31A1C"
    : d > 4000
    ? "#FC4E2A"
    : d > 3000
    ? "#FD8D3C"
    : d > 2000
    ? "#FEB24C"
    : d > 1000
    ? "#FED976"
    : "#FFEDA0";
}
// GeoJSONのスタイル
function geoJsonStyle(feature) {
  return {
    fillColor: getColor(feature.properties.data[0].value),
    weight: 1,
    opacity: 1,
    color: "white",
    dashArray: "3",
    fillOpacity: 0.7,
  };
}
```
表示結果
![ChoPolygon2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2893989/48f516d1-c9a2-ecd0-fa18-45bf43c36792.png)

## 凡例作成
[Interactive Choropleth Map](https://leafletjs.com/examples/choropleth/) に倣って凡例も作成してみます。index.jsの末尾に以下コードを追記します。
```js
const legend = L.control({ position: "bottomright" });

legend.onAdd = function () {
  const div = L.DomUtil.create("div", "info legend");
  const grades = [0, 1000, 2000, 3000, 4000, 5000, 6000, 7000];
  const labels = [];

  for (let i = 0; i < grades.length; i++) {
    const from = grades[i];
    const to = grades[i + 1];

    labels.push(
      `<i style="background:${getColor(from + 1)}"></i> ${from}${
        to ? `&ndash;${to}` : "+"
      }`
    );
  }

  div.innerHTML = labels.join("<br>");
  return div;
};

legend.addTo(map);
```
CSSファイルにも以下の記述を行います。
```style.css
.info {
  padding: 6px 8px;
  font: 14px/16px Arial, Helvetica, sans-serif;
  background: rgba(255, 255, 255, 0.8);
  box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
  border-radius: 5px;
}
.legend {
  text-align: left;
  line-height: 18px;
  color: #555;
}
.legend i {
  width: 18px;
  height: 18px;
  float: left;
  margin-right: 8px;
  opacity: 0.7;
}
```
## 完成画像
全体が上手くいくと、以下のような表示結果になります。

![ChoPolygon3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2893989/155fb0f3-28ca-ba37-adeb-6d53e0943e3a.png)

記事は以上になります。
最後まで読んでいただきましてありがとうございます。