Google Maps APIとVue.js を使ってGoogle Map 上にルートを描画する
技術スタック JavascriptVue.js

Google Maps APIとVue.js を使ってGoogle Map 上にルートを描画する

2021.03.10

こんにちはjunです。自主開発で地図上に描画する機能を実装するときに「Vueを用いてGoogle Map上にラインを描画できないかな?」と思いその方法を調べた結果、なんとか実装できました。今回の記事ではGoogle Map APIを用いてVue(またはVanilla js)で地図の表示とラインの描画機能を実装したいと思います。Google Map APIの取得の仕方とVue.jsのインストールなどはある程度省きます。

Google Map APIを取得する

詳細な取得方法は省略しますが、最低限必要なものだけ解説します。自前のGoogleアカウントを用いて、Google Cloud PlatformでGoogle Map APIを取得します。

毎月$200分までのリクエストは無料なので開発環境には十分でしょう。そしてweb上にGoogleMapを表示するにはMaps JavaScript APIが必要になります。

このAPIを有効にしてAPIキーを手に入れます。まずAPI側のセットアップは以上です。

Vue側の準備

今回はVue CLIを用いて開発します。vue cliを用いて適当にプロジェクトを作成します。

$ vue create vue_map

api 用のJSを読み込む

/src 配下にあるmain.js/public配下にあるindex.htmlに以下のコードを挿入します。

public/index.html
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    
  <!-- このスクリプトを挿入-->
    <script src="http://maps.google.com/maps/api/js?key=YOUR_API_KEY&language=ja"></script>
   
   <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

http://maps.google.com/maps/api/jsからAPIのソースを手に入れます。できたらnpmあたりでローカルに予めインストールしたいなと思ったのですが、node.js専用だったりとひとまず開発したかったので、今回は外部ファイルとします。このときVue.jsより早く読み込まれるようにしましょう。

スクリプトのurlにはAPIキーを含めます。公開環境で使用する場合は必ずAPIキーが自サイトのみで使用される条件を設定しておきましょう。でないと第三者に好き勝手にキーを使われて、請求だけはあなたのクレジットカードにきます。

プラグインとしてVueに登録しておく

上記のソースを読み込めばwindow.googleを見ると、今回使用するAPIを操作できるクラスなりメソッドがあります。

console.lgo(window.google);
/**
*{maps: {}}
*/

例えば地図を特定のDOMにマウントするときは以下のように呼びます。

window.google.maps.Map(document.getElementById('map'),{option});

毎回、window.google.mapsとやるのは面倒なのでthis.$gmと呼び出せるようにプラグイン化しておきます。

src/main.js
import Vue from 'vue'
import App from './App.vue'

//これ
Vue.prototype.$gm = window.google.maps;

Vue.config.productionTip = false
new Vue({
  render: h => h(App),
}).$mount('#app')

これで前準備が完了しました。

とりあえず地図をマウントする

準備が整ったのでvueを用いてGoogle Mapをマウントしましょう。インストール直後にあるApp.vueを以下のように書きます。

src/App.vue
<template>
  <div id="app" class="mt-4">
      <div id="map"></div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data(){
    return{
      map:undefined,
    }
  },
  mounted(){
   const map = new this.$gm.Map(document.getElementById('map'),{
      center: { lat: 34.855273888888888, lng: 135.30649 }, //自由な緯度・経度を入力
      zoom: 10,
    });
  this.map = map;
  }
}
</script>

Mapsクラスのレファランスの通り、第一引数にマウント対象のDOMを入れ、第二引数にはオプションを入れます。DOMが必要なのでmounted()で初期処理を行います。

オプションには

  • center:初期表示の地図の中央座標
  • zoom:拡大の縮尺(10ぐらいがちょうどいい)

を入れておきましょう。latは緯度、lngは経度を示しています。このインスタンスは後で使い回すのでthis.map = map としてインスタンスを入れておきましょう。ひとまずこの処理を実装してブラウザで見てみましょう。

$ npm run serve

localhostをみたとき、このようになっていれば問題ありません。ストリートビューや前面表示がない方がいい人はオプションを以下のようにしておきます。

src/main.js
new this.$gm.Map(document.getElementById('map'),{
      center: { lat: 34.855273888888888, lng: 135.30649 },
      zoom: 10,
      streetViewControl:false, // ストリートビュー非表示
      fullscreenControl:false  // フルスクリーン非表示
});

地図にクリックイベントを追加

Google Mapの地図にはクリックやドラッグなどのイベントリスナーを追加できます。特定の位置やマーカーをクリックしたら何やかんやするというのができます。まずは簡単にクリックした地図位置の緯度・経度を取得してみましょう。以下のようにします。

src/main.js
<template>
  <div id="app" class="mt-4">
      <div id="map"></div>
      {{position}}
  </div>
</template>

<script>

export default {
  name: 'App',
  data(){
      return{
        map:undefined,
        position:undefined
      }
  },
  methods:{
   clickOnMap(mapEvent){
    console.log(mapEvent.latLng.toString())
    this.position = mapEvent.latLng.toString();
   }
  },
  mounted(){
   const map = new this.$gm.Map(document.getElementById('map'),{
      center: { lat: 34.855273888888888, lng: 135.30649 }, //自由な緯度・経度を入力
      zoom: 10,
    });

    //リスナーの登録
    map.addListener('click',(mapsMouseEvent)=>{
      return this.clickOnMap(mapsMouseEvent);
    });

  this.map = map;
  }
}

map.addListener('click',(mapsMouseEvent)=>{...})とDOMにイベントを追加する時と似ていますね。第二引数に実行するコールバックを入れます。ちなみにコールバックの引数には自動的に地図上の座標なり他の情報が入っています。

このイベントリスナーには以下のメソッドが実行されるようになっており、クリック位置の経度、緯度を取得します。

src/main.js
clickOnMap(mapEvent){
        console.log(mapEvent.latLng.toString())
        this.position = mapEvent.latLng.toString();
},

クリックすると以下のようになります。(真ん中の赤いのは気にしないでください。)

左下に座標が表示されました。ひとまずこれで地図に対するイベントリスナーの登録と情報の取得については理解できたと思います。

ラインの描画

それでは今度はクリックした際にラインを描画できるようにします。ラインを描画するためにはgoogle.maps.Polylineクラスのインスタンスを作成し、先ほどのMapインスタンスにセットすることで描画ができます。

上記の通り地図上の情報を取得できたように、今度は緯度経度の情報を元に地図に何かセットします。まずはMapの初期表示と同時にラインを描画しましょう。

src/main.js
...  
mounted(){
  const map = new this.$gm.Map(document.getElementById('map'),{
    center: { lat: 34.855273888888888, lng: 135.30649 },
    zoom: 10,
  });
  map.addListener('click',(mapsMouseEvent)=>{
    return this.clickOnMap(mapsMouseEvent);
  });
  const LINE = new this.$gm.Polyline({
      path:[
        { lat: 34.855273888888888, lng: 135.30649 },
        { lat: 34.854465, lng: 135.8 },
      ],
      geodesic: true,
      strokeColor: "#FF0000",
      strokeOpacity: 1.0,
      strokeWeight: 2,
  })
  LINE.setMap(map);
  this.map = map;
} 
...

this.$gm.Polylineでラインインスタンスを作成し、オプションをオブジェクト形式で指定すればラインの色、パス(2点以上の座標)、太さなどを指定できます。最後にLINE.setMap(map)で地図にはめると、以下のように描画されます。

地図に赤線が表示されました。今は2点の適当な座標間ですが細かくパスを設定すれば以下のようにも描画できます。

この座標情報は友人のGPSから引っ張ってきたもので、詳細な座標情報が配列であったのでこれほど細かく描画されます。

クリックした任意の地点でラインを描画していく。

初期表示でラインを描画することができたので、次はユーザーが任意の地点をクリックしたらその地点に向かってラインが描画されるようにしましょう。

先ほどクリックイベントから座標情報をしたのを覚えていますか?それを応用します。

  1. クリック位置から緯度・経度を取得
  2. Google Map用の座標インスタンスに変換
  3. ラインインスタンスにその座標(パス)を追加する。
  4. クリックされたら繰り返す。

クリックイベントに付与したdrawLineメソッドこんな感じです。

src/main.js
data(){
  return{
    map:undefined,
    bounds:undefined,
    path:[],
    line:undefined
  }
},
methods:{
  drawLine(mapEvent){
    let latLng = mapEvent.latLng;

    // 1点目をクリック
    if(this.line === undefined){
      const newLine = new this.$gm.Polyline({
        path:[latLng],
        geodesic: true,
        strokeColor: "#FF0000",
        strokeOpacity: 1.0,
        strokeWeight: 2,
      })
      newLine.setMap(this.map);
      this.path.push(latLng);
      this.line = newLine;
      return;
    }

    // 2点目以降
    this.path.push(latLng);
    this.line.setPath([...this.path]);
    return;
  },
},

1点目の時はインスタンスを作成しdata()に格納します。そしてクリックごとにpathに挿入していき、this.line.setPath([...this.path])で更新したパスの配列を展開、インスタンスのパスも更新します。するとクリックするたびにその地点に向かって線画描画されます。静止画ですがVUEという文字を一筆でかいてみました笑

末尾のパスを消して再セットすればやり直し機能ができますし、特定のパスの座標を変更すれば途中の変更もできます。今回は面倒なのでやりませんでした。パスのインスタンスを複数管理できれば、複数ライン・レイヤーなど高度なライン描画を実現できます。詳細な実装をしたらまた記事を書いてみます。

Vueじゃなくてもよくね?

はい。その通りです。ほとんどがGoogle map javascript apiから提供されたオブジェクトをいじっているだけです。なのでVanilla.jsな環境でも普通に描画機能は実装できます。今回はvue.jsを利用して自主開発していたのでvue.jsを使っただけです。

いろいろ試してみる

Google Map APIには他にもマーカ・カスタムデザインマーカを入れたり、DOM要素を地図に入れ込むなんてこともできるそうです。これらの描画情報をJSONに格納して、DBに入れておけば地図共有アプリなんかもできそうですね。いろいろやってみます。閲覧ありがとうございました。

Copyright © 2021 jun. All rights reserved.