🗾

Google Maps APIとVue3を組み合わせた地図アプリケーションの作り方

2024/05/20に公開

はじめに

今回はプロジェクトでGoogle Maps APIをVue3で利用したときの備忘録として記事にしてみました。
プロジェクトでは以下の機能を使ってデバイスの経路や計測ポイントの密度を表示しました。

Google Maps API

Google Mapsの機能を組み込むことが可能なツールです。
地図の表示はもちろん、経路やヒートマップなどの描画が可能です。
利用にはGoogle Cloud Platformでプロジェクトを作成し、APIキーを取得する必要があります。利用には通常、使用量に応じた料金が発生します。

https://developers.google.com/maps/documentation/javascript/get-api-key?hl=ja

Google Maps API + Vue3

今回は以下のライブラリを使ってGoogle Maps API + Vue3を使っていきます。

https://www.npmjs.com/package/vue3-google-map

追加方法
npm install vue3-google-map
# OR
yarn add vue3-google-map

地図表示

GoogleMapコンポーネントを使うことで簡単に地図を表示できます。
※ 地図を表示するだけであれば、無料なので埋め込みがオススメです。

maponly

<script setup lang="ts">
import { Ref, ref, watch } from 'vue';
import { GoogleMap } from 'vue3-google-map';

type gmap = {
  mapRef: Ref<HTMLElement | undefined>;
  ready: Ref<boolean>;
  map: Ref<google.maps.Map | undefined>;
  api: Ref<typeof google.maps | undefined>;
  mapTilesLoaded: Ref<boolean>;
};

const { VITE_GMAP_API_KRY } = import.meta.env;
const mapRef: Ref<gmap | null> = ref(null);

const center = { lat: 34.7055864522747, lng: 135.4989457104213 };

watch(() => mapRef.value?.ready, (ready) => {
  if (!ready) {
    return;
  }
});
</script>

<template>
  <GoogleMap 
    ref="mapRef"
    :api-key="VITE_GMAP_API_KRY"
    style="width: 100%; height: 600px"
    :center="center"
    :zoom="15"
  />
</template>

地図表示_プロパティ

GoogleMapコンポーネントで指定できるプロパティは公式と同じ内容が設定できます。
主なプロパティをここでは紹介します。

プロパティ 設定内容
api-key Google Cloud Platformで取得したAPIキーを指定
center 表示した地図の初期位置
center.lat 表示した地図の初期位置(緯度)
center.lng 表示した地図の初期位置(経度)
zoom 初期ズームレベル

ポリライン(Polyline)

経路などの連続した線を表示したい場合はPolylineコンポーネントを利用します。
例えば、デバイスが○月△日に移動した経路を表示したいときなどです。

polyline

<script setup lang="ts">
import { Ref, ref, watch } from 'vue';
import { GoogleMap, Polyline } from 'vue3-google-map';

type gmap = {
  mapRef: Ref<HTMLElement | undefined>;
  ready: Ref<boolean>;
  map: Ref<google.maps.Map | undefined>;
  api: Ref<typeof google.maps | undefined>;
  mapTilesLoaded: Ref<boolean>;
};

const { VITE_GMAP_API_KRY } = import.meta.env;
const mapRef: Ref<gmap | null> = ref(null);
const lineOption: Ref<google.maps.PolylineOptions | null> = ref(null);

const center = { lat: 34.7055864522747, lng: 135.4989457104213 };

const path = [
  { lat: 34.70246409457652, lng: 135.49540519451972 },
  { lat: 34.70350489355238, lng: 135.49737930026106 },
  { lat: 34.70523364935635, lng: 135.49707889286566 },
  { lat: 34.7055864522747, lng: 135.4989457104213 },
  { lat: 34.70821478628786, lng: 135.49772262307397 },
  { lat: 34.71123109354799, lng: 135.4980444881405 },
  { lat: 34.711162263421876, lng: 135.49694223970306 }
];

watch(() => mapRef.value?.ready, (ready) => {
  if (!ready) {
    return;
  }

  lineOption.value = {
    path: path,
    geodesic: true,
    strokeColor: '#FF0000',
    strokeOpacity: 1,
    strokeWeight: 2,
    icons: [
      {
        icon: {
          fillColor: "#FFFFFF",
          fillOpacity: 1,
          path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
          scale: 4,
        },
        repeat: '10%'
      }
    ]
  }
});
</script>

<template>
  <GoogleMap 
    ref="mapRef"
    :api-key="VITE_GMAP_API_KRY"
    style="width: 100%; height: 600px"
    :center="center"
    :zoom="15"
  >
    <Polyline v-if="lineOption" :options="lineOption" />
  </GoogleMap>
</template>

ポリライン(Polyline)_プロパティ

Polylineコンポーネントで指定できるプロパティも公式と同じ内容が設定できます。
主なプロパティをここでは紹介します。

プロパティ 設定内容
path ストローク(線)の座標
strokeColor ストローク(線)の色
strokeOpacity ストローク(線)の透明度0.0~1.0
strokeWeight ストローク(線)の太さ(幅)
icons ストローク(線)に沿って表示されるアイコン
icons[i].repeat 連続表示するアイコンの間隔。50% や 12pxで設定できる
icons[i].icon.path アイコンの形状
icons[i].icon.scale アイコンのサイズ

ヒートマップ(HeatmapLayer)

ヒートマップを表示したい場合はHeatmapLayerコンポーネントを利用します。
例えば、人口の多い箇所を赤く表示したいときなどです。

HeatmapLayer

<script setup lang="ts">
import { Ref, ref } from 'vue';
import { GoogleMap, HeatmapLayer } from 'vue3-google-map';

type gmap = {
  mapRef: Ref<HTMLElement | undefined>;
  ready: Ref<boolean>;
  map: Ref<google.maps.Map | undefined>;
  api: Ref<typeof google.maps | undefined>;
  mapTilesLoaded: Ref<boolean>;
};

const { VITE_GMAP_API_KRY } = import.meta.env;
const mapRef: Ref<gmap | null> = ref(null);

const center = { lat: 34.7055864522747, lng: 135.4989457104213 };

// 各データポイントの影響の半径(ピクセル単位)
const radius = 30;

// 座標配列
const heatmapData = [
  { location: { lat: 34.7055864522747, lng: 135.4989457104213 } },
  // ...
  { location: { lat: 34.7055864522747, lng: 135.4989457104213 } }
];

</script>

<template>
  <GoogleMap 
    ref="mapRef"
    :api-key="VITE_GMAP_API_KRY"
    :libraries="['visualization']"
    style="width: 100%; height: 600px"
    :center="center"
    :zoom="15"
  >
    <HeatmapLayer :options="{ data: heatmapData, radius: radius }" />
  </GoogleMap>
</template>

ヒートマップ(HeatmapLayer)_プロパティ

HeatmapLayerコンポーネントで指定できるプロパティも公式と同じ内容が設定できます。
主なプロパティをここでは紹介します。

プロパティ 設定内容
radius データポイントの影響の半径(ピクセル単位)
data データポイント
data[i].location.lat データポイント(緯度)
data[i].location.lng データポイント(経度)
data[i].weight 【任意】重み付け

ハマりどころ

google.mapsをsetupのスクリプト中で使うとエラーが出る

setup関数の中でgoogle.mapsを参照するとエラーReferenceError: google is not definedが発生しました。
このエラーは、setup関数が実行されているタイミングではまだインポートされていないため発生します。

回避方法としては以下になります。

  1. GoogleMapのコンポーネントをwatchする(vueのwatch関数を使う)
  2. ロード済みready=trueにステータスが変わる
  3. google.mapsを参照する
NG時(スクリプト部のみ抜粋)
import { GoogleMap, Polyline } from 'vue3-google-map';

const lineOption: Ref<google.maps.PolylineOptions | null> = ref(null);

// 表示元データ(線)
const path = [
  // 省略
];

lineOption.value = {
  path: path,
  geodesic: true,
  strokeColor: '#FF0000',
  strokeOpacity: 1,
  strokeWeight: 2,
  icons: [
    {
      icon: {
        fillColor: "#FFFFFF",
        fillOpacity: 1,
        path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW, // ここでエラー
        scale: 4
      },
      repeat: '10%'
    }
  ]
}
OK時(スクリプト部のみ抜粋)
import { Ref, ref, watch, } from 'vue';
import { GoogleMap, Polyline } from 'vue3-google-map';

type gmap = {
  mapRef: Ref<HTMLElement | undefined>;
  ready: Ref<boolean>;
  map: Ref<google.maps.Map | undefined>;
  api: Ref<typeof google.maps | undefined>;
  mapTilesLoaded: Ref<boolean>;
};

const { VITE_GMAP_API_KRY } = import.meta.env;
const mapRef: Ref<gmap | null> = ref(null);
const lineOption: Ref<google.maps.PolylineOptions | null> = ref(null);

// 表示元データ(線)
const path = [
  // 省略
];

watch(() => mapRef.value?.ready, (ready) => {
  if (!ready) {
    return;
  }

  lineOption.value = {
    path: path,
    geodesic: true,
    strokeColor: '#FF0000',
    strokeOpacity: 1,
    strokeWeight: 2,
    icons: [
      {
        icon: {
          fillColor: "#FFFFFF",
          fillOpacity: 1,
          path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
          scale: 4,
        },
        repeat: '10%'
      }
    ]
  }
});
OK時(テンプレート部のみ抜粋)
<GoogleMap 
  ref="mapRef"
  :api-key="VITE_GMAP_API_KRY"
  :libraries="['visualization']"
  style="width: 100%; height: 600px"
  :center="center"
  :zoom="15"
>
  <Polyline v-if="lineOption" :options="lineOption" />
</GoogleMap>

おわりに

今回はGoogle Maps API + Vue3の構成でポリラインとヒートマップの2種類のレイアウトを紹介しました。
無料枠があるといっても有償であるため、利用回数の制限など考慮して使いましょう。

セカンドセレクション

Discussion