震度分布図を作ろう⑧ ～塗りつぶしをしよう～

## はじめ
みなさんこんにちは。
これまた期間が空いてしまい申し訳ありません。
前回同様、挨拶しているとめんどくさいので…（省略）

### 前回したこと
前回は、地図上に観測点の震度を画像を使ってアイコンを描画しましたね。

### 今回すること
今回は少しの改修と塗りつぶしと ~~各地の震度の追加~~ をやっていきましょう。

## 開発スタート
### 前回までのコード
前回までのコードは

https://qiita.com/kottaro123456/items/fb31192dd47aa271d2a0#%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%AB

に貼ってありますので、コピーして利用ください。

### ①ちょっとした改修
まあ、まずはウォーミングアップとしてちょっとした改修から行っていきましょう。
いきなりカスみたいな量のJSを書くのはごめんなので。

#### ①-①無段階ズームにする
今のままでは、パソコンからアクセスしてマウスホイールで拡大縮小をしようとするときは、細かくズームレベルを変更することはできません。
つまり、「あー、この倍率とこの倍率の間の倍率にしたいのにー」となったときもパソコンでは間の倍率に変更できません。
それでは不便なので、無段階ズームを実装仕様ではないか、ということです。
そもそも、無段階ズームとは、Google Mapのように、どの倍率でも地図を見られるようにすることです。

まあ書いてて何を書いているかわかっていないですが、実装していきましょう。

今回はこちらの<font color="#f00"><b>すばらしい</b></font>プラグインの<font color="#f00"><b>「Leaflet.SmoothWheelZoom」</b></font>を借りるとしましょう。
これはMIT licenseで配布されているので改変しない限り自由に使えますね。

https://qiita.com/mutsuyuki/items/18750a8a73675604c4d8

こちらがそのすばらしいプラグインのQiitaですね。

まずは

https://github.com/mutsuyuki/Leaflet.SmoothWheelZoom/blob/master/SmoothWheelZoom.js

GitHubからこれをダウンロードして」

```diff_html:index.html
+<script src="source/SmoothWheelZoom.js"></script>
<script src="source/JMAPoints.js"></script>
<script src="index.js"></script>
```

HTMLに読み込みタグを追加し、

```diff_javascript:index.js
var map = L.map('map', {
    preferCanvas: true,
+    scrollWheelZoom: false,
+    smoothWheelZoom: true,
+    smoothSensitivity: 1.5,
}).setView([36.575, 137.984], 6);
```

JavaScriptのマップの宣言のオプションに、
`scrollWheelZoom: false`：まず標準のマウスホイールでのズームを禁止する
`smoothWheelZoom: true`：今回のズームライブラリを適用する
`smoothSensitivity: 1.5`：ズーム感度の設定（好みで変えてください。私はこれくらいがいいと思いました。）

そうしたら再読込してみると、確かにカクカクズームレベルが変わるのではなく、スムーズになめらかにズームレベルが変わっていっていることがわかります。

やはり<font color="#f00"><b>すばらしい</b></font>プラグインですね。

しかし、
<b>ちょっとした</b>改修の<font color="#f00"><b>「ちょっとした」</b></font>とは何処へ行ってしまったのでしょうか…。
長すぎるやろ。これだけで記事出せ

### ②塗りつぶしをしよう

#### ②-①データの下準備
さてここからやっと本題です。
塗りつぶし、簡単にできるかな…と思っていたら、まさかの読み込んでいる地図データが都道府県データでしたので、変更しないといけません。
**↑地震情報での塗りつぶしは細分区域(都道府県をいくつかの地区に分けたもの)ごとで塗らないといけません**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637649/c28c80de-8c8e-c46d-9bb5-d0b8c38c1102.png)
たとえば宮崎県で行くと、右が細分区域で都道府県を4つに分けていることがわかると思います。

てなわけで、読み込むデータを都道府県から細分区域に変更しましょう。

まずは
https://miyakocam.github.io/geojsons/saibun.geojson
からGeoJSONファイルをダウンロードしてきてください。
出典は https://www.data.jma.go.jp/developer/gis.html こちらです。

```diff_javascript:index.js:42
+var japan_data;
-$.getJSON("prefectures.geojson", function (data) {
+$.getJSON("saibun.geojson", function (data) {
+    japan_data = data;
    L.geoJson(data, {
        pane: "pane_map3",
        style: PolygonLayer_Style_nerv
    }).addTo(map);
});
```

そして右下の出典元に気象庁を入れておきましょう。
```diff_javascript:index.js:12
map.zoomControl.setPosition('topright');
+map.attributionControl.addAttribution(
+    "<a href='https://www.jma.go.jp/jma/index.html' target='_blank'>気象庁</a>"
+);
map.attributionControl.addAttribution(
    "<a href='https://github.com/mutsuyuki/Leaflet.SmoothWheelZoom' target='_blank'>SmoothWheelZoom</a>"
);
```

これで読み込むと、都道府県よりも境界線が増えていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637649/cbdc10e0-676c-0243-7640-0f55d71eba22.png)

#### ②-②塗りつぶしの下準備
まあ後々いることになるので、便利な関数を用意しておきましょう。

```diff_javascript:index.js:224
function AreaNameToCode(Name) {
    var array_Num = AreaName.indexOf(Name);
    return AreaCode[array_Num];
}
function AreaCodeToName(code) {
    var array_Num = AreaCode.indexOf(code);
    return AreaName[array_Num];
}
```

これを追加しておきましょう。
`AreaNameToCode()`は地域名(大阪府北部)を地域コード(520)に変換するもので、
`AreaCodeToName()`はそれの反対バージョンだと思っていただけたら大丈夫です。
いきなり出てくる`AreaCode`とか`AreaName`はすでにJMAPoints.jsで宣言されているのでエラーとはなりません。

また、塗りつぶし情報を保存する変数も宣言しておきましょう。
```diff_javascript:index.js:125
var shindo_layer = L.layerGroup();
+var shindo_filled_layer = L.layerGroup();
+var filled_list = {};

function QuakeSelect(num) {
+    if (shingenIcon && shindo_layer && shindo_filled_layer) {
        map.removeLayer(shingenIcon);
        map.removeLayer(shindo_layer);
+        map.removeLayer(shindo_filled_layer);
        shingenIcon = "";
        shindo_layer = L.layerGroup();
+        shindo_filled_layer = L.layerGroup();
+        filled_list = {};
        shindo_icon = "";
    }
```

#### ②-③塗りつぶししていこう！
```diff_javascript:index.js:222
    shindo_layer.addLayer(shindo_icon);
    
+    //塗りつぶしの設定をする
+    //AreaNameToCode()は下を参照。大阪府北部を520等に変換
+    //filled_listは連想配列で{520: 10, 120: 20}など、エリアコード: 震度の大きさ
+    var areaCode = AreaNameToCode(JMAPointsJson[result]["area"]["name"]);
+    //filled_listにエリアコードがなかったり、さらに大きな震度になっていたら更新
+    if ((!filled_list[areaCode]) || filled_list[areaCode] < element["scale"]) {
+        filled_list[areaCode] = element["scale"];
+    }
}
+//for(... in ...)もforEachと同等。keyに連想配列の名前が入る
for (key in filled_list){ 
    var PointColor;
    if (filled_list[key] == 10) {
        eval('PointColor = '+icon_theme+'_backColor_1');
    } else if (filled_list[key] == 20) {
        eval('PointColor = '+icon_theme+'_backColor_2');
    } else if (filled_list[key] == 30) {
        eval('PointColor = '+icon_theme+'_backColor_3');
    } else if (filled_list[key] == 40) {
        eval('PointColor = '+icon_theme+'_backColor_4');
    } else if (filled_list[key] == 45) {
        eval('PointColor = '+icon_theme+'_backColor_50');
    } else if (filled_list[key] == 46) {
        eval('PointColor = '+icon_theme+'_backColor_50');
    } else if (filled_list[key] == 50) {
        eval('PointColor = '+icon_theme+'_backColor_55');
    } else if (filled_list[key] == 55) {
        eval('PointColor = '+icon_theme+'_backColor_60');
    } else if (filled_list[key] == 60) {
        eval('PointColor = '+icon_theme+'_backColor_65');
    } else if (filled_list[key] == 70) {
        eval('PointColor = '+icon_theme+'_backColor_7');
    }
    //引数"key"はエリアコード、"PointColor"は塗りつぶし色のHEX値
    FillPolygon(key, PointColor);
+}
```

```diff_javascript:index.js:265
map.addLayer(shindo_layer);
+map.addLayer(shindo_filled_layer);
map.flyTo(shingenLatLng, 7.5, { duration: 0.5 })
```

```diff_javascript:index.js:274
function AreaCodeToName(code) {
    var array_Num = AreaCode.indexOf(code);
    return AreaName[array_Num];
}

+function FillPolygon(area_Code, PointColor) {
    var array_Num = AreaCode.indexOf(area_Code);
    if (array_Num != -1) {
        var style;
        style = {
            "color": "#ffffff",
            "weight": 1.2,
            "opacity": 1,
            "fillColor": PointColor,
            "fillOpacity": 1,
        }
        data_japan = japan_data["features"][array_Num];
        Filled_Layer = L.geoJSON(data_japan, {
            style: style,
            pane: "pane_map_filled",
            onEachFeature: function (feature, layer) {
                if (feature.properties && feature.properties.popupContent) {
                    layer.bindPopup(feature.properties.popupContent);
                }
                layer.myTag = "Filled"
            },
        });
        shindo_filled_layer.addLayer(Filled_Layer);
        let latlon = centerPoint[area_Code];
        // map.addLayer(Filled_Layer);
        // var geodata = data_japan["geometry"]["coordinates"][0];
        // map.eachLayer(function (layer) {
        //     if (layer.myTag && layer.myTag === "Filled") {
        //         latlon = layer.getCenter();
        //     }
        // });
        // map.removeLayer(Filled_Layer);
        return latlon;
    }
+}
```

開発した当初もここらへんは難しかったのでコメントアウトが結構残っていますね。

##### 1つめのコードブロックの解説

まずコメントアウトにもある通り`filled_list`は塗りつぶしの地域とその震度のリストです。
そして、forでの観測点の繰り返しで`filled_list`の更新が終わった後に、`filled_list`の中身を`FillPolygon()`へ渡しています。

##### 2つめのコードブロックの解説
`map.addLayer(shindo_filled_layer);`はまだ解説していませんが、`FillPolygon()`でできた、塗りつぶしのレイヤーを地図に表示させるようにしています。

##### 3つめのコードブロックの解説
```javascript:index.js:279
var array_Num = AreaCode.indexOf(area_Code);
```
まず、`indexOf()`が見つかった場所を返すことから、そのコードの区域が配列の何番目にあるのかを探しています。

```javascript:index.js:280
if (array_Num != -1) {
```
`indexOf()`は見つからなかったときに`-1`を返すことから、 **「検索結果が`-1`ではない」=「探してたものがあった」** という条件分岐をしています。

```javascript:index.js:281
var style;
style = {
    "color": "#ffffff",
    "weight": 1.2,
    "opacity": 1,
    "fillColor": PointColor,
    "fillOpacity": 1,
}
```
そして、`style`で塗りつぶしのポリゴンのスタイルを決めます。
`"fillColor"`の塗りつぶし色の設定のところで、引数のHEX値が入った`PointColor`を設定しています。

```javascript:index.js:289
data_japan = japan_data["features"][array_Num];
```
これで細分区域GeoJSONファイルの中の`array_Num`つまり、細分区域ごとのシェイプを取り出して、先程のスタイルを適用することで塗りつぶししています。

```javascript:index.js:290
Filled_Layer = L.geoJSON(data_japan, {
    style: style,
    pane: "pane_map_filled",
    onEachFeature: function (feature, layer) {
        if (feature.properties && feature.properties.popupContent) {
            layer.bindPopup(feature.properties.popupContent);
        }
        layer.myTag = "Filled"
    },
});
```
ここでさきほどの`data_japan`を使って、ポリゴンの作成をしています。

```javascript:index.js:300
shindo_filled_layer.addLayer(Filled_Layer);
```
`shindo_filled_layer`というレイヤーに、一旦`Filled_Layer`さきほどの塗りつぶしした細分区域のポリゴンを追加しています。（まだ地図上には表示されていません。）

```javascript:index.js:301
let latlon = centerPoint[area_Code];
// map.addLayer(Filled_Layer);
// var geodata = data_japan["geometry"]["coordinates"][0];
// let latlon;
// map.eachLayer(function (layer) {
//     if (layer.myTag && layer.myTag === "Filled") {
//         latlon = layer.getCenter();
//     }
// });
// map.removeLayer(Filled_Layer);
return latlon;
```
~~ここは後々出てくる震度速報の描画のためのコードです。
一旦細分区域を地図に表示して、中心座標を求め、地図から削除して、中心座標を返り値で戻りています。~~
うんたらかんたらのんべんだらりと書いて、カスみたいな精度の中心座標を求めるくらいだったら、中心座標をまとめたデータベースを作ってしまえばええやんということで作りました。
`centerPoint[area_Code]`は`centerPoint`という座標が連想配列形式で格納されているものの中から`area_Code(702)`とかを抜き出す操作をしています。


:::note info
~~今さらやっと気づいたのですが、この`polygon.getCenter()`はどのような仕組みはわかりませんが、都道府県に離れている島等があると、一気に座標がずれます。
そのため、細分区域名とその中心座標をまとめたJSONファイルを用意しとけばよかったと思います。
細分区域は簡単に増えるものでもありませんし…~~
**↑中心座標をまとめたJSONを作りました。
[ `JMAstations.json` ](https://nanka.cloudfree.jp/webapps/shindobunpu/source/old/JMAstations.json)を更新しているので再ダウンロードしておいてください。**
:::

### 塗りつぶし完成！
さて、これで塗りつぶしができました！
今の状況はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637649/6524c0c4-95b1-510b-2707-36e247d0ff2c.png)

さて、今回はこんなところにしておこうと思います。
前の更新が7月…、そして今はもう12月真ん中…。
夏クソ暑かったのが今となってやもうクソ寒くなってきております。
更新できていなくて本当にすみません。

## 終わりに
今回はちょっとした改修と、塗りつぶしをやっていきました。
次こそはこんな長い期間サボっていないですぐに投稿したいと思います。
次は今回できていない、各地の震度と震度速報のところを作っていきましょう！

今回のサンプル
[https://nanka.cloudfree.jp/bin/webapps/shindobunpu_qiita/8/](https://nanka.cloudfree.jp/bin/webapps/shindobunpu_qiita/8/)

<details><summary>今回のソースコード</summary>

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <title>震度分布図</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <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>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://nanka.cloudfree.jp/static/font/fonts.css">
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <div id="map"></div>
    <div class="btns">
        <select id="quakelist"><option>地震情報の取得中…</option></select>
        <span class="setsumei" style="padding: 0;padding-right: 5px;"><button id="reload">情報更新</button> <input type="number" id="reload_num" value="20" max="100">件</span>
    </div>
    <script src="source/SmoothWheelZoom.js"></script>
    <script src="../JMAPoints.js"></script>
    <script src="index.js"></script>
</body>
</html>
```

```javascript:index.js
var QuakeJson;
var JMAPointsJson;

var map = L.map('map', {
    preferCanvas: false,
    scrollWheelZoom: false,
    smoothWheelZoom: true,
    smoothSensitivity: 1.5,
}).setView([36.575, 137.984], 6);
L.control.scale({ maxWidth: 150, position: 'bottomright', imperial: false }).addTo(map);
map.zoomControl.setPosition('topright');
map.attributionControl.addAttribution(
    "<a href='https://www.jma.go.jp/jma/index.html' target='_blank'>気象庁</a>"
);
map.attributionControl.addAttribution(
    "<a href='https://github.com/mutsuyuki/Leaflet.SmoothWheelZoom' target='_blank'>SmoothWheelZoom</a>"
);

//地図に表示させる上下の順番
map.createPane("pane_map1").style.zIndex = 1; //地図（背景）
map.createPane("pane_map2").style.zIndex = 2; //地図（市町村）
map.createPane("pane_map3").style.zIndex = 3; //地図（細分）
map.createPane("pane_map_filled").style.zIndex = 5; //塗りつぶし
map.createPane("shindo10").style.zIndex = 10;
map.createPane("shindo20").style.zIndex = 20;
map.createPane("shindo30").style.zIndex = 30;
map.createPane("shindo40").style.zIndex = 40;
map.createPane("shindo45").style.zIndex = 45;
map.createPane("shindo46").style.zIndex = 46;
map.createPane("shindo50").style.zIndex = 50;
map.createPane("shindo55").style.zIndex = 55;
map.createPane("shindo60").style.zIndex = 60;
map.createPane("shindo70").style.zIndex = 70;
map.createPane("shingen").style.zIndex = 100; //震源
map.createPane("tsunami_map").style.zIndex = 110; //津波

var PolygonLayer_Style_nerv = {
    "color": "#ffffff",
    "weight": 1.5,
    "opacity": 1,
    "fillColor": "#3a3a3a",
    "fillOpacity": 1
}

var japan_data;
$.getJSON("../saibun.geojson", function (data) {
    japan_data = data;
    L.geoJson(data, {
        pane: "pane_map3",
        style: PolygonLayer_Style_nerv
    }).addTo(map);
});

$.getJSON("../JMAstations.json", function (data) {
    JMAPointsJson = data;
    GetQuake();
});

//ボタン押下時のイベント設定とローカルストレージの設定
document.getElementById('reload').addEventListener("click",()=>{
    if (document.getElementById('reload_num').value != "") {
        if (document.getElementById('reload_num').value > 100 || document.getElementById('reload_num').value <= 0) {
            GetQuake(100);
        } else {
            GetQuake(document.getElementById('reload_num').value);
        }
    } else {
        GetQuake();
    }
    document.getElementById('reload').innerText = "更新中…";
    setTimeout(() => {
        document.getElementById('reload').innerText = "更新完了";
        setTimeout(() => {
            document.getElementById('reload').innerText = "情報更新";
        }, 1000);
    }, 1000);
});

function GetQuake(option) {
    var url;
    if (!isNaN(option)) {
        url = "https://api.p2pquake.net/v2/history?codes=551&limit="+option;
    } else {
        url = "https://api.p2pquake.net/v2/history?codes=551&limit=20";
    }
    $.getJSON(url, function (data) {
        QuakeJson = data;

        while (document.getElementById('quakelist').lastChild) {
            document.getElementById('quakelist').removeChild(document.getElementById('quakelist').lastChild);
        }
    
        var forEachNum = 0;
        data.forEach(element => {
            var option = document.createElement("option");
            var text;
            let maxInt_data = element['earthquake']['maxScale'];
            let maxIntText = hantei_maxIntText(maxInt_data);
            let Name = hantei_Name(element['earthquake']['hypocenter']['name']);
            let Time = element['earthquake']['time'];
            if (element["issue"]["type"] == "ScalePrompt") {
                text = "【震度速報】" + element["points"][0]["addr"] + "など " + "\n" + Time.slice(0, -3) + "\n最大震度 : " + maxIntText;
            } else if (element["issue"]["type"] == "Foreign") {
                text = "【遠地地震】" + Time.slice(0, -3) + " " + Name;
            } else {
                text = Time.slice(0, -3) + " " + Name + " " +  "\n" + "\n最大震度 : " + maxIntText;
            }
            option.value = "" + forEachNum + "";
            option.textContent = text;
            document.getElementById('quakelist').appendChild(option);
            forEachNum++;
        });
    
        //地震情報リストをクリックしたときの発火イベント
        var list = document.getElementById('quakelist');
        list.onchange = event => {
            QuakeSelect(list.selectedIndex);
        }
        
        QuakeSelect(0);
    });
}

var shingenIcon;
var shindo_icon;
var shindo_layer = L.layerGroup();
var shindo_filled_layer = L.layerGroup();
var filled_list = {};

function QuakeSelect(num) {
    if (shingenIcon && shindo_layer && shindo_filled_layer) {
        map.removeLayer(shingenIcon);
        map.removeLayer(shindo_layer);
        map.removeLayer(shindo_filled_layer);
        shingenIcon = "";
        shindo_layer = L.layerGroup();
        shindo_filled_layer = L.layerGroup();
        filled_list = {};
        shindo_icon = "";
    }
    let maxInt_data = QuakeJson[num]['earthquake']['maxScale'];
    var maxIntText = hantei_maxIntText(maxInt_data);
    var Magnitude = hantei_Magnitude(QuakeJson[num]['earthquake']['hypocenter']['magnitude']);
    var Name = hantei_Name(QuakeJson[num]['earthquake']['hypocenter']['name']);
    var Depth = hantei_Depth(QuakeJson[num]['earthquake']['hypocenter']['depth']);
    var tsunamiText = hantei_tsunamiText(QuakeJson[num]['earthquake']['domesticTsunami']);
    var Time = QuakeJson[num]['earthquake']['time'];

    var shingenLatLng = new L.LatLng(QuakeJson[num]["earthquake"]["hypocenter"]["latitude"], QuakeJson[num]["earthquake"]["hypocenter"]["longitude"]);
    var shingenIconImage = L.icon({
        iconUrl: 'source/shingen.png',
        iconSize: [40, 40],
        iconAnchor: [20, 20],
        popupAnchor: [0, -40]
    });
    shingenIcon = L.marker(shingenLatLng, {icon: shingenIconImage }).addTo(map);
    shingenIcon.bindPopup('発生時刻：'+Time+'<br>最大震度：'+maxIntText+'<br>震源地：'+Name+'<span style=\"font-size: 85%;\"> ('+QuakeJson[num]["earthquake"]["hypocenter"]["latitude"]+", "+QuakeJson[num]["earthquake"]["hypocenter"]["longitude"]+')</span><br>規模：M'+Magnitude+'　深さ：'+Depth+'<br>受信：'+QuakeJson[num]['issue']['time']+', '+QuakeJson[num]['issue']['source'],{closeButton: false, zIndexOffset: 10000, maxWidth: 10000});
    shingenIcon.on('mouseover', function (e) {this.openPopup();});
    shingenIcon.on('mouseout', function (e) {this.closePopup();});

    if (QuakeJson[num]["issue"]["type"] != "ScalePrompt") { //各地の震度に関する情報
        //観測点の震度についてすべての観測点に対して繰り返す
        QuakeJson[num]["points"].forEach(element => {
        var result = JMAPoints.indexOf(element["addr"]);
        if (result != -1) {
            var ImgUrl = "";
            var PointShindo = "";
            var icon_theme = "jqk";
            if (element["scale"] == 10) {
                ImgUrl = "source/"+icon_theme+"_int1.png";
                PointShindo = "震度1";
            } else if (element["scale"] == 20) {
                ImgUrl = "source/"+icon_theme+"_int2.png";
                PointShindo = "震度2";
            } else if (element["scale"] == 30) {
                ImgUrl = "source/"+icon_theme+"_int3.png";
                PointShindo = "震度3";
            } else if (element["scale"] == 40) {
                ImgUrl = "source/"+icon_theme+"_int4.png";
                PointShindo = "震度4";
            } else if (element["scale"] == 45) {
                ImgUrl = "source/"+icon_theme+"_int50.png";
                PointShindo = "震度5弱";
            } else if (element["scale"] == 46) {
                ImgUrl = "source/"+icon_theme+"_int_.png";
                PointShindo = "震度5弱以上と推定";
            } else if (element["scale"] == 50) {
                ImgUrl = "source/"+icon_theme+"_int55.png";
                PointShindo = "震度5強";
            } else if (element["scale"] == 55) {
                ImgUrl = "source/"+icon_theme+"_int60.png";
                PointShindo = "震度6弱";
            } else if (element["scale"] == 60) {
                ImgUrl = "source/"+icon_theme+"_int65.png";
                PointShindo = "震度6強";
            } else if (element["scale"] == 70) {
                ImgUrl = "source/"+icon_theme+"_int7.png";
                PointShindo = "震度7";
            } else {
                ImgUrl = "source/"+icon_theme+"_int_.png";
                PointShindo = "震度不明";
            }
            if (element["isArea"] == false) { //観測点
                let shindo_latlng = new L.LatLng(JMAPointsJson[result]["lat"], JMAPointsJson[result]["lon"]);
                let shindoIcon = L.icon({
                    iconUrl: ImgUrl,
                    iconSize: [20, 20],
                    popupAnchor: [0, -40]
                });
                let shindoIcon_big = L.icon({
                    iconUrl: ImgUrl,
                    iconSize: [34, 34],
                    popupAnchor: [0, -40]
                });
                shindo_icon = L.marker(shindo_latlng, { icon: shindoIcon,pane: eval('\"shindo'+element["scale"]+'\"') });
                shindo_icon.bindPopup('<ruby>'+element["addr"] + '<rt style="font-size: 0.7em;">' + JMAPointsJson[result]["furigana"] + '</rt></ruby>　'+ PointShindo,{closeButton: false, zIndexOffset: 10000,autoPan: false,});
                shindo_icon.on('mouseover', function (e) {
                    this.openPopup();
                });
                shindo_icon.on('mouseout', function (e) {
                    this.closePopup();
                });
                shindo_layer.addLayer(shindo_icon);

                //塗りつぶしの設定をする
                //AreaNameToCode()は下を参照。大阪府北部を520等に変換
                //filled_listは連想配列で{520: 10, 120: 20}など、エリアコード: 震度の大きさ
                var areaCode = AreaNameToCode(JMAPointsJson[result]["area"]["name"]);
                //filled_listにエリアコードがなかったり、さらに大きな震度になっていたら更新
                if ((!filled_list[areaCode]) || filled_list[areaCode] < element["scale"]) {
                    filled_list[areaCode] = element["scale"];
                }
            }
            //for(... in ...)もforEachと同等。keyに連想配列の名前が入る
            for (key in filled_list){ 
                var PointColor;
                if (filled_list[key] == 10) {
                    eval('PointColor = '+icon_theme+'_backColor_1');
                } else if (filled_list[key] == 20) {
                    eval('PointColor = '+icon_theme+'_backColor_2');
                } else if (filled_list[key] == 30) {
                    eval('PointColor = '+icon_theme+'_backColor_3');
                } else if (filled_list[key] == 40) {
                    eval('PointColor = '+icon_theme+'_backColor_4');
                } else if (filled_list[key] == 45) {
                    eval('PointColor = '+icon_theme+'_backColor_50');
                } else if (filled_list[key] == 46) {
                    eval('PointColor = '+icon_theme+'_backColor_50');
                } else if (filled_list[key] == 50) {
                    eval('PointColor = '+icon_theme+'_backColor_55');
                } else if (filled_list[key] == 55) {
                    eval('PointColor = '+icon_theme+'_backColor_60');
                } else if (filled_list[key] == 60) {
                    eval('PointColor = '+icon_theme+'_backColor_65');
                } else if (filled_list[key] == 70) {
                    eval('PointColor = '+icon_theme+'_backColor_7');
                }
                //引数"key"はエリアコード、"PointColor"は塗りつぶし色のHEX値
                FillPolygon(key, PointColor);
            }
        }
        });
    }
    map.addLayer(shindo_layer);
    map.addLayer(shindo_filled_layer);
    map.flyTo(shingenLatLng, 7.5, { duration: 0.5 })
}

function AreaNameToCode(Name) {
    var array_Num = AreaName.indexOf(Name);
    return AreaCode[array_Num];
}
function AreaCodeToName(code) {
    var array_Num = AreaCode.indexOf(code);
    return AreaName[array_Num];
}

function FillPolygon(area_Code, PointColor) {
    var array_Num = AreaCode.indexOf(area_Code);
    if (array_Num != -1) {
        var style;
        style = {
            "color": "#ffffff",
            "weight": 1.2,
            "opacity": 1,
            "fillColor": PointColor,
            "fillOpacity": 1,
        }
        data_japan = japan_data["features"][array_Num];
        var Filled_Layer = L.geoJSON(data_japan, {
            style: style,
            pane: "pane_map_filled",
            onEachFeature: function (feature, layer) {
                if (feature.properties && feature.properties.popupContent) {
                    layer.bindPopup(feature.properties.popupContent);
                }
                layer.myTag = "Filled"
            },
        });
        shindo_filled_layer.addLayer(Filled_Layer);
        map.addLayer(Filled_Layer);
        var geodata = data_japan["geometry"]["coordinates"][0];
        let latlon;
        map.eachLayer(function (layer) {
            if (layer.myTag && layer.myTag === "Filled") {
                latlon = layer.getCenter();
            }
        });
        map.removeLayer(Filled_Layer);
        return latlon;
    }
}

function hantei_maxIntText(param) {
    let kaerichi = param == 10 ? "1" : param == 20 ? "2" : param == 30 ? "3" : param == 40 ? "4" :
    param == 45 ? "5弱" : param == 46 ? "5弱" : param == 50 ? "5強" : param == 55 ? "6弱" :
    param == 60 ? "6強" : param == 70 ? "7" : "不明";
    return kaerichi;
}
function hantei_Magnitude(param) {
    let kaerichi = param != -1 ? param.toFixed(1) : 'ー.ー';
    return kaerichi;
}
function hantei_Name(param) {
    let kaerichi = param != "" ? param : '情報なし';
    return kaerichi;
}
function hantei_Depth(param) {
    let kaerichi = param != -1 ? "約"+param+"km" : '不明';
    return kaerichi;
}
function hantei_tsunamiText(param) {
    let kaerichi = param == "None" ? "なし" :
    param == "Unknown" ? "不明" :
    param == "Checking" ? "調査中" :
    param == "NonEffective" ? "若干の海面変動" :
    param == "Watch" ? "津波注意報" :
    param == "Warning" ? "津波警報" : "情報なし";
    return kaerichi;
}
```

```css:index.css
html, body, #map {
    width: 100%;
    height: 100%;
    margin: 0;
}
#map {
    background: #1d1d1d;
}

.btns {
    position: absolute;
    bottom: 10px;
    left: 10px;
    z-index: 10000;
    user-select: none;
}
.setsumei, #quakelist, #reload, #map_ichi, #test, #btn_shindo_ichiran, #autoreload, #display_onoff_point_check, #view_info {
    display: inline-block;
    background: #00000088;
    border: white 2.5px solid;
    border-radius: 5px;
    color: white;
    padding: 5px;
    font-family: "ヒラギノ角ゴ-Pro",'Noto Sans JP';
    font-weight: 500;
    font-size: 0.8rem;
    cursor: pointer;
}
#reload, #autoreload {
    background: #00000000;
    padding: 5px;
    border: none;
}
#reload_num, #autoreload_num {
    background: #00000000;
    border: 0;
    width: 2rem;
    font-family: "ヒラギノ角ゴ-Pro",'Noto Sans JP';
    font-weight: 500;
    font-size: 0.9rem;
    color: white;
    border-bottom: #ffffff 1px solid;
}
select, input, button {
    outline: none;
}
input[type="number"]::-webkit-outer-spin-button, 
input[type="number"]::-webkit-inner-spin-button { 
    -webkit-appearance: none; 
    margin: 0; 
} 
input[type="number"] { 
    -moz-appearance:textfield; 
} 
.setsumei {
    cursor: default;
}
#quakelist {
    width: 25em;
    height: calc(2em + 5px);
}

.leaflet-fade-anim .leaflet-popup {
    transition: 0s;
}
.leaflet-popup-content-wrapper {
	background-color: rgba(255, 255, 255, 0.85);
    box-shadow: 0px 3px 7px 2px rgba(0, 0, 0, 0.4);
    border-radius: 0!important;
    font-family: "ヒラギノ角ゴ-Pro",'Noto Sans JP';
    font-weight: 500;
    user-select: none;
	margin-bottom: 0;
}
.leaflet-popup-content {
    color: black !important;
    font-size: 1.2rem;
    margin: 10px 8px 8px 8px;
}
.leaflet-popup-tip-container {
    display: none;
}
```

</details>

## 次回予告

https://qiita.com/kottaro123456/items/bf750bd6c89291999485