だれでもわかる、たのしいGoogle Maps API

これはフェンリル デザインとテクノロジー Advent Calendar2024 16日目の記事です。

まえがき

はじめまして。NILTOのバックエンドエンジニアの小西です。入社してまだ二ヶ月ですが、面白い企画があると聞きつけて、今回フェンリルのアドベントカレンダーに参加しました。技術系の記事を執筆するのは初めてのことで緊張していますが、何卒よろしくお願いいたします。

さて、アドベントカレンダーと言えばクリスマス。 大人になってしまった今はクリスマスに何の感情も抱きませんが、幼い頃はサンタさんのプレゼントを楽しみに待ったものです。ワクワクできたあの頃は良かった。

記事のネタを考えていた私はひらめいたのです。「エンジニアになる前、学生時代にワクワクしていたことを書けばいいのでは?!」

ということで、遡ること4年前、かつて私が大学生だった頃に出会った Google Maps API(Java Script向け) についてご紹介しようと思います。 エンジニア以外の方でも楽しめるように書いてみましたので、ぜひ肩の力を抜いてご覧ください!

※ HTMLと若干のJavaScriptの知識があると読みやすいです

注意事項

本記事で紹介している内容は執筆時点(2024年12月10日)での情報であり、今後の動作を保証するものではありません。仕様変更により挙動が変わってしまうことも考えられます。適宜、公式ドキュメントを参照し、最新の情報をご確認いただくことをお勧めいたします。

Google Maps “API”とは?

その名の通り、Google社が提供する Google Maps のAPI。

「いや、別に名前を見たらわかるし、そこじゃなくてAPIが何なのかを教えて欲しいんや...!」という方向けに、ちょっと補足します。

例えば、あなたがカフェを経営するオーナーで、集客のためにウェブサイトを作ろうとしている、と仮定します。当然、お店へのアクセス情報を示すために地図を載せることになるでしょう。

地図は画像でも十分ですが、欲が出たあなたは「せっかくだし、周辺の建物の名前や道路が表示されてズームもできる、イケてる地図にしたい!」と考えます。

そこで発生するのは、『イケてる地図の実装にどれだけ時間かかるのか問題』。ひょっとすると、サイト本体よりも膨大な時間が必要になってしまうかもしれません。

あなたは思わずにはいられない、「あの便利なグーグルマップを拝借できたらどんなに楽か」ってね…。

はい、それはAPIが解決してくれます。

Google Maps API を使うと自作のウェブサイトにグーグルマップを表示することができます。なんて素晴らしい世の中なんだ。

今回主軸を置いて解説するのはJavaScriptでのマップ表示ですが、ルート検索と実際の交通状況を加味した所要時間の算出、さらには花粉の飛散データまで利用できます(昔に比べてできることが増えていて驚き)。

いま一度思い返してみてください、何かしらの形で Google Maps API を用いたサービスにお世話になったことがあるかも?

独自の地図を作成できるサービスとツール - Google Maps Platform

ちなみに、私が開発に携わっているヘッドレスCMS NILTO でも開発者向けにAPIを提供しています。 NILTOで何ができるのか、興味ある方はぜひ覗いてみてください。

NILTO Developer APIリファレンス

やってみよう

座学はここで終わりにして、実践パートに入ります。以下のHTMLに、地図を表示するための処理を追加していきましょう。japan-map というidが付与されたdiv要素に地図を表示する想定です。

<!DOCTYPE html>
<html>

<head>
  <title>Hello, world!</title>
</head>

<body>
  <h1>Hello, world!</h1>
  <div id="japan-map"></div>
  <script>
    // 地図を表示するための処理をここに書いていく
  </script>


</body>

</html>

APIキーの準備

Google Maps API に限らず、APIを利用するには「APIキー」をプログラム内に記述する必要があります。本筋から外れるため手順は省略させていただきますが、公式ドキュメントに方法が示されていますのでそちらをご覧ください。

取得したAPIキーは、ドキュメントに記載されているサンプルコードにコピペして貼り付けます。煩雑な内容に慄いている方がいるかもしれませんが、取得したAPIキーを入れるだけでOKですので安心してください。

    (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
      key: "★APIキーをここにコピペ",
      v: "weekly",
    });

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

地図を表示しよう

お待たせいたしました。地図の表示方法です。 普段プログラミングしない方も怖がらずにソースコードを読んでみてほしいのですが、何をしているのかふわっとわかる気がしませんか?

    let map;

    async function initMap() {
      const { Map } = await google.maps.importLibrary("maps");
      map = new Map(document.getElementById('japan-map'), {
        center: { lat: 35.36188319083308, lng: 138.72714859384826 },
        zoom: 8,
        mapId: "DEMO_MAP_ID",
      });
    }

    initMap();

mapcenterzoomなどから、「なんか、地図を表示するために中心とか縮尺を書いている気がするぞ...?」と推測できた方もいるのではないでしょうか。YES、正解です!

小難しいことを書くと、地図を表示するための変数と関数を定義している処理になります。

centerで緯度と経度を指定すると、地図の中心座標を決めることができます。

気が付いたら12月も半ばで正月も近いですし、縁起の良い富士山を指定してみました(初夢に出てくれますように!)。

上記の説明を踏まえて、もう一度ソースコードを見てみましょう。補足コメントがやかましい気もしなくもないですが、つまりこういうことです。

    // map宣言「あとで使うから覚えといてね」
    let map;

    // 地図を表示するための技 initMap() の仕込み
    async function initMap() {
      const { Map } = await google.maps.importLibrary("maps");

      // 宣言したmap ここで再登場
      map = new Map(document.getElementById('japan-map'), {
        center: { lat: 35.36188319083308, lng: 138.72714859384826 }, // ここは富士山
        zoom: 8,
        mapId: "DEMO_MAP_ID",
      });
    }

    // いけ、JavaScript!地図を表示ッ!!  
    initMap();

仕上がったプログラムをブラウザで読み込むと...センターに富士山を捉えた地図が!

富士山がセンター

実際のソースコードはこちら。表示位置を調整するためにheadタグでちょろっと記述を加えています。

<!DOCTYPE html>
<html>

<head>
  <style>
    html,
    body {
      height: 100%;
    }

    #japan-map {
      height: 90%;
    }
  </style>
</head>

<body>
  <h1>Hello, world!</h1>
  <div id="japan-map"></div>
  <script>

    (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
      key: "★APIキーをここにコピペ",
      v: "weekly",
    });

    let map;

    async function initMap() {
      const { Map } = await google.maps.importLibrary("maps");
      map = new Map(document.getElementById('japan-map'), {
        center: { lat: 35.36188319083308, lng: 138.72714859384826 },
        zoom: 8,
        mapId: "DEMO_MAP_ID",
      });
    }
    initMap();

  </script>

</body>

</html>

マーカーを表示しよう

地図だけだとつまらないので、マーカーも表示してみましょう。先ほど仕込んだiniMap()の処理に、定義を追加するだけなので簡単です。

下記のように、どの地図(map)のどの位置(position)に表示したいのかを指定します。

titleには、マウスカーソルをホバーしたときに表示するテキストを設定できます。ひつまぶしと迷いましたが、今回はうなぎで!

      const marker = new AdvancedMarkerElement({
        map: map, // どの地図?
        position: { lat: 34.70517065710131, lng: 137.73424122206728 }, // どの座標?
        title: "うなぎ!!", // 食べたいね
      });

浜松市にマーカー、そして食べたいうなぎ

マーカーは複数設置できます。お隣の愛知県にも設置してみました。

      // NOTE: 別のマーカーと名前が被らないように注意
      const marker2 = new AdvancedMarkerElement({
        map: map,
        position: { lat: 35.17103900721801, lng: 136.88155730577137 },
        title: "ういろう!!",
      });

歳をとるほど、和菓子のおいしさに感動している気がする

完成した initMap()の処理がこちら。地図を作りこめば作りこむほど、ここの処理が増えていきます。

    async function initMap() {
      const { Map } = await google.maps.importLibrary("maps");
      const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
      map = new Map(document.getElementById('japan-map'), {
        center: { lat: 35.36188319083308, lng: 138.72714859384826 },
        zoom: 8,
        mapId: "DEMO_MAP_ID",
      });

      // マーカー定義を追加
      const marker = new AdvancedMarkerElement({
        map: map,
        position: { lat: 34.70517065710131, lng: 137.73424122206728 },
        title: "うなぎ!!",
      });

      const marker2 = new AdvancedMarkerElement({
        map: map,
        position: { lat: 35.17103900721801, lng: 136.88155730577137 },
        title: "ういろう!!",
      });
    }
    initMap();

おわりに

本記事ではGoogle Maps API について紹介しました。説明できた内容は基礎中の基礎であり、作りこめばもっともっとイケてる地図を作ることができます。

例えば、こんなことも可能です。

  • 地図を2つ表示する
  • マーカーを画像に差し替える
  • マーカーをクリックすると、別の位置にマーカーが出現する
  • 地図上に直線や円を表示する(色や線の太さ、塗りつぶし)

できることが多い分、組み合わせればなんだって作れます。ちなみに私は学生の頃にポケモンを捕まえるゲームを作りました。

そう、それが冒頭で触れた私が学生時代にワクワクしていたことです。

エンジニア3年目という発展途上の身の上ではありますが、初心を忘れずに技術者としての道を歩んでいきたいと思います!

それでは、みなさんよいクリスマスをお過ごしください。最後までご覧いただきありがとうございました!