Vue CLIでGoogle Maps APIを使う

Vue CLIを使ったWEBアプリ開発の中でGoogle Maps APIを利用したのでそのメモです。
（韓国アイドルのSEVENTEENが日本で訪れた場所を地図に表示する趣味全開のアプリです🫠）

⏬GitHubはこちらから

https://github.com/buuibuui/SEVENTEEN-visited-map

## 💎 環境
Vue(2.6.14)
Google Maps API(1.1.1)

:::note warn
APIキーは事前に取得しているものとします
:::

## 💎 アプリ画面
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178942/5958415e-59b9-7553-2b93-01ccd33724b9.png"/>

## 💎 コード
※関係する部分のみ
```vuejs:component.vue
<template>
    <div>
		<div id="google-map" class="google-map" ref="googleMap">
            <!-- Google Map表示 -->
        </div>
    </div>
</template>

<script>
import GoogleMapsApiLoader from 'google-maps-api-loader';

export default {
    data: () => {
        return {
            google: null,
            map: null,
            geocoder: null,
            // Markerを複数表示するので、配列に入れていきます
            marker: [],
            // オリジナルのアイコン画像
            iconImg: '/images/diamond-shadow.png',
            // 初期設定
            mapConfig: {
                // 初期表示のズーム具合
                zoom: 14,
                // 初期表示のセンター
                center: {
                    lat: 35.6596043,
                    lng: 139.6987104
                },
                // デフォルトUIを無効にする
                disableDefaultUI: true,
                styles: [
                    /* Google mapカスタムのスタイル（） */
                ]
            },
        }
    },
    async mounted() {
        // Google Map APIの読み込み
        const apiKey = process.env.VUE_APP_GOOGLE_MAPS_API_KEY;
        const googleMapApi = await GoogleMapsApiLoader({
        apiKey: apiKey
        });
        this.google = googleMapApi;

        this.initializeMap();
        this.createMarkers();
		
    },
    methods: {
        initializeMap() {
            const mapContainer = document.getElementById('google-map');
            this.map = new this.google.maps.Map(
                mapContainer, this.mapConfig
        )},
        // Markerを作成する関数
        createMarkers() {
            // displayingPlaceListの要素数だけ繰り返し
            for (let i = 0; i < this.displayingPlaceList.length; i++) {
                // もしlatlngの値が無い場合、Markerを作成しない
                if( this.displayingPlaceList[i]['lat'] != null && this.displayingPlaceList[i]['lng'] != null ) {
                    const markerLatLng = new this.google.maps.LatLng({
                        // それぞれのlatlngを設定
                        lat: this.displayingPlaceList[i]['lat'],
                        lng: this.displayingPlaceList[i]['lng']
                    });
                    // Markerを作成する
                    this.marker[i] = new this.google.maps.Marker({
                        position: markerLatLng,
                        map: this.map,
                        icon: {
                            url: this.iconImg,
                            scaledSize: new this.google.maps.Size(40, 40),
                        }
                    });
                    // それぞれのMarkerに合った情報ウィンドウを作成するために必要情報を渡す
                    this.markerInfoWindow(this.marker[i],this.displayingPlaceList[i]['id'], this.displayingPlaceList[i]['placeName']);
                }
            }
        },
        // Markerの情報ウィンドウを作成する関数
        markerInfoWindow(marker,id, name) {
            let infoWindow = new this.google.maps.InfoWindow({
                content: `<v-card class="custom-info-window">
                        <v-list-item-title class="text-subtitle-1 font-weight-medium mx-1">${name}</v-list-item-title>
                        </v-card>`,
            });
            // マウスが乗ったら表示
            this.google.maps.event.addListener(marker, 'mouseover', () => {
                infoWindow.open(this.map, marker);
            });
            // マウスが外れたら閉じる
            this.google.maps.event.addListener(marker, 'mouseout', () => {
                infoWindow.close();
            });
            // （クリックされたらダイアログを開く）
            this.google.maps.event.addListener(marker, 'click', () => {
                this.isDialog = true;
                this.setSelectedPlaceID(id);
            });
        },
    }
}
</script>

<style lang="scss" scoped>

// width, height設定しないと地図が表示されませんでした。
.google-map {
  width: 100vw;
  height: 100vh;
}
</style>

```

<details><summary>place-list.json</summary>

```json:place-list.json
[
  {
    "id": 1001,
    "placeName": "三井住友銀行渋谷支店前",
    "placeCategory": "roadside",
    "address": "東京都渋谷区宇田川町20-2",
    "lat": 35.6608601,
    "lng": 139.700261,
    "image": {
      "imageSrc": "/images/1001.jpeg",
      "imageRef": "twitter"
    },
    "members": [
      "Jeonghan"
    ]
  },
  {
    "id": 1002,
    "placeName": "とんかつ檍大門店",
    "placeCategory": "restaurant",
    "address": "東京都港区浜松町1-11-12",
    "lat": 35.6588233,
    "lng": 139.755709,
    "image": {
      "imageSrc": "/images/1002.jpeg",
      "imageRef": "twitter"
    },
    "members": [
      "Seungkwan"
    ]
  },
...
]

```
</details>

## 💎 メモ
### 読み込み
Google Maps API の読み込みは[Vue.jsの公式ドキュメント](https://jp.vuejs.org/v2/cookbook/practical-use-of-scoped-slots.html)を参考にしました。

### API Keyを環境変数に設定する
API keyは環境変数で設定して読み込むことで、GitHubで公開した時に隠せます。（私は最初、コード内にバリバリ書いたまま公開してしまいました😇。Googleが警告メールを送ってくれたので気づけました。）
参考サイト⏩ [Qiita Vue CLIを用いた環境変数の設定方法](https://qiita.com/go6887/items/2e254d31b5a4af42f813)

※公開してしまった場合、リポジトリを新しく作ってcommit履歴を引き継がないように複製して解決させました。
加えて、API keyも再生成しました。
参考サイト⏩ [【Git】リポジトリをコミット履歴の引継ぎなしで複製する方法！](https://alfort.online/3155)

### styleのカスタム
※今回はjsonをvueファイルに直接コピペしましたが、別ファイルに切り取った方が見やすいです。
参考サイト⏩[【Google Maps API】地図デザインの変更と「Styling Wizard」の使い方](https://www.granfairs.com/blog/staff/google-maps-api-04)
カスタムに使ったサイト⏩ [Styling Wizard](https://mapstyle.withgoogle.com/)

### MapのデフォルトUIを無効にする
ズームコントロールやストリートビューコントロールなど、地図の上下左右端に出てくるコントロール類を纏めて非表示にします。
参考サイト⏩[コントロール | Google Maps Platform](https://developers.google.com/maps/documentation/javascript/controls?hl=ja)

### 情報ウィンドウ
Markerにホバーした時、該当場所の名前が小さいウィンドウで表示されるようにします。
複数Markerがあり、クリック時にダイアログで詳細情報を開きたいため、引数で「場所のID」と「場所の名前」も渡し、Markerアイコンと該当場所の情報を紐づけました。
参考サイト1⏩[情報ウィンドウ | Google Maps Platform](https://developers.google.com/maps/documentation/javascript/infowindows?hl=ja)
参考サイト2⏩[Google Maps APIを使ってマーカー(ピン)に吹き出しを追加しよう！](https://tips-web.net/gmap-add-infowindow/)