前回の記事で、Google Maps APIの導入方法からマーカー画像変更までの流れを紹介しました。

この記事では、変更したマーカーをクリックしたら吹き出し(情報ウィンドウ)を表示する方法について紹介します。

【重要】

  • 紹介する実装内容は、1つのマーカーに対してだけではありません。複数のマーカーに対して吹き出しを表示する方法も紹介します!
  • HTMLやCSSについては前回の記事と同じです。HTMLとCSSについては前回の記事を参考にしてください。

マーカーが1つの場合の実装例

これはわりと簡単です。

前回の記事の「地図の色を変えてみよう!」のセクションで紹介したJSの記述に数行追記するだけでOKです。

JavaScript

以下の、薄くハイライトした44行目から67行目を追記するだけです。

  window.initMap = () => {

    let map;

    const area = document.getElementById("map"); // マップを表示させるHTMLの箱
    // マップの中心位置(例:原宿駅)
    const center = {
      lat: 35.6673833,
      lng: 139.7054965
    };


    const styles = [
      //地図全体の色味をカスタマイズ
      //グレースケールにするために、saturation(彩度)を最低値-100に設定
      {
        stylers: [{
          saturation: -100
        }]
      }
    ];


    //マップ作成
    map = new google.maps.Map(area, {
      center,
      zoom: 17,
      styles: styles
    });

    //マーカーオプション設定
    const markerOption = {
      position: center, // マーカーを立てる位置を指定
      map: map, // マーカーを立てる地図を指定
      icon: {
        url: '/img/marker04.png' // お好みの画像までのパスを指定
      }
    }

    //マーカー作成
    const marker = new google.maps.Marker(markerOption);

     // 👇追記ここから
    //吹き出し(情報ウィンドウ)作成
    const infoWindow = new google.maps.InfoWindow({
      position: map.getCenter(),
      content: `<div class="custom-info">
        <div class="custom-info-item name">
        Tips
        </div>
        <div class="custom-info-item address">
        東京都ほげ
        </div>
        <div class="custom-info-item tel">
        <a href="tel:000-0000-0000">000-0000-0000</a>
        </div>
        <div class="custom-info-item google-map">
        <a href="https://goo.gl/maps/qytx6qv2aGp2Xg8G8" target="_blank">MAP</a>
        </div>
    </div>`,
      pixelOffset: new google.maps.Size(0, -50)
    })

    //マーカーをクリックしたら情報ウィンドウを開く
    marker.addListener('click', () => {
      infoWindow.open(map);
    });
  // 👆追記ここまで

  }

詳しく見ていきます。

まず、吹き出しを作成します。

//吹き出し(情報ウィンドウ)作成
const infoWindow = new google.maps.InfoWindow({
  position: map.getCenter(),
  content: `<div class="custom-info">
    <div class="custom-info-item name">
    Tips
    </div>
    <div class="custom-info-item address">
    東京都ほげ
    </div>
    <div class="custom-info-item tel">
    <a href="tel:000-0000-0000">000-0000-0000</a>
    </div>
    <div class="custom-info-item google-map">
    <a href="https://goo.gl/maps/qytx6qv2aGp2Xg8G8" target="_blank">MAP</a>
    </div>
</div>`,
  pixelOffset: new google.maps.Size(0, -50)
})

吹き出しを追加するためには、InfoWindowクラスを使用します。

new google.maps.InfoWindow({省略}) がそれに該当します。

InfoWindowクラスにはいくつかオプションが用意されています。

それが、positioncontentpixelOffsetなどです。(もっとありますが割愛)

  • positionには、吹き出しを表示させたい位置を指定します。

今回は、以下のようにしたので、吹き出しの表示位置は地図の中心です。

position: map.getCenter(),

地図の中心とはつまり、以下で指定した場所になります。

// マップの中心位置(例:原宿駅)
const center = {
  lat: 35.6673833,
  lng: 139.7054965
};
  • contentには吹き出しの中身を指定します。テキストまたはHTMLを指定することができます。

このHTMLに対してCSSでスタイリングすればOKです。
(後ほどコード例を紹介します。)

  • pixelOffset は情報ウィンドウのオフセット位置を Size クラスを使って指定します。

何も指定しないままだと、マーカーと重なって見ずらいので上方向に50px移動させています。

pixelOffset: new google.maps.Size(0, -50)

吹き出しを作成しただけだとまだ何も表示されないので、マーカーをクリックしたら吹き出しを表示するようにします。

それが以下の部分です。

//マーカーをクリックしたら情報ウィンドウを開く
marker.addListener('click', () => {
  infoWindow.open(map);
});

infoWindowクラスには、openメソッドというものが用意されているのでそれを利用しています。

openメソッドは以下のような引数をとることができます。

  • open([options, anchor])

今回は第一引数にmapを指定しています。
このmapは、以下の「map」を指していますので、名前が一致している必要があります。

//マップ作成
map = new google.maps.Map(area, {
  center,
  zoom: 17,
  styles: styles
});

infoWindow.open(map); とすることで、「吹き出しを表示するマップはこのマップ!」と指定しているわけですね

これでマーカーをクリックしたら吹き出しが表示されるかと思います。

CSS

このままだと吹き出しが少し見えずらいので、スタイリングします。

以下はあくまでサンプルです。

.custom-info {
  width: 200px;
  > * {
    font-family: "游ゴシック体", YuGothic, "游ゴシック", "Yu Gothic", "メイリオ",
      Meiryo, sans-serif !important;
  }
  .custom-info-item {
    font-size: 14px;
    font-weight: 500;
    + .custom-info-item {
      margin-top: 8px;
    }
  }
  .name {
    font-size: 16px;
    font-weight: bold;
  }
  .tel {
    a {
      display: block;
    }
  }
  .google-map {
    a {
      display: flex;
      align-items: center;
      position: relative;
      line-height: 1;
      &::after {
        content: "";
        background-color: transparent;
        background-image: url(./path/to/target_blank.svg);
        background-repeat: no-repeat;
        background-position: center center;
        background-size: contain;
        width: 15px;
        height: 15px;
        margin-left: 5px;
      }
    }
  }
}

すると、以下のような吹き出しになります。

マーカーが複数ある場合の実装例

以下のような仕様の場合の実装例を紹介します。

  • マーカーが複数ある
  • それぞれのマーカーに対して吹き出しを表示する
  • マーカーの画像は1種類だけではなく、情報ごとにマーカー画像を変更する

例えば、マップに表示したいデータが原宿駅・渋谷駅・新宿駅の3つだったとして、それぞれに吹き出しを追加し、それぞれマーカーの画像を変更する場合を見てみましょう。

最終的には以下のようになるのがゴールです!

初回表示時
マーカークリック時

JavaScript

HTMLとCSSは先ほどと同様で、JSの記述を以下のようにすればOKです!

  window.initMap = () => {

    let map;

    const area = document.getElementById("map"); // マップを表示させるHTMLの箱
    // マップの中心位置(例:原宿駅)
    const center = {
      lat: 35.6673833,
      lng: 139.7054965
    };

    const styles = [
      //地図全体の色味をカスタマイズ
      //グレースケールにするために、saturation(彩度)を最低値-100に設定
      {
        stylers: [{
          saturation: -100
        }]
      }
    ];

    //マップ作成
    map = new google.maps.Map(area, {
      center,
      zoom: 13,
      styles: styles
    });

    //マーカー表示データ
    const markerData = [{
        "name": "原宿駅",
        "type": "harazyuku",
        "lat": 35.6673833,
        "lng": 139.7054965,
        "address": "東京都渋谷区神宮前1丁目",
        "url": "https://goo.gl/maps/JPUH7LP278ZvgVSG6"
      },
      {
        "name": "渋谷駅",
        "type": "shibuya",
        "lat": 35.6690126,
        "lng": 139.6953269,
        "address": "東京都渋谷区渋谷2丁目",
        "url": "https://goo.gl/maps/uipJzh6uqVQmfFVk8"
      },
      {
        "name": "新宿駅",
        "type": "shinzyuku",
        "lat": 35.6807234,
        "lng": 139.6988152,
        "address": "東京都新宿区新宿3丁目38−1",
        "url": "https://goo.gl/maps/ckA28ah3BB2eUJre8"
      },
    ];

    //マーカーを格納する配列
    const marker = [];

    //吹き出し(情報ウィンドウ)を格納する配列
    const infoWindow = [];

    // マーカーをクリックしたときのイベント登録
    const markerEvent = (i) => {
      marker[i].addListener('click', () => {
        for (const j in marker) {
          //マーカーをクリックしたときに他の情報ウィンドウを閉じる
          infoWindow[j].close(map, marker[j]);
        }

        //クリックされたマーカーの吹き出し(情報ウィンドウ)を表示
        infoWindow[i].open(map, marker[i]);
      });
    }

    // マーカー毎の処理
    for (let i = 0; i < markerData.length; i++) {

      //マーカー作成
      // 緯度経度のデータ作成
      const markerLatLng = new google.maps.LatLng({
        lat: markerData[i]['lat'],
        lng: markerData[i]['lng']
      });

      //マーカーオプション設定
      const markerOption = {
        position: markerLatLng, // マーカーを立てる位置を指定
        map: map, // マーカーを立てる地図を指定
        icon: {
          url: '/img/marker.png'//デフォルトのマーカー画像
        }
      }

      //原宿だったときのマーカー画像を設定
      if (markerData[i]['type'] === 'harazyuku') {
        markerOption.icon = '/img/marker04.png'
      }
      //新宿だったときのマーカー画像を設定
      if (markerData[i]['type'] === 'shinzyuku') {
        markerOption.icon = '/img/maker05.png'
      }


      //各データごとにマーカーを作成
      marker[i] = new google.maps.Marker(markerOption);

      // 各データごとに吹き出し(情報ウィンドウ)を作成
      infoWindow[i] = new google.maps.InfoWindow({
        content: `<div class="custom-info">
                <div class="custom-info-item name">
                ${markerData[i]['name']}
                </div>
                <div class="custom-info-item address">
                ${markerData[i]['address']}
                </div>
                <div class="custom-info-item google-map">
                <a href="${markerData[i]['url']}" target="_blank">MAP</a>
                </div>
            </div>` // 吹き出しに表示する内容
      });

      // 各マーカーにクリックイベントを追加
      markerEvent(i);
    }

  }

簡単に解説

まず、マップに表示するための情報をまとめた配列を用意します。👇

//マーカー表示データ
const markerData = [{
    "name": "原宿駅",
    "type": "harazyuku",
    "lat": 35.6673833,
    "lng": 139.7054965,
    "address": "東京都渋谷区神宮前1丁目",
    "url": "https://goo.gl/maps/JPUH7LP278ZvgVSG6"
  },
  {
    "name": "渋谷駅",
    "type": "shibuya",
    "lat": 35.6690126,
    "lng": 139.6953269,
    "address": "東京都渋谷区渋谷2丁目",
    "url": "https://goo.gl/maps/uipJzh6uqVQmfFVk8"
  },
  {
    "name": "新宿駅",
    "type": "shinzyuku",
    "lat": 35.6807234,
    "lng": 139.6988152,
    "address": "東京都新宿区新宿3丁目38−1",
    "url": "https://goo.gl/maps/ckA28ah3BB2eUJre8"
  },
];

配列の中はオブジェクトになっていますね。

中でも必要なプロパティは、lat(緯度)lng(経度)です。
後程、各マーカーや吹き出しを作成するために使用するからです。

次に、各情報(原宿駅や渋谷駅)のマーカーを格納する配列と、吹き出しを格納する配列を用意します。

//マーカーを格納する配列
const marker = [];

//吹き出し(情報ウィンドウ)を格納する配列
const infoWindow = [];

次に、マーカーごとにクリックイベントを登録するための関数を作成します。

// マーカーをクリックしたときのイベント登録
const markerEvent = (i) => {
  marker[i].addListener('click', () => {
    for (const j in marker) {
      //マーカーをクリックしたときに他の情報ウィンドウを閉じる
      infoWindow[j].close(map, marker[j]);
    }

    //クリックされたマーカーの吹き出し(情報ウィンドウ)を表示
    infoWindow[i].open(map, marker[i]);
  });
}

これは後程利用します。

最後に、用意した各情報を格納した配列ごとの処理をします。

// マーカー毎の処理
for (let i = 0; i < markerData.length; i++) {

  // 緯度経度のデータ作成
  const markerLatLng = new google.maps.LatLng({
    lat: markerData[i]['lat'],
    lng: markerData[i]['lng']
  });

  //マーカーオプション設定
  const markerOption = {
    position: markerLatLng, // マーカーを立てる位置を指定
    map: map, // マーカーを立てる地図を指定
    icon: {
      url: '/img/marker.png'//デフォルトのマーカー画像
    }
  }

  //原宿だったときのマーカー画像を設定
  if (markerData[i]['type'] === 'harazyuku') {
    markerOption.icon = '/img/marker_harazyuku.png'
  }
  //新宿だったときのマーカー画像を設定
  if (markerData[i]['type'] === 'shinzyuku') {
    markerOption.icon = '/img/marker_shinzyuku.png'
  }


  //各データごとにマーカーを作成
  marker[i] = new google.maps.Marker(markerOption);

  // 各データごとに吹き出し(情報ウィンドウ)を作成
  infoWindow[i] = new google.maps.InfoWindow({
    content: `<div class="custom-info">
            <div class="custom-info-item name">
            ${markerData[i]['name']}
            </div>
            <div class="custom-info-item address">
            ${markerData[i]['address']}
            </div>
            <div class="custom-info-item google-map">
            <a href="${markerData[i]['url']}" target="_blank">MAP</a>
            </div>
        </div>` // 吹き出しに表示する内容
  });

  // 各マーカーにクリックイベントを追加
  markerEvent(i);
}

何をやっているかについては、上記のコードのコメントを見ていただければと思います^^

今回は、マーカーを表示する各情報を配列であらかじめ用意しました。

しかし、WordPressで登録したデータを動的に取得してマーカーを作成するという要件もあったりします。

そういうときは、各情報を格納するための空の配列を用意しておき、WordPressで登録されたデータを何かしらの方法で取得し、その空の配列に格納していけばOKですね^^

まとめ

今回紹介したコードをベースに、色々な案件の要件ごとに機能拡張していけると思いますので是非参考にしてみてください。

■参考記事
https://www.webdesignleaves.com/pr/plugins/googlemap_01.html