Google Mapsでマーカーラベルを大量に付けると ごちゃごちゃになるのを解決する

今日もまた「[霊園ガイド](https://reien.top)サイト開発日記」のスタイルで書いてみます。

今回は[前回](https://qiita.com/toshirot/items/5f2b5abfe51b1ec570bf)のGoogle Maps APIの記事のシリーズになります。

[霊園ガイド](https://reien.top)は一目でわかる通り、Google Mapsなどの枯れたマッシュアップを中心に据えています。そんなわけで、Google Maps APIのネタには事欠きません(^^; <br>[<img width=200 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7103/62c49e0e-d2e3-e487-e9d9-31112bd3f602.png">霊園ガイドサイト](https://reien.top/)　

さて、今日取り上げるのは「Google Mapsでマーカーラベルを大量に付けると
ごちゃごちゃになる問題」です。

つまりこれですね。下の2枚の画像の左側は、zoomが16の時のものですが、そのズームを12にすると文字がごちゃごちゃになって読めなくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7103/47081d90-a45f-a485-03d5-2ed47f6e629f.png)

### 動作を確認してみる

では実際に目で見て確認してみましょう。
<b>デモページ:</b>  https://reien.top/blog/test/gmap/marker/2020-11-12-1.html

デモページにいてみると下の画像のようにズームボタンのついた地図があります。これをクリックしてズーム値を低い値(たとえば12)にすると字が読めなくなるのを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7103/4eab6240-d896-5903-c487-d3cbef50b7a3.png)

つまり地図を俯瞰するとこうなってしまうわけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7103/bdeb2e7b-8041-dc16-e72d-e60b40afe33a.png)

因みに今回使ったデータは、国土交通省の下記を使わせていただきました。ありがとうございます(_ _)<br>
位置参照情報 ダウンロードサービス
<li><a href="https://nlftp.mlit.go.jp/cgi-bin/isj/dls/_download_files.cgi">https://nlftp.mlit.go.jp/cgi-bin/isj/dls/_download_files.cgi</a>　

### 対策の方針を考えてみる

この対策もいくつか考えられると思いますが、今日は「<b>ズーム値が下がったら(俯瞰したら)マーカーラベルを消す</b>」という方向で対策してみようと思います。

Google Maps API では

1.ズーム値は map.getZoom() メソッドで取得できます。
2.ズームの変更は map.addListener("zoom_changed") リスナで取得できます

一応これをおさえてマーカーの書き換え操作などを加えるとおおむねこの対策ができるようになります。今回はアニメーションを最初だけに限定するというフラグも立てて操作してみました。

### 今回の対策

これも実際に目で見て確認してみましょう。
<b>デモページ:</b>  https://reien.top/blog/test/gmap/marker/2020-11-12-2.html

このページも上と沿うようにズームボタンが並んでいるので押してみると、zoom 13以下でラベル文字が消えるのが判ります。

そしてデモページでズーム値を操作してみるとわかりますが、たとえば zoom 13だとこうなり、文字が消えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7103/646ca8ce-13b5-072a-006c-faea1375ace5.png)


### 対策前のコードと対策後のコード

一応いま急いで書いたざっくりしたサンプルですが、参考までに置いておきます。google Maps のapiキーはご自身で取得したものをお使いください。サイトにおいてコンソール上でそのサイトを許可する必要がありますがそのあたりは下に書いた参考ページが判りやすいです。

対策前

```html
<div id="map" style="width:90%;height:60%"></div>

<script>
    let lists=`"13","東京都","13101","千代田区","131010001002","内幸町二丁目","35.670812","139.754182","0","3"
"13","東京都","13101","千代田区","131010001001","内幸町一丁目","35.670839","139.758119","0","3"
"13","東京都","13101","千代田区","131010002003","霞が関三丁目","35.671825","139.746988","0","3"
"13","東京都","13101","千代田区","131010003000","北の丸公園","35.691555","139.751639","0","1"
   //(省略)
`

let map //ここではmap だけあとでzoomを操作するためにグローバルにおいておきます

//地図を描画する
function initMap(){

    //中心の経緯度
    let lat=35.688069 
    let lng=139.763929

    //経緯度のインスタンスを作る
    let centerlocation = new google.maps.LatLng(
        lat,
        lng
    );

    //DOM要素id map に地図を描画する
    map = new google.maps.Map(document.getElementById("map"), {
        center: centerlocation,
        zoom: 16, //ズーム値
    });
    //経緯度のインスタンスを作る
    let mylocation = new google.maps.LatLng(
        lat,//経度
        lng//経度
    );

    //マーカーを描く
    drawMarkers(map, lists)
}

//データcsvから町名と経緯度を取り出しマーカーを描く
function drawMarkers(map, lists){

    //データcsvから町名と経緯度を取り出す
    let lines=lists.split('\n')//行で分解し配列にする
    //行を回してデータを取り出す
    for(let i=0;i<lines.length;i++){
        let line=lines[i]
        let cols=line.split(',')//列で分解し配列にする

        //マーカーを描く "霞が関一丁目" "35.673944" "139.752558" 
        mkMarker(
            map
            //町名は5番目の列にある
            , cols[5] 
            //latは6番目の列にある
            //単に+やparseFloatでは数値化できなかったので+JSON.parseした
            , +JSON.parse(cols[6]) 
            //lngは7番目の列にある
            , +JSON.parse(cols[7])  
        )
    }
}

//マーカーを描く
function mkMarker(map, name, lat, lng){

    //経緯度のインスタンスを作る
    let mylocation = new google.maps.LatLng(
        lat,//経度
        lng//経度
    );
    //マーカーを描く
    let cityMarker=new google.maps.Marker({
        position: mylocation,//経緯度
        icon: {
            path: google.maps.SymbolPath.CIRCLE,//シンボル円
            scale: 6,          //アイコンサイズ
            fillColor: '#fff',  //塗り潰し色
            fillOpacity: 0.8,   //塗り潰し透過率
            strokeColor: "red", //枠線の色
            strokeWeight: 8,    //枠線の幅
        },
        label: {
            text:  name,           //ラベル文字
            color: 'oraneg',       //文字の色
            fontSize: '12px',      //文字のサイズ
            fontWeight: '900'      //文字の太さ
        },
        draggable: false, //ドラッグしたいならtrue
        map: map, //地図オブジェクト
        animation:  google.maps.Animation.DROP //マーカーアニメーション
    });
}

</script>
<script 
    src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC0BiR5x2hwF3Tj2IQZadRHOLOSznUzXQI&callback=initMap"
    async defer>
</script>
```

対策後

```html
<div id="map" style="width:90%;height:60%"></div>

<script>
    let lists=`"13","東京都","13101","千代田区","131010001002","内幸町二丁目","35.670812","139.754182","0","3"
"13","東京都","13101","千代田区","131010001001","内幸町一丁目","35.670839","139.758119","0","3"
"13","東京都","13101","千代田区","131010002003","霞が関三丁目","35.671825","139.746988","0","3"
"13","東京都","13101","千代田区","131010003000","北の丸公園","35.691555","139.751639","0","1"
   //(省略)
`

let map //ここではmap だけあとでzoomを操作するためにグローバルにおいておきます
let cityMarkers=[]

//地図を描画する
function initMap(){

    //中心の経緯度
    let lat=35.688069 
    let lng=139.763929

    //経緯度のインスタンスを作る
    let centerlocation = new google.maps.LatLng(
        lat,
        lng
    )

    //DOM要素id map に地図を描画する
    map = new google.maps.Map(document.getElementById("map"), {
        center: centerlocation,
        zoom: 16, //ズーム値
    })

    //ズーム後にzoom値がマーカーを再描画する
    map.addListener("zoom_changed", () => {
        reSetMarkers()
        if(map.getZoom()<14){
            //14未満はラベルなし
            drawMarkers(map, lists, false, false)
        } else {
            //14以上はラベルあり
            drawMarkers(map, lists, true, false)
        }
        
    })

    //マーカーを描く
    drawMarkers(map, lists, true, true)
}

//マーカーをリセットする
function reSetMarkers(){
    for(let i=0;i<cityMarkers.length;i++){
        cityMarkers[i].setMap(null)
    }
}

//データcsvから町名と経緯度を取り出しマーカーを描く
function drawMarkers(map, lists, labelFlg, animeFlg){

    //データcsvから町名と経緯度を取り出す
    let lines=lists.split('\n')//行で分解し配列にする
    //行を回してデータを取り出す
    for(let i=0;i<lines.length;i++){
        let line=lines[i]
        let cols=line.split(',')//列で分解し配列にする

        //マーカーを描く "霞が関一丁目" "35.673944" "139.752558" 
        mkMarker(
            map
            //町名は5番目の列にある
            , cols[5] 
            //latは6番目の列にある
            //単に+やparseFloatでは数値化できなかったので+JSON.parseした
            , +JSON.parse(cols[6]) 
            //lngは7番目の列にある
            , +JSON.parse(cols[7])
            ,labelFlg
            ,animeFlg
        )
    }
}

//マーカーを描く
function mkMarker(map, name, lat, lng, labelFlg, animeFlg){
    
    //経緯度のインスタンスを作る
    let mylocation = new google.maps.LatLng(
        lat,//経度
        lng//経度
    );

    // icon設定
    let icon= {
        path: google.maps.SymbolPath.CIRCLE,//シンボル円
        scale: 6,          //アイコンサイズ
        fillColor: '#fff',  //塗り潰し色
        fillOpacity: 0.8,   //塗り潰し透過率
        strokeColor: "red", //枠線の色
        strokeWeight: 8,    //枠線の幅
    }

    //labelフラグによるoption設定分岐
    if(!labelFlg){
        option={
            position: mylocation,//経緯度
            icon: icon,
            draggable: false, //ドラッグしたいならtrue
            map: map, //地図オブジェクト
        }
    } else {
        option={
            position: mylocation,//経緯度
            icon: icon,
            label: {
                text:  name,           //ラベル文字
                color: 'oraneg',       //文字の色
                fontSize: '12px',      //文字のサイズ
                fontWeight: '900'      //文字の太さ
            },
            draggable: false, //ドラッグしたいならtrue
            map: map, //地図オブジェクト
        }
    }

    //マーカーを描く
    let cityMarker=new google.maps.Marker(option);
    //マーカーアニメーションは最初だけにしておく
    if(!!animeFlg){
        cityMarker.setAnimation(google.maps.Animation.DROP)
    } else {
        cityMarker.setAnimation(null);
    }
    //マーカー配列に入れておく
    cityMarkers.push(cityMarker)

}

</script>
<script 
    src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC0BiR5x2hwF3Tj2IQZadRHOLOSznUzXQI&callback=initMap"
    async defer>
</script>

```

###参考
霊園ガイドサイト（ここのCTOやってます）
https://reien.top/

Google maps APIで東京駅を表示する方法(事前準備(APIキー取得)方法など)
https://qiita.com/Jenny1025/items/74935088ced3f70893da

Maps JavaScript API
https://developers.google.com/maps/documentation/javascript/overview
APIキーを取得する
https://developers.google.com/maps/documentation/javascript/get-api-key