CDNでGoogle Mapを描く

# 概要

- vueでgoogle mapを描く時のパッケージであるvue2-google-mapはGASでwebページを作成する時は使えません。
- @googlemaps/js-api-loaderというパッケージはCDNが提供されているので、これを使いました。

# 開発の背景

- 勤務先ではGsuitesを使って、製品検索ページやら取引先へのメール配信やらにGASを使ったWebアプリケーションを作成しています。
- GASでWebアプリを作る場合、フロント側はHTML形式で書く必要があります。普通vueやnuxtでフロントページを作る場合はwebpackでインストールしますが、GASのHTMLではwebpackは使えません。そのため、パッケージツールはCDNを頼ることになります
- Vueでgoogle mapを使うときはvue2-google-mapを使うのが一般的だと思うのですが、2021年1月現在vue2-google-mapのCDNは提供されていません。[https://github.com/Jeson-gk/vue2-google-maps/blob/master/API.md](https://github.com/Jeson-gk/vue2-google-maps/blob/master/API.md)
- そこで、vue2-google-mapを使うことなく、別のパッケージを使用しました。

# 設計

- こちらの記事を参考にしています。

[https://qiita.com/terrierscript/items/9a9dda5a5ca5b3293d48](https://qiita.com/terrierscript/items/9a9dda5a5ca5b3293d48)

## 構成

- いつものnuxt風な構成にしています

### layouts/default.html

```jsx
<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <?!= include("config") ?>
</head>
<body>
  <?!= include("store/index") ?>
  <?!= include("components/ChildMarker") ?>
  <?!= include("components/MapLoader") ?>

  <?!= include("pages/index") ?>

  <div id="app"></div>

  <script>
    new Vue({
      vuetify: vuetify,
      store: store,
      render: h => h(index)
    }).$mount("#app")
  </script>

</body>
</html>
```

### pages/index.html

```jsx
<script type="text/x-template" id="index">
  <v-app>
    <v-sheet>
          <map-loader>
            <template slot-scope="scopeProps">
              <child-marker
                v-for="(marker, i) in markers" :key="i"
                :position="marker" :google="scopeProps.google" :map="scopeProps.map"/>
            </template>
          </map-loader>

    </v-sheet>
  </v-app>
</script>

<script>
  const index = {
    template: "#index",
    components: {
      "MapLoader":MapLoader,"ChildMarker":ChildMarker
    },
    data() {
      return {
        loadeds: ["お待ち下さい"],
        markers:[
          {"lat":35.6432027,"lng":139.6729435},
          {"lat":35.5279833,"lng":139.6989209},
          {"lat":35.6563623,"lng":139.7215211},
          {"lat":35.6167531,"lng":139.5469376},
          {"lat":35.6950961,"lng":139.5037899}
        ]
      }
    },
  }
</script>
```

### components/MapLoader.html

- ここが今回のミソです。
- templateにv-ifを書くことで、googleオブジェクトとmapオブジェクトが作られないと子コンポーネントであるChildMarkerが作られない仕組みです。
- mountedの内容はExampleに書いてあるとおりに作りました

```jsx
<script type="text/x-template" id="map-loader">
  <div>
    <div ref="map" style="width:800px;height:500px"></div> <!-- point 1 -->
    <template v-if="!!this.google && !!this.map">
      <slot :google="google" :map="map"></slot>
    </template>
  </div>
</script>

//google mapを使うためのCDN
<script src="https://unpkg.com/@googlemaps/js-api-loader@1.0.0/dist/index.min.js"></script>

<script>
  const MapLoader = {
    template:"#map-loader",
    data(){return{
      google:null,
      map:null
    }},
//mountedでgoogleオブジェクトとmapオブジェクトを作成する
    mounted(){
      let self = this
      const {Loader} = google.maps.plugins.loader
      const loader = new Loader({apiKey: "API-KEY"})
      const mapOption = {
        center:{lat:35,lng:135},
        zoom:8
      }

      loader
        .load()
        .then(()=> {
          self.google = google
          self.map = new google.maps.Map(self.$refs.map,mapOption)
        })
        .catch(e=>{
          console.log(e)
        })
    },
  }
</script>
```

### components/ChildMarker.html

- ここのgoogleオブジェクトとmapオブジェクトは親であるMapLoaderコンポーネントから引き継いでます

```jsx
<script>
const ChildMarker =  {
  template:"<div></div>",
  props:{
    google:Object,map:Object,
    position:Object //{lat:Number,lng:Number}
  },
  data(){return{
    marker:null
  }},
  mounted(){
    const { Marker } = this.google.maps
    this.marker = new Marker({
      position: this.position,
      map: this.map,
      title: "Child marker!"
    })
  }
}
</script>
```