Tech blog Produced by FOURIER

Google Maps API の使い方

Ichikawa Ichikawa 2023.02.20

はじめに

みなさま、Google マップ 使われてますでしょうか?2022 年の調査では 99.4%の人が「使ったことがある」と回答しており、地図アプリではダントツトップの利用率となっております。

Google マップが埋め込まれている Web サイトもよくあります。Google マップからコードを抽出するだけなので、とても簡単に実装できますよね。

今回の記事では Google Maps Api を使って以下の機能を実装していきたいと思います。

  • ピンを移動すると、住所と座標(緯度・経度)を算出する
  • 住所を入力すると、ピンを住所の位置に移動し座標(緯度・経度)を算出する

ちなみに、Laravel9 と JavaScript で実装を進めます。

Google Maps Platform に登録

まずは、Google Maps Platformに登録してMaps API Key を取得しましょう。

この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&region=JP&key=AIzaSxxxxxxxxxxxxxxxxxxxxxxxx&callback=initMap" async defer></script>
</body>

</html>

ポイント

地図を描画する領域とサイズを指定します。

<div id="map" style="height:500px; width:800px;"></div>

GoogleMapsのAPIを読み込みをします。

<script src="https://maps.googleapis.com/maps/api/js?language=ja&region=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("住所を確認してください"); // フォームに入力された住所から、座標が取得できなかった場合のアラート
            }
        }
    );
}

当初は、/resources/js/map.js のようにファイルを配置して、@vite(['resources/js/map.js']) で読み込む形を考えていましたが、message: 'initMap is not a function’ とエラーが発生するので、/public/js/ に直接配置しています。

どうやら vite でビルドすると参照できなくなるようです…少しハマりました。

ポイント

コードを分割して解説すると、逆にわかりづらくなるかと思いコード上に記載しました。

処理の流れは以下のようになっています。

  1. フォームの値から座標を取得して、マップの初期化と描画
  2. ※リロード or「検索」ボタンを押す のどちらかで処理が動きます

  1. アイコンを移動するとイベントが発火、移動後のアイコンの位置から座標を取得
  1. 取得した座標でマップを再描画

最後に

とてもシンプルに地図周りの機能を実装できました。さすがはGoogle。さすがはGAFA。

いろいろとオプションは充実しているので、公式ドキュメントをご参照ください。

この記事がそれなりに反響あるようでしたら、次はVue.jsとかで実装してみようかと思います。

最後まで読んでいただきありがとうございます。では、また次回の記事で!

Ichikawa

Ichikawa / Engineer

パン屋から転身してエンジニア3年目。主にPHP/Laravelを使っています。最近ではVue.js/Nuxt.jsと人間に興味あり。