LoginSignup
24
28

More than 3 years have passed since last update.

Google Maps JavaScript APIで複数マーカーをいい感じに表示する

Posted at

Google Maps PlatformのMaps JavaScript APIを使う機会があったのですが、とても簡単に複数マーカーをいい感じに表示できたので備忘録も兼ねて記事にしたいと思います。
ソースはここ

なお、API Keyは取得していることを前提として進めます。
取得がまだの方はここを参考にしてみてください。

Google Mapを表示させる

基本的にドキュメントを読めば簡単に表示させられます。

<div id="map"><!-- Google Map表示 --></div>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script>
<script>
  function initMap() {
    // 日本の中央を表示する
    const defaultSettings = {zoom: 15, center: {lat: 40.804365, lng: 141.134867}};
    const map = new google.maps.Map(
      document.querySelector('#map'),
      defaultSettings
    );
  }
</script>
  • Map表示用のdivを用意
  • Maps JavaScript APIを読み込む(API keyを忘れずに)
  • callback関数のinitMapを定義
  • Map表示用divDOMとズームレベルや初期表示位置を設定

これだけ
API Key取得のほうが面倒ですね。

指定の場所にマーカーをつける

こちらも簡単です。
ドキュメント

// 表示データ
const data = [
  { name: "東京タワー", lat: 35.6585805, lng: 139.7454329 },
  { name: "京都タワー", lat: 34.9875441, lng: 135.7592164 },
  { name: "通天閣", lat: 34.6524992, lng: 135.5063058 }
];

function initMap() {
  // 省略

  // 現在表示されているinfoWindowオブジェクト
  let currentWindow;

  data.map(d => {
    // マーカーをつける
    const marker = new google.maps.Marker({
      position: {lat: d.lat, lng: d.lng},
      map: map
    });

    // マーカークリックしたら地名をポップアップさせる
    marker.addListener('click', () => {
      currentWindow && currentWindow.close();
      const infoWindow = new google.maps.InfoWindow({content: d.name});
      infoWindow.open(map, marker);
      currentWindow = infoWindow;
    });
  });
}

jsonをmapで回してMarkerオブジェクトを作ります。

せっかくなので、マーカーをクリックしたらその地名が表示されるようにました。

  • Markerオブジェクトそれぞれにclickイベントを付与
  • 既に開いているinfoWindowオブジェクトがあればそのwindowを閉じる
  • クリックされたマーカーのinfoWindowオブジェクトを作成してwindowを開く
  • 開いたinfoWindowオブジェクトを保存

infoWindowオブジェクトを保持するのがちょっと不格好ですが、これ以外に方法がなさそうでした。
開いているwindowを取得できればいいのですが......

マーカーが画面上に収まるようにする

マーカーを表示できたのはいいのですが、画面に収まっていません。
そんなときはfitBoundsメソッドを使います。
引数には、LatLngBoundsクラスで範囲のインスタンスを渡してあげます。
LatLngBoundsの引数には緯度経度の最小値、最大値を渡します。

// マーカーがいい感じに表示できるよう調整
map.fitBounds(new google.maps.LatLngBounds(
  // sw
  {
    lat: Math.min(...data.map(d => d.lat)),
    lng: Math.min(...data.map(d => d.lng))
  },
  // ne
  {
    lat: Math.max(...data.map(d => d.lat)),
    lng: Math.max(...data.map(d => d.lng))
  }
));

ここで重要なのMapオブジェクトを作った際に指定したmaxZoomオプションです。

function initMap() {
  // 日本の中央を表示する
  const defaultSettings = {zoom: 15, /* これ */ maxZoom: 15, center: {lat: 40.804365, lng: 141.134867}};;
  const map = new google.maps.Map(
    document.querySelector('#map'),
    defaultSettings
  );

  // 以下省略
}

このオプションがないと、マーカーが1つだったり、マーカー同士が極端に近い場合、拡大されすぎて見栄えが悪くなってしまうんです。

こんな感じに
2019-04-27-17-06.png

動的に拡大率を変更する方法

基本的にfitBoundsmaxZoomオプションで事足りると思いますが、何らかの条件をつけて拡大率を動的に変更しなければならない場合は以下のうようにします。

const listener = google.maps.event.addListener(map, 'idle', () => {
  // 実際には何らかの条件で拡大率を取得設定する
  map.getZoom() > 15 && map.setZoom(15);
  google.maps.event.removeListener(listener);
});

MapのイベントにaddListenerしてズームレベルを変えています。
なぜこんな面倒なことをしなければならないのか
実はfitBoundsを実行したあとは、setZoom()getZoom()も効かないのです。
how do I get the zoom level after fitBounds

google.maps.eventであれば何でもよさそうだったので、様々な処理が完了したタイミングで実行されるidleイベントで処理するようにしました。

バグなのか仕様なのかはわかりかねますが、拡大率が設定できない場合は、上記のうようにしてみてください。

参考

Google Maps Platform Documentation

24
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
28