はじめに
みなさま、Google マップ 使われてますでしょうか? 2022 年の調査 では 99.4%の人が「使ったことがある」と回答しており、地図アプリではダントツトップの利用率となっております。
Google マップが埋め込まれている Web サイトもよくあります。Google マップからコードを抽出するだけなので、とても簡単に実装できますよね。
今回の記事では Google Maps Api を使って以下の機能を実装していきたいと思います。
ピンを移動すると、住所と座標(緯度・経度)を算出する
住所を入力すると、ピンを住所の位置に移動し座標(緯度・経度)を算出する
ちなみに、Laravel9 と JavaScript で実装を進めます。
Google Maps Platform に登録
まずは、Google Maps Platformに登録してMaps API Key を取得しましょう。
Google Cloud プロジェクトをセットアップする | Maps JavaScript API | Google for Developers
https://developers.google.com/maps/documentation/javascript/cloud-setup?hl=ja
このAPIは1ヶ月あたり28,500 回分(200ドル)の無料枠があり、その範囲内であれば無料でAPIを使用できます。(2023年2月現在)
※ ローカル環境で開発するだけでしたら API キーの保護はなくても大丈夫ですが、本番環境で使用する際にはドメインや IP アドレスで制限をして不正利用されないにしましょう
Laravel
Laravel の初期設定は済んでおり、 http://localhost にアクセスすると初期画面が表示される状態を想定しています。
また、ビルドツールは Laravel9 で標準装備されている Vite を使用します。
ビュー
/resources/views/welcome.blade.php
を以下のよう変更します。
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.bunny.net/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
<!-- Styles -->
<style>
body {
font-family: 'Nunito', sans-serif;
}
</style>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="antialiased">
<div id="map" style="height:500px; width:800px;"></div>
<form>
<input type="text" name="address" value="静岡県浜松市早出町234-2" id="address">
<button type="button" id="button">検索</button>
</form>
<ul>
<li>lat: <span id="lat"></span></li>
<li>lng: <span id="lng"></span></li>
</ul>
<script src="{{ asset('/js/map.js') }}"></script>
<script src="https://maps.googleapis.com/maps/api/js?language=ja®ion=JP&key=AIzaSxxxxxxxxxxxxxxxxxxxxxxxx&callback=initMap" async defer></script>
</body>
</html>
/resources/views/welcome.blade.php
ポイント
地図を描画する領域とサイズを指定します。
<div id="map" style="height:500px; width:800px;"></div>
GoogleMapsのAPIを読み込みをします。
<script src="https://maps.googleapis.com/maps/api/js?language=ja®ion=JP&key=AIzaSxxxxxxxxxxxxxxxxxxxxxxxx&callback=initMap" async defer></script>
パラメータはそれぞれ以下のようになっています。
language=ja:言語設定(日本語)
region=JP:地域設定(日本)
key=AIzaSxxx…:API キー設定(取得した Maps API Key)
callback=initMap:API 読み込み後、 initMap()
というコールバック関数を実行する
コールバック関数で呼ばれる initMap()を読み込みます。 @vite(['resources/js/map.js'])
の形式でない理由は後述します。
<script src="{{ asset('/js/map.js') }}"></script>
コールバック関数
続いて /public/js/map.js
を作成します。コードは以下のよう設定してください。
const inputAddress = document.getElementById("address");
const button = document.getElementById("button");
button.onclick = initMap;
function initMap() {
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 15, // 地図の尺度
mapTypeId: google.maps.MapTypeId.ROADMAP, // マップタイプ(ROADMAPはデフォルトのもの)
});
const geocoder = new google.maps.Geocoder(); // Googlgのサーバーと通信するためのインスタンスを生成
geocoder.geocode(
{
address: inputAddress.value, // フォームに入力された値を渡す
region: "jp",
},
function (result, status) {
// ↑の検索結果に対しての処理
if (status == google.maps.GeocoderStatus.OK) {
const location = result[0].geometry.location;
const marker = new google.maps.Marker({
position: location, // 検索結果の緯度・経度を設定
map: map, // マップの描画設定
title: location.toString(), // アイコンにカーソルが重なった際に表示されるテキスト
draggable: true, // trueにすることでアイコンを自由に移動できる
});
map.setCenter(location); // マップ中央にアイコンが表示される
document.getElementById("lat").textContent = location.lat();
document.getElementById("lng").textContent = location.lng();
google.maps.event.addListener(
// アイコンが移動した際に発火するイベントを登録
marker,
"dragend",
function (event) {
const latLng = event.latLng; // 移動したアイコンの座標を取得
marker.setTitle(latLng.toString());
document.getElementById("lat").textContent = latLng.lat();
document.getElementById("lng").textContent = latLng.lng();
const geocoder = new google.maps.Geocoder();
geocoder.geocode(
// 取得した座標で再描画
{ location: latLng },
function (result, status) {
if (status == google.maps.GeocoderStatus.OK) {
// 住所を取得してフォームに値を入れる
let address = '';
const addressComponents = result[0].address_components;
for (let i = 0; i < (addressComponents.length - 2); i++) {
address = addressComponents[i].long_name + address;
}
inputAddress.value = address
}
}
);
}
);
} else {
alert("住所を確認してください"); // フォームに入力された住所から、座標が取得できなかった場合のアラート
}
}
);
}
/public/js/map.js
当初は、 /resources/js/map.js
のようにファイルを配置して、 @vite(['resources/js/map.js'])
で読み込む形を考えていましたが、 message: 'initMap is not a function’
とエラーが発生するので、 /public/js/
に直接配置しています。
どうやら vite でビルドすると参照できなくなるようです…少しハマりました。
ポイント
コードを分割して解説すると、逆にわかりづらくなるかと思いコード上に記載しました。
処理の流れは以下のようになっています。
フォームの値から座標を取得して、マップの初期化と描画
※リロード or「検索」ボタンを押す のどちらかで処理が動きます
アイコンを移動するとイベントが発火、移動後のアイコンの位置から座標を取得
取得した座標でマップを再描画
最後に
とてもシンプルに地図周りの機能を実装できました。さすがはGoogle。さすがはGAFA。
いろいろとオプションは充実しているので、公式ドキュメントをご参照ください。
Google Maps Platform のドキュメント | Maps JavaScript API | Google for Developers
Google Maps Platform のドキュメント
https://developers.google.com/maps/documentation/javascript?hl=ja
この記事がそれなりに反響あるようでしたら、次はVue.jsとかで実装してみようかと思います。
最後まで読んでいただきありがとうございます。では、また次回の記事で!