GoogleMapsAPIでハマった話

私が業務中にGoogleMapsAPIでハマった話についての備忘録です。
# GoogleMapsAPIについて
GoogleMapsAPIとは、Googleマップを表示する際に独自にカスタマイズして使用できるようにするAPIです。
GoogleマップをカスタマイズするためのAPIは大きく分けて「モバイルAPI」「ウェブAPI」「ウェブサービスAPI」の3つのようです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628676/7e484e7e-da0f-3701-2ca9-f685cb17fba2.png)
今回使用したのはウェブAPIの「JavaScript API」


# 本題
シナリオテスト中に「検索結果が1件の時にリクエストが再度送られている」という不具合が発生しました。

以下が実際のコードの省略版になります。
```javascript:maps.js
this.map = new this.google.maps.Map(target, {
    ~~~ 省略 ~~~
});

//検索ボタンクリック
onClickSearchButton() {
    this.isClick = true;

    //APIリクエスト呼び出し
    this.search();

    //マーカー作成
    this.createMarker();

    //マーカーがすべて見えるようにマップを描画
    this.setAllMarkersVisibleBounds();
},

//APIリクエスト
search() {
    console.log('検索中(click_button)');

    this.google.maps.event.addListener(this.map, 'zoom_changed', () => {
        //検索ボタンでの検索時は、zoom_changedイベントでの検索は行わない
        if (this.isClick) {
            this.isClick = false;
            return;
        }
        console.log('検索中(zoom_changed)');
    });
},

//マーカー作成
createMarker() {
    console.log('マーカー作成');
},

//マーカーをすべて描画
setAllMarkersVisibleBounds() {
    console.log('マーカーをすべて描画');
    this.map.fitBounds();
}
```

このコードで検索ボタンクリックの検索処理を実行すると以下の出力結果になります。
```console:出力結果
検索中(click_button)
マーカー作成
マーカーをすべて描画
検索中(zoom_changed)
```

検索ボタンでの検索時は`zoom_changed`イベントでは何も行わないようにしているはずなのに
`zoom_changed`イベントの検索が走ってしまっています。

その原因は`this.map.fitbounds()`にありました。

# fitboundsとは
下の画像のようにマーカーが見切れてるのを右の画像のように描画範囲にマーカーを表示し
てくれるメソッドです。
![キャプチャ4-1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628676/fb4faf43-db4a-a0f8-c07e-ea5759984f6c.png)
↓↓↓↓↓↓↓↓↓↓↓↓↓↓
![キャプチャ4-2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628676/5575713d-10c1-4994-b6be-175290c7dab6.png)


しかし、検索結果が1件だった場合にfitboundsを使用すると以下のように
ズームレベルを最大にしてしまうようなのです。
![キャプチャ5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628676/d2774278-1b77-10ac-24a7-59de2987315a.png)
これだけならまだよかったのですが何やら挙動がおかしい。

極限までズームしようとして失敗。
しょうがないからズームレベルを最大（レベル22）に設定。
という変な挙動をしてるらしい。

# コード修正

以下が修正したコードです。
```javascript:maps.js
this.map = new this.google.maps.Map(target, {
    ~~~ 省略 ~~~
});

//検索ボタンクリック
onClickSearchButton() {
    //初回ズームフラグ・・・修正１
    this.isInitialZoom = true;
    this.isClick = true;

    //APIリクエスト呼び出し
    this.search();

    //マーカー作成
    this.createMarker();

    //マーカーがすべて見えるようにマップを描画
    this.setAllMarkersVisibleBounds();
},

//APIリクエスト
search() {
    console.log('検索中(click_button)');

    //マップの描画完了時・・・修正２
    this.google.maps.event.addListener(this.map, 'tilesloaded', () => {
        this.isInitialZoom = false;
    });

    this.google.maps.event.addListener(this.map, 'zoom_changed', () => {
        //検索ボタンでの検索時は、zoom_changedイベントでの検索は行わない
        if (this.isClick) {
            this.isClick = false;
            return;
        }
        //修正３
        if (!this.isInitialZoom) {
            console.log('検索中(zoom_changed)');
        }
    });
},

//マーカー作成
createMarker() {
    console.log('マーカー作成');
},

//マーカーをすべて描画
setAllMarkersVisibleBounds() {
    console.log('マーカーをすべて描画');
    this.map.fitBounds();
}
```

1.初回ズームフラグを立てる
2.tilesloadedイベント時（マップの描画完了時）に初回ズームフラグをfalseに変更
3.zoom_changedイベント時の検索は初回ズームフラグがfalseの時のみ実行されるように修正

これでバグともおさらばです。

# まとめ
今回の不具合について、どこで調べても「初回ズームフラグを噛ませればいけるよ」
みたいなことしか書いてなかったがうまくいきませんでした。

zoom_changedイベントが終わったタイミングにちょうどかみ合ったのがtilesloadedイベントだったため、これを使ってみたら見事にうまくいったという話でした。

以上、ありがとうございました。