なりせなるてず

技術ブログにしたい

GoogleMapsAPI v3でマーカーを動かして住所を取得する

Google Maps API v3を使いマップを表示させて、住所で検索してマーカーを立て、マーカーを動かしたら住所を取得し直すものを実装した時のメモ

やりたいこと

・モーダルウィンドウ上にマップを表示
・住所や地名で検索しマーカーを立てる
・マーカーをドラッグしたら住所を取得し直す

モーダルウィンドウ上にマップを表示

まずはリファレンスを見る。
スタート ガイド - Google Maps JavaScript API v3 — Google Developers

Googleさんのリファレンスは動くコードだし、新しい情報だし本当素晴らしい。
Amazonは見習って欲しい。


このスタートガイドで行けると思ったが問題発生。
モーダルウィンドウをjs動的に作成・表示しようと思っていたのだがそれが原因でUncaught TypeError: Cannot read property 'offsetWidth' of nullというエラーがでてマップが表示されなかった。

原因はページロード時?(もしくはGoogleMapsAPIのjsを読み込んだタイミング?)で存在する要素でなければ行けなかったようで、要素をhtmlで作りdisplay:noneしておき、モーダル作成タイミングでマップの初期化処理をすれば表示された。


住所や地名で検索しマーカーを立てる

マーカーを表示するにはgoogle.maps.Markerオブジェクトを作り、マップと紐付ければ良い。

var marker = new google.maps.Marker( {
  map: map,
  position: results[0].geometry.location
});


検索はジオコーディングサービスを利用して行う。

var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': '東京'}, function(results, status) {
  alert(status);
});

こんな感じに住所を投げると当てはまる詳細な住所や緯度経度を返してくれる


検索すると地図が左上しか表示されなくなったりするので、そういう時は

google.maps.event.trigger(map, 'resize');

を呼び出すと全部表示してくれる

マーカーをドラッグしたら住所を取得し直す

マーカーをドラッグ出来るようにするには、マーカーオブジェクトを作成するときにdraggableプロパティをつければいい

var marker = new google.maps.Marker( {
  map: map,
  position: results[0].geometry.location,
  draggable: true
});


ドラッグし終わったイベントを取得する

google.maps.event.addListener(marker, 'dragend', function(e)
{
  codeLatLng(e.latLng.lat(), e.latLng.lng());
});


先ほどのgeocoderオブジェクトに緯度経度を投げると、逆ジオコーディングをしてくれて、一番違い住所を返してくれる

function codeLatLng(lat, lng)
{
  geocoder.geocode({'latLng': latlng}, function(results, status) {
    alert(status);
  });
}

ソースコード

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key= <span style="color: #ff2900">YOUR_API_KEY</span>&sensor=false"></script>
</head> 
 
<body>
<div class="container">
  <button id="view-modal">モーダルを表示</button>

  <div id="modal-window" style="display:none;">
    <input type="text" id="address">
    <button id="address-search">検索</button>

    <div id="map_canvas"></div>

    <input id="results" type="text" placeholder="ここに住所が表示されます">
  </div>
</div>
</body>
</html>


javascript

$(function()
{
  var map;
  var marker;
  var geocoder = new google.maps.Geocoder();

  function initialize() {
    var mapOptions = {
      center: new google.maps.LatLng(35.710538, 139.810952),
      zoom: 15,
      mapTypeId: google.maps.MapTypeId.ROADMAP,
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
  }

  function codeAddress() {
    var address = document.getElementById("address").value;
    geocoder.geocode( { 'address': address}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
        google.maps.event.trigger(map, 'resize');
        map.setCenter(results[0].geometry.location);
        marker = new google.maps.Marker({
          map: map,
          position: results[0].geometry.location,
          draggable: true
        });

        // 住所を取得
        $('#results').val(results[0].formatted_address);

        // ドラッグイベント
        google.maps.event.addListener(marker, 'dragend', function(e)
        {
          codeLatLng(e.latLng.lat(), e.latLng.lng());
        });
      } else {
        alert("Geocode was not successful for the following reason: " + status);
      }
    });
  }

  function codeLatLng(lat, lng)
  {
    var latlng = new google.maps.LatLng(lat, lng);
    geocoder.geocode({'latLng': latlng}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK)
        {
          if (results[1])
            {
              // 住所を取得
              $('#results').val(results[0].formatted_address);
            }
        }
    });
  }

  $('#view-modal').click(function(e)
  {
    e.stopPropagation();
    $('#modal-window').show();
    initialize();
  });

  $('#address-search').click(function(e)
  {
    e.stopPropagation();
    codeAddress();
  });
});