位置情報サービスのはじめ方

第4回 位置情報を表示してみよう

この記事を読むのに必要な時間:およそ 11 分

今回は,前回前々回で取得した位置情報を元に,地図を表示する方法を解説します。

Google Maps JavaScript APIで動的な地図を表示する

Webサイトで地図を表示する方法と言えば,多くの方がGoogle MapsのAPIを思い浮かべるのではないでしょうか。APIの公開後,現在も頻繁にアップデートがあり,いくつもの新機能が追加されています。ここでは,Google Maps JavaScript APIの基本的な使い方を解説しつつ,最新のversion 3で追加されたいくつかの面白い新機能を紹介したいと思います。

シンプルな地図の表示

まずは,オーソドックスに地図を表示してみましょう。

以下のようなHTMLを記述するだけで,ページ上に,マウス操作で自由自在に操作できる地図が表示できます。

https://github.com/chris4403/geolocation/blob/master/map-simple.html

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>Map Sample</title>
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0px; padding: 0px }
#map { width : 100%; height : 100%}
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script type="text/javascript">
function init(){
  var myOptions = {
    zoom: 8,
    center: new google.maps.LatLng(35.68,139.76),
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var map = new google.maps.Map(document.getElementById("map"),myOptions);
}
</script>
</head>
<body onload="init()">
<div id="map"></div>
</body>
</html>

11行目が,Google Maps JavaScript APIのversion3をロードしているところになります。

この部分は以下のように記述することもできます。

<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("maps","3", {"other_params":"sensor=true"});
</script>

version 2のAPIを利用されていた方は,API Keyがなくなったことに気づかれたでしょうか? version 2まで必要だったドメインごとのAPI Keyの発行が,version 3からは不要になりました。

また,version 3の特徴の1つとして,モバイルデバイスへの最適化というのが挙げられます。1つの大きなjsファイルとしてロードされていたversion 2に比べ,version 3は,必要最低限のものを最初にロードし,必要に応じて順次スクリプトをロードしていく方式になっています。そのため,version 2に比べて,モバイルデバイスでの表示や動作が早く,快適に利用できます。そのほか,地図のコントローラのデザインも最適化されています。

位置情報を取得して自分の位置を地図に表示

それでは,前回作った,定期的に自分自身の位置を取得するサンプルに手を加えて,取得した位置情報を地図上に表示してみます。

https://github.com/chris4403/geolocation/blob/master/geolocation-api-map.html

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>Geolocation API Sample</title>
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0px; padding: 0px }
#map {
  width : 100%;
  height : 300px;
}
</style>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/base/jquery-ui.css">
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("jquery","1.4.2");
google.load("jqueryui", "1.8.2");
google.load("maps","3", {"other_params":"sensor=true"});
</script>
<script type="text/javascript">

$(function(){
  var myOptions = {
    zoom: 8,
    center: new google.maps.LatLng(35.68,139.76),
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var map = new google.maps.Map(document.getElementById("map"),myOptions);
  
  // geolocationオブジェクトを生成
  var geolocation;
  try {
    if(typeof(navigator.geolocation) == 'undefined'){
      geolocation = google.gears.factory.create('beta.geolocation');
    } else {
      geolocation = navigator.geolocation;
    }
  } catch(e) {}
  if (!geolocation) {
    alert('位置情報は利用できません');
    return;
  }

  var watchId;
  // 位置情報取得に成功したとき呼ばれるcallback関数
  var success = function (position) {
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
    var latlng = new google.maps.LatLng(lat, lon);
    map.setCenter(latlng);
    var marker = new google.maps.Marker({
        position: latlng,
        map: map
    });
    google.maps.event.addListener(marker, 'click', function() {
      map.setZoom(8);
    });
  }
  // 位置情報取得に失敗したとき呼ばれるcallback関数
  var error = function (error) {
    var result = $('<tr>' +
      '<td>' + error.code + '</td>' +
      '<td>' + error.message + '</td>' +
      '</tr>');
    $('#errorresult').append(result);
  }
  // 位置情報取得時に設定するオプション
  var option = {
    enableHighAccuracy: true,
    timeout : 10000,
    maximumAge: 0
  };
  // 位置情報取得を開始する関数
  function start() {
    watchId = geolocation.watchPosition(success, error, option);
    $('#controler').attr('value','stop');
  }
  // 位置情報取得を停止する関数
  function stop() {
    geolocation.clearWatch(watchId);
    $('#controler').attr('value','start');
  }
  // ボタンに開始/停止関数を紐付け
  $('#controler').toggle(start, stop);
});
</script>
</head>
<body>
<form><input type="button" value="start" id="controler"></form>
<h2>取得成功</h2>
<div id="map"></div>
<h2>取得失敗</h2>
<table id="errorresult">
  <tbody>
  <tr>
    <th>code</th>
    <th>message</th>
  </tr>
  </tbody>
</table>
</body>
</html>

このサンプルは,ブラウザで緯度経度を取得できたら,その位置にマーカーを表示するというものです。

24~29行目

地図を表示するdivをidで取得して,Mapオブジェクトをnewします。

myOptionsという変数で渡しているのは,Mapオブジェクト生成時に渡すオプションの値です。zoomは,ズームレベルの初期値,centerは,地図の中心地点,mapTypeIdは,地図の表示タイプを定数で指定できます。

その他にも,地図をドラッグ可能にするかどうか,マウスホイールのスクロールで地図にズームイン/アウトするかどうかなど,細かい設定を行うことができます。設定できる項目については,APIリファレンスを参照してください。

48~55行目

取得した位置情報を元に,LatLngオブジェクト(位置を指し示すオブジェクト)をnewします。setCenterメソッドにLatLngオブジェクトを渡すことで,表示されている地図の中心点をそこへ移動させます。

LatLngオブジェクトと,Mapオブジェクトを引数に渡して,Markerオブジェクトをnewすることで,地図上にマーカーが表示します。

56~58行目

eventオブジェクトでマーカーのclickイベントをひろい,地図のズームレベルを変更します。

位置情報を取得して自分の位置を地図に表示(その2)

さらに,さきほどのサンプルを改良して,定期的に取得した位置情報を線(polyline)でつないでみます。

こちらのページにアクセスして,⁠start」ボタンを押すと,地図上に赤い線が引かれていきます。PCよりも,スマートフォンなどのモバイル端末で試してみるほうがよく分かります。

ブラウザでこのページを開いたまま,あちこち移動してみると,簡易的なGPSロガーとして利用することができます。

サンプルの変更した箇所は,47~66行目の位置情報を取得したときに呼ばれる関数の部分です。

https://github.com/chris4403/geolocation/blob/master/geolocation-api-polyline.html

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Geolocation API Sample</title>
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0px; padding: 0px }
#map {
  width : 100%;
  height : 300px;
}
</style>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/base/jquery-ui.css">
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("jquery","1.4.2");
google.load("jqueryui", "1.8.2");
google.load("maps","3", {"other_params":"sensor=true"});
</script>
<script type="text/javascript">

$(function(){
  var myOptions = {
    zoom: 14,
    center: new google.maps.LatLng(35.68,139.76),
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var map = new google.maps.Map(document.getElementById("map"),myOptions);
  
  // geolocationオブジェクトを生成
  var geolocation;
  try {
    if(typeof(navigator.geolocation) == 'undefined'){
      geolocation = google.gears.factory.create('beta.geolocation');
    } else {
      geolocation = navigator.geolocation;
    }
  } catch(e) {}
  if (!geolocation) {
    alert('位置情報は利用できません');
    return;
  }

  var watchId;
  var latlngs = [];
  // 位置情報取得に成功したとき呼ばれるcallback関数
  var success = function (position) {
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
    var latlng = new google.maps.LatLng(lat, lon);
    map.setCenter(latlng);
    if (latlngs.length > 0) {
      var prevLatlng = latlngs[latlngs.length -1];
      var pathLatlng = [prevLatlng, latlng];
      var path = new google.maps.Polyline({
        path: pathLatlng,
        strokeColor: "#FF0000",
        strokeOpacity: 1.0,
        strokeWeight: 2
      });
      path.setMap(map);
    }
    latlngs.push(latlng);
  }
  // 位置情報取得に失敗したとき呼ばれるcallback関数
  var error = function (error) {
    var result = $('<tr>' +
      '<td>' + error.code + '</td>' +
      '<td>' + error.message + '</td>' +
      '</tr>');
    $('#errorresult').append(result);
  }
  // 位置情報取得時に設定するオプション
  var option = {
    enableHighAccuracy: true,
    timeout : 10000,
    maximumAge: 0
  };
  // 位置情報取得を開始する関数
  function start() {
    watchId = geolocation.watchPosition(success, error, option);
    $('#controler').attr('value','stop');
  }
  // 位置情報取得を停止する関数
  function stop() {
    geolocation.clearWatch(watchId);
    $('#controler').attr('value','start');
  }
  // ボタンに開始/停止関数を紐付け
  $('#controler').toggle(start, stop);
});
</script>
</head>
<body>
<form><input type="button" value="start" id="controler"></form>
<h2>取得成功</h2>
<div id="map"></div>
<h2>取得失敗</h2>
<table id="errorresult">
  <tbody>
  <tr>
    <th>code</th>
    <th>message</th>
  </tr>
  </tbody>
</table>
</body>
</html>
47行目

取得した緯度経度を元に生成したLatLngオブジェクトを格納していく配列を定義しています。

54~64行目

緯度経度を格納している配列に1つ以上LatLngオブジェクトが入っているとき,1つ前に取得したLatLngオブジェクトと,今回取得したオブジェクトからPolyLineオブジェクトを生成して,マップ上に表示しています。

58行目のLatLngの配列を渡しているところで,47行目で定義した配列を渡すこともできます。ただし,この方法を取る場合は,同じところに線がなんども描かれないように,マップ上に描かれている線を都度削除する必要があります。

著者プロフィール

栗栖義臣(くりすよしおみ)

株式会社はてな。Java, JavaScript, ActionScript, Perlなどをたしなむ。

優秀な若手エンジニアたちに囲まれながら奮闘する毎日。

URL : http://d.hatena.ne.jp/chris4403/

技術ネタ : http://d.hatena.ne.jp/chris4403+tech/

コメント

コメントの記入