Webアプリを公開しよう! Chrome Web Store/Apps入門

第4回Webアプリを作ろう#1─⁠─Geolocation API、Notification API

前回までの連載で、Chrome Web Storeの概要やWeb Appsの作成方法と公開までをご紹介しました。今回より、いよいよ実際のWebアプリの作成を通して、各種APIの詳細を解説していきたいと思います。

Webアプリの概要

今回作成するWebアプリは、地図上で目的地を設定し、目的地と現在地との距離を計算する「Odometer(距離計⁠⁠」という単純なものを考えてみます。また、目的地までの距離が近づくとデスクトップにポップアップを表示して残りの距離を通知する機能なども付け加えていきます。Packaged Appsとして作成し、現在地の取得などにはGeolocation API、デスクトップへの通知にはNotification APIを利用します。地図データとのマッピングにはGoogle Mapsを利用しますが、本連載では解説しませんので詳細についてはこちらを参照してください。

また、本稿で作成するWebアプリは実際のWebアプリとしては作り込みが甘い部分もありますが、解説の都合上ご了承ください。

図1 Odometer
図1 Odometer

Webアプリの構成

Webアプリを構成するファイルを以下のように配置します。

ファイル構成
manifest.json
{
  "name": "Odometer",
  "description": "距離計",
  "version": "0.1",
  "app": {
    "launch": {
      "local_path": "main.html"
    }
  },
  "icons": {
    "16": "icon_16.png",
    "48": "icon_48.png",
    "128": "icon_128.png"
  },
  "permissions": [
    "geolocation",
    "notifications"
  ]
}

Packaged Appとして作成するため⁠app⁠フィールドの⁠launch⁠には、⁠local_path⁠を設定します。今回は、Webアプリのトップページとしてmain.htmlを指定しています。また、Geolocation APIとNotification APIを利用するため、⁠permissions⁠⁠geolocation⁠⁠notifications⁠を指定しています。これによって、各APIを利用する際に許可を求める通知が表示されていたものが暗黙的に許可されます。

main.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Odometer</title>
    <link rel="stylesheet" href="./css/odometer.css">
    <script src="http://maps.google.com/maps/api/js?sensor=true"></script>
    <script src="./js/odometer.js"></script>
</head>
<body>
<div id="map-container">
    <div id="map"></div>
</div>
<div id="data-container">
    <form id="search">
        <input type="text" id="address" placeholder="住所など">
        <input type="submit" value="検索">
    </form>
    <p>地図をクリックして目的地を設定してください</p>
    <section id="distance-container">
        <h1>- 目的地までの距離 - </h1>
        
        <p style=""><span id="distance">0</span> km<br>
        <input type="button" value="自動更新開始" id="auto-update"></p>
        
    </section>
    
    <section>
        <h1>- 目的地 -</h1>
        <table>
            <tr>
                <td width="80px">緯度</td>
                <td width="200px" id="dest-latitude"></td>
            </tr>
            <tr>
                <td>経度</td>
                <td id="dest-longitude"></td>
            </tr>
        </table>
        <input type="button" value="目的地を表示" id="move-dest">
    </section>
    
    <section>
        <h1>- 現在地 -</h1>
        <table>
            <tr>
                <td width="80px">緯度</td>
                <td width="200px" id="latitude"></td>
            </tr>
            <tr>
                <td>経度</td>
                <td id="longitude"></td>
            </tr>
            <tr>
                <td>精度</td>
                <td id="accuracy"></td>
            </tr>
            <tr>
                <td>移動方向</td>
                <td id="heading"></td>
            </tr>
            <tr>
                <td>移動速度</td>
                <td id="speed"></td>
            </tr>
            <tr>
                <td>日時</td>
                <td id="timestamp"></td>
            </tr>
        </table>
        <input type="button" value="現在地を表示" id="move-current">
    </section>
</div>
</body>
</html>

Geolocation API

Geolocation APIは、緯度や経度といった位置情報を取得するAPIです。window.navigator.geocation以下のメソッドを使って取得することができます。Webアプリの実際のソースコードを例に解説します。

位置情報の取得

まずは、Geolocation APIを使って最初に現在地を取得して表示します。現在地を取得している部分は、以下の通りです。

odometer.js(該当部分のみ抜粋)
//オプション
var geoOptions = {
    enableHighAccuracy: true,   //高精度要求
    timeout: 6000,          //タイムアウト(ミリ秒)
    maximumAge: 0       //キャッシュ有効期限(ミリ秒)
}

if (navigator.geolocation) {
    
    //現在地の位置情報取得
    navigator.geolocation.getCurrentPosition(
        init,       //成功時コールバック
        onError,    //失敗時コールバック
        geoOptions  //オプション
    );
} else {
    return;
}

現在の位置情報を取得する場合は、navigator.geolocation.getCurrentPositionメソッドを使用します。第1引数に取得成功時のコールバック、第2引数に取得失敗時のコールバック、第3引数にオプションを指定します。成功時のコールバックメソッドの引数に与えられるイベントオブジェクトから位置情報を取り出します。ここでは成功時のコールバックにinitメソッドを指定しています。

/*
 * 初期表示
 */
function init(position){
    
    //地図作成
    createMap(position.coords.latitude, position.coords.longitude);
    
    //現在地情報表示
    showCurrentPosition(position);
    
    //現在地を保持
    currentPos.lat = position.coords.latitude;
    currentPos.lng = position.coords.longitude;
    
}

/*
 * エラーコールバック
 */
function onError(e) {
    alert(e.message + '(' + e.code + ')');
}

/*
 * 現在地情報表示
 */
function showCurrentPosition(position){
    
    //現在地を表示
    //緯度
    document.getElementById('latitude').textContent = 
        position.coords.latitude;
    
    //経度
    document.getElementById('longitude').textContent = 
        position.coords.longitude;
    
    //精度
    document.getElementById('accuracy').textContent = 
        position.coords.accuracy;
    
    //移動方向
    document.getElementById('heading').textContent = 
        position.coords.heading;
    
    //移動速度
    document.getElementById('speed').textContent = 
        position.coords.speed;
    
    //取得日時
    var dt = new Date(position.timestamp);
    document.getElementById('timestamp').textContent =
        dt.getFullYear() + '年' + (dt.getMonth()+1) + '月' + dt.getDate() + '日' + 
        dt.getHours() + '時' + dt.getMinutes() + '分' + dt.getSeconds() + '秒';
}

initメソッド内では、createMapメソッドでGoogle Mapsを使って地図を作成しています。HTMLに位置情報を表示しているのはshowCurrentPositionメソッドになります。ここでは、イベントオブジェクト内の各プロパティをHTMLにセットしているだけです。取得可能な位置情報は緯度、経度といった基本的な情報に加え、精度や移動方向、移動速度なども取得することができます。詳細は下記表を参照してください。注意点として、navigator.geolocation.getCurrentPositionメソッドでは移動している状態を認識していないため、移動方向、移動速度を取得することができません。これらを取得するには、navigator.geolocation.watchPositionメソッドを使って継続的に位置情報を取得する必要があります。navigator.geolocation.watchPositionメソッドについては後述します。

表1 位置情報のイベントオブジェクト
プロパティ 説明
coords.latitude 緯度
coords.longitude 経度
coords.accuracy 精度(誤差をメートル単位で表示)
coords.altitude 高度(GPS高度)
※標高ではないことに注意
coords.altitudeAccuracy 高度の精度(誤差をメートル単位で表示)
coords.heading 移動方向(真北を0度とした右回りの角度)
coords.spped 移動速度(m/s)
timestamp 取得日時(数値)
※本来の仕様上はDate型を返す

目的地の設定と距離の算出

目的地の設定は、地図上をクリックすることによって行います。Google Mapsのクリックイベントから緯度と経度を取得することができるので、現在地情報の表示と同様にshowDestinationPositionメソッドで目的地の緯度、経度を表示します。また、同時にshowDistanceメソッドで目的地までの距離を算出して表示します。

/*
 * 目的地情報表示
 */
function showDestinationPosition(lat, lng) {
    
    //目的地を表示
    document.getElementById('dest-latitude').textContent = lat;
    document.getElementById('dest-longitude').textContent = lng;
}

/*
 * 目的地までの距離表示
 */
function showDistance(currentPos, destPos){
    
    //単位をkmに変換して表示
    document.getElementById('distance').textContent =
        Math.round(getDistance(currentPos.lat, currentPos.lng, destPos.lat, destPos.lng)) / 1000;
}

/*
 * 2点間距離計算(m)
 */
function getDistance(lat, lng, dLat, dLng){
    
    //緯度1度あたり111km、経度1度あたり91kmの概算
    var h = Math.abs(dLat - lat) * 111000;
    var v = Math.abs(dLng - lng) * 91000;
    
    return Math.sqrt(Math.pow(h, 2) + Math.pow(v, 2));
}

目的地までの距離の算出については、厳密な計算方法は非常に複雑なため、ここでは緯度1度あたり111km、経度1度あたり91kmの概算で計算しています。そのため、日本以外の場所では誤差が大きくなります。

位置情報の自動更新

次に、現在地が移動などによって更新された場合に、位置情報と目的地までの距離を再計算するようにしたいと思います。位置情報の自動更新にはnavigator.geolocation.watchPositionメソッドを使用します。使い方はnavigator.geolocation.getCurrentPositionメソッドと同様ですが、位置情報が更新されるたびに第1引数のコールバックが呼び出されます。自動更新を停止するには、navigator.geolocation.clearWatchメソッドを使用します。引数には、navigator.geolocation.watchPositionメソッドの戻り値である識別IDを指定します。

/*
 * 自動更新
 */
var watchId = 0;    //自動更新停止用のID
document.getElementById('auto-update').addEventListener('click', function(){
    
    if ( watchId == 0) {
        
        if ( destPos.lat == 0 && destPos.lng == 0 ) {
            alert('目的地が設定されていません');
            return;
        }
        
        
        //自動更新を開始する
        watchId = navigator.geolocation.watchPosition(function(position){
            
            //地図更新
            updateMap(position.coords.latitude, position.coords.longitude);
            
            //現在地情報表示
            showCurrentPosition(position);
            
            //目的地までの距離表示
            currentPos.lat = position.coords.latitude;
            currentPos.lng = position.coords.longitude;
            showDistance(currentPos, destPos);
            
        }, null, geoOptions);
        
        this.value = '自動更新停止';
        
    } else {
        
        //以前の自動更新を停止する
        navigator.geolocation.clearWatch(watchId);
        watchId = 0;
        this.value = '自動更新開始';
    }
    
}, false);

実際の動きですが、⁠自動更新開始」ボタンをクリックするとnavigator.geolocation.watchPositionメソッドを呼び出し、コールバックの中で現在地情報と目的地までの距離を更新しています。また、watchIdという変数に識別IDを保持しておき、次回の「自動更新停止」ボタンをクリックした際に、navigator.geolocation.clearWathメソッドで自動更新を停止しています。

ここまでで、最初に現在地を表示し、目的地を設定して目的地までの距離を表示すること、移動することによってリアルタイムに内容が更新されるところまでが実現できました。

表2 Geolocation API ⁠navigator.geolocation)
メソッド 説明
getCurrentPosition(onSuccessCallback, onErrorCallback, options) 位置情報を取得する
watchPosition(onSuccessCallback, onErrorCallback, options) 位置情報を継続的に取得する。戻り値として、自動更新停止のための識別IDを返す
clearWatch(watchId) 位置情報の自動更新を停止する
表3 位置情報取得のオプション
オプション 説明
enableHighAccuracy 高精度を要求する(真偽値)
timeout タイムアウト(ミリ秒)
maximumAge キャッシュ有効期限(ミリ秒)

Notification API

Odometerに新たな機能として、目的地までの距離が近づくとNotification APIを使ってデスクトップにポップアップを表示し、残りの距離を通知する機能を実装します。

Notification APIは、デスクトップ上に通知用のポップアップを表示するAPIです。window.webkitNotifications以下のメソッドを利用します。

デスクトップへの通知

まずは、汎用的に利用できるように、notifiyメソッドを定義し、navigator.geolocation.wachPositionメソッドで登録したコールバック内からnotifiyメソッド呼び出すように変更します。

/*
 * デスクトップへ通知
 */
function notify(title, message){
    
    //マニフェストファイルへの記述で許可されている
    if ( webkitNotifications.checkPermission() == 0 ) {
        
        var popup = webkitNotifications.createNotification('icon_48.png', title, message);
        popup.ondisplay = function(){
            setTimeout(function(){
                popup.cancel();
            }, 5000);
        };
        popup.show();
        
    } else {
        
        //デスクトップへの通知許可を要求する
        webkitNotifications.requestPermission();
    }
}

webkitNotifications.checkPermissionメソッドは、Notification APIの許可や未許可、拒否などのステータスを返すメソッドですが、マニフェストファイルの⁠permissions⁠⁠notifications⁠を指定しているため、ここでは必ず許可されていることになります。

もし、未許可や拒否などのステータスの場合、webkitNotifications.requestPermissionメソッドを使って許可を求めるようにしています。ただし、webkitNotifications.requestPermissionメソッドは、ボタンなどのクリックイベント内でしか動作しませんので注意が必要です。

デスクトップへの通知用のポップアップは、webkitNotifications.createNotificationメソッドを使用して作成します。第1引数にアイコンのURL、第2引数にタイトル、第3引数に本文を指定します。作成したNotifiationオブジェクトのshowメソッドで実際に通知を行い、cancelメソッドで通知をキャンセルします。ここでは、5秒後にポップアップが閉じるようにsetTimeoutメソッドを使ってcancelメソッドを使用しています。

そのほかにも、HTMLを通知用のポップアップに表示するwebkitNotifications.createHTMLNotificationメソッドもあります。通知する情報量などが多い場合には、こちらを利用してください。

//通知済みの距離を保持
var notified = {};

~省略~

//自動更新を開始する
watchId = navigator.geolocation.watchPosition(function(position){
    
    //地図更新
    updateMap(position.coords.latitude, position.coords.longitude);
    
    //現在地情報表示
    showCurrentPosition(position);
        
        //目的地までの距離表示
        currentPos.lat = position.coords.latitude;
        currentPos.lng = position.coords.longitude;
        showDistance(currentPos, destPos);
    
    //デスクトップに通知
    //目的地までの距離を取得してkm単位に変換
    var distance = Math.round(getDistance(currentPos.lat, currentPos.lng, destPos.lat, destPos.lng)) / 1000;
    
    //距離によってしきい値を変える
    var threshold = 0;
    if ( distance < 1 ) {
        
        //1km未満は、200mごとに通知
        threshold = 0.2;
        
    } else if (distance < 10 ) {
        
        //10km未満は、1kmごとに通知
        threshold = 1;
        
    } else {
        
        //10km以上は、10kmごとに通知
        threshold = 10;
    }
    
    //一度通知した距離は再通知しない
    var notifiedKey = Math.floor(distance / threshold) * threshold;
    if ( !notified[notifiedKey]  ) {
        notify('目的地までの距離', '約 ' + distance + ' km');
        notified[notifiedKey] = true;
    }
    
    
}, null, geoOptions);

位置情報が更新されるたびに通知されるのは冗長ですので、1km未満の場合は200mごと、10km未満の場合は1kmごと、それ以外の場合は10kmごとに通知されるようにしています。また、一度通知を行った距離では、再度通知しないようnotifiedという変数に通知済みの距離を保持しています。

画像

これで、位置情報の取得からデスクトップへの通知までが完成しました。

表4 Notification API(webkitNotifications)
メソッド 説明
checkPermission() デスクトップへの通知に対する許可、未許可、拒否などのステータスを取得する
requestPermission() デスクトップへの通知の許可を求める
createNotification(iconURL, title, message) 通知用のポップアップを作成する
createHTMLNotification(htmlURL) 通知用のポップアップをHTMLから作成する
表5 Notificationオブジェクト
メソッド 説明
show() デスクトップへ通知する
cancel() デスクトップへの通知をキャンセルする
onclick 通知ポップアップのクリックイベントのコールバック
onclose 通知ポップアップの閉じるイベントのコールバック
ondisplay 通知ポップアップの表示イベントのコールバック
※ドラフト仕様では、onshow
onerror エラー時のコールバック

まとめ

今回は、OdometerというWebアプリの作成を通して、Geolocation API、Notification APIの詳細を解説しました。次回は、このOdometerにさらに機能を追加していく形で各種APIを解説していきたいと思います。本稿で作成したOdometerは、下記リンクからダウンロードできますので宜しければ参考にしてください。

crxファイルはzipファイルですので、右クリックからのダウンロード後に拡張子をzipに変えていただければ中身を参照できます

また、本連載で取り上げているChrome Web Store/Appsは、⁠Chrome API Developers JP」という開発者コミュニティでも議論されています。こちらも覗いてみてはいかがでしょうか。

参考

main.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Odometer</title>
    <link rel="stylesheet" href="./css/odometer.css">
    <script src="http://maps.google.com/maps/api/js?sensor=true"></script>
    <script src="./js/odometer.js"></script>
</head>
<body>
<div id="map-container">
    <div id="map"></div>
</div>
<div id="data-container">
    <form id="search">
        <input type="text" id="address" placeholder="住所など">
        <input type="submit" value="検索">
    </form>
    <p>地図をクリックして目的地を設定してください</p>
    <section id="distance-container">
        <h1>- 目的地までの距離 - </h1>
        
        <p style=""><span id="distance">0</span> km<br>
        <input type="button" value="自動更新開始" id="auto-update"></p>
        
    </section>
    
    <section>
        <h1>- 目的地 -</h1>
        <table>
            <tr>
                <td width="80px">緯度</td>
                <td width="200px" id="dest-latitude"></td>
            </tr>
            <tr>
                <td>経度</td>
                <td id="dest-longitude"></td>
            </tr>
        </table>
        <input type="button" value="目的地を表示" id="move-dest">
    </section>
    
    <section>
        <h1>- 現在地 -</h1>
        <table>
            <tr>
                <td width="80px">緯度</td>
                <td width="200px" id="latitude"></td>
            </tr>
            <tr>
                <td>経度</td>
                <td id="longitude"></td>
            </tr>
            <tr>
                <td>精度</td>
                <td id="accuracy"></td>
            </tr>
            <tr>
                <td>移動方向</td>
                <td id="heading"></td>
            </tr>
            <tr>
                <td>移動速度</td>
                <td id="speed"></td>
            </tr>
            <tr>
                <td>日時</td>
                <td id="timestamp"></td>
            </tr>
        </table>
        <input type="button" value="現在地を表示" id="move-current">
    </section>
</div>
</body>
</html>
odometer.css
#map-container, #data-container {
    float: left;
}

#data-container {
    padding: 10px;
}

#map {
    width: 600px;
    height: 500px;
}

h1 {
    font-size: 1em;
    
}

#distance-container p {
    font-size: 2em;
    margin-top: 5px;
}
odometer.js
document.addEventListener('DOMContentLoaded', function(){
    
    //現在地
    var currentPos = {
        lat: 0,
        lng: 0
    }
    
    //目的地
    var destPos = {
        lat: 0,
        lng: 0
    }
    
    //通知済みの距離を保持
    var notified = {};
    
    //オプション
    var geoOptions = {
        enableHighAccuracy: true,   //高精度要求
        timeout: 6000,              //タイムアウト(ミリ秒)
        maximumAge: 0               //キャッシュ有効期限(ミリ秒)
    }
    
    if (navigator.geolocation) {
        
        //現在地の位置情報取得
        navigator.geolocation.getCurrentPosition(
            init,       //成功時コールバック
            onError,    //失敗時コールバック
            geoOptions  //オプション
        );
    } else {
        return;
    }
    
    /*
     * 初期表示
     */
    function init(position){
        
        //地図作成
        createMap(position.coords.latitude, position.coords.longitude);
        
        //現在地情報表示
        showCurrentPosition(position);
        
        //現在地を保持
        currentPos.lat = position.coords.latitude;
        currentPos.lng = position.coords.longitude;
        
    }
    
    /*
     * エラーコールバック
     */
    function onError(e) {
        alert(e.message + '(' + e.code + ')');
    }
    
    /*
     * 現在地情報表示
     */
    function showCurrentPosition(position){
        
        //現在地を表示
        //緯度
        document.getElementById('latitude').textContent = 
            position.coords.latitude;
        
        //経度
        document.getElementById('longitude').textContent = 
            position.coords.longitude;
        
        //精度
        document.getElementById('accuracy').textContent = 
            position.coords.accuracy;
        
        //移動方向
        document.getElementById('heading').textContent = 
            position.coords.heading;
        
        //移動速度
        document.getElementById('speed').textContent = 
            position.coords.speed;
        
        //取得日時
        var dt = new Date(position.timestamp);
        document.getElementById('timestamp').textContent =
            dt.getFullYear() + '年' + (dt.getMonth()+1) + '月' + dt.getDate() + '日' + 
            dt.getHours() + '時' + dt.getMinutes() + '分' + dt.getSeconds() + '秒';
    }
    
    /*
     * 目的地情報表示
     */
    function showDestinationPosition(lat, lng) {
        
        //目的地を表示
        document.getElementById('dest-latitude').textContent = lat;
        document.getElementById('dest-longitude').textContent = lng;
    }
    
    /*
     * 目的地までの距離表示
     */
    function showDistance(currentPos, destPos){
        
        //単位をkmに変換して表示
        document.getElementById('distance').textContent =
            Math.round(getDistance(currentPos.lat, currentPos.lng, destPos.lat, destPos.lng)) / 1000;
    }
    
    /*
     * 2点間距離計算(m)
     */
    function getDistance(lat, lng, dLat, dLng){
        
        //緯度1度あたり111km、経度1度あたり91kmの概算
        var h = Math.abs(dLat - lat) * 111000;
        var v = Math.abs(dLng - lng) * 91000;
        
        return Math.sqrt(Math.pow(h, 2) + Math.pow(v, 2));
    }
    
    /*
     * 自動更新
     */
    var watchId = 0;    //自動更新停止用のID
    document.getElementById('auto-update').addEventListener('click', function(){
        
        if ( watchId == 0) {
            
            if ( destPos.lat == 0 && destPos.lng == 0 ) {
                alert('目的地が設定されていません');
                return;
            }
            
            //通知済みの距離をリセット
            notified = {};
            
            //自動更新を開始する
            watchId = navigator.geolocation.watchPosition(function(position){
                
                //地図更新
                updateMap(position.coords.latitude, position.coords.longitude);
                
                //現在地情報表示
                showCurrentPosition(position);
                
                //目的地までの距離表示
                currentPos.lat = position.coords.latitude;
                currentPos.lng = position.coords.longitude;
                showDistance(currentPos, destPos);
                
                //デスクトップに通知
                //目的地までの距離を取得してkm単位に変換
                var distance = Math.round(getDistance(currentPos.lat, currentPos.lng, destPos.lat, destPos.lng)) / 1000;
                
                //距離によってしきい値を変える
                var threshold = 0;
                if ( distance < 1 ) {
                    
                    //1km未満は、200mごとに通知
                    threshold = 0.2;
                    
                } else if (distance < 10 ) {
                    
                    //10km未満は、1kmごとに通知
                    threshold = 1;
                    
                } else {
                    
                    //10km以上は、10kmごとに通知
                    threshold = 10;
                }
                
                //一度通知した距離は再通知しない
                var notifiedKey = Math.floor(distance / threshold) * threshold;
                if ( !notified[notifiedKey]  ) {
                    notify('目的地までの距離', '約 ' + distance + ' km');
                    notified[notifiedKey] = true;
                }
                
                
            }, null, geoOptions);
            
            this.value = '自動更新停止';
            
        } else {
            
            //以前の自動更新を停止する
            navigator.geolocation.clearWatch(watchId);
            watchId = 0;
            this.value = '自動更新開始';
        }
        
    }, false);
    
    /*
     * デスクトップへ通知
     */
    function notify(title, message){
        
        //マニフェストファイルへの記述で許可されている
        if ( webkitNotifications.checkPermission() == 0 ) {
            
            var popup = webkitNotifications.createNotification('icon_48.png', title, message);
            popup.ondisplay = function(){
                setTimeout(function(){
                    popup.cancel();
                }, 5000);
            };
            popup.show();
            
        } else {
            
            //デスクトップへの通知許可を要求する
            webkitNotifications.requestPermission();
        }
    }
    
    
    /*
     * Google Maps
     */
    var map,
        marker;
    var mapOptions = {
        zoom: 13,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    
    /*
     * 地図作成
     */
    function createMap(lat, lng) {
        
        //地図作成
        var infowindow = new google.maps.InfoWindow(),
            latLng = new google.maps.LatLng(lat, lng);
        map = new google.maps.Map(document.getElementById("map"), mapOptions);
        
        //マーカー作成
        marker = new google.maps.Marker(
            {
                title: '現在地',
                position: latLng,
                map: map
            }
        );
        
        /*
         * クリックで目的地設定
         */
        var destMarker = null;
        google.maps.event.addListener(map, "click", function(event){
            if ( destMarker ) {
                destMarker.setMap(null);
            }
            destMarker = new google.maps.Marker(
                {
                    title: '目的地',
                    position: event.latLng,
                    map: map
                }
            );
            
            //目的地情報表示
            showDestinationPosition(event.latLng.lat(), event.latLng.lng());

            //目的地までの距離表示
            destPos.lat = event.latLng.lat();
            destPos.lng = event.latLng.lng();
            showDistance(currentPos, destPos);
            
            //通知済みの距離をリセット
            notified = {};
        });
        
        map.setCenter(latLng);
        infowindow.open(map);
    }
    
    /*
     * 地図更新
     */
    function updateMap(lat, lng) {
        
        var latLng = new google.maps.LatLng(lat, lng);
        
        //マーカー作成
        if ( marker ) {
            marker.setMap(null);
        }
        marker = new google.maps.Marker(
            {
                title: '現在地',
                position: latLng,
                map: map
            }
        );
        map.setCenter(latLng);
    }
    
    /*
     * 住所検索
     */
    var geocoder = new google.maps.Geocoder();
    document.getElementById('search').addEventListener('submit', function(event){
        
        //デフォルトのsubmit動作をキャンセル
        event.preventDefault();
        
        var addr = document.getElementById('address').value;
        if ( !addr ) {
            return;
        }
        
        //Geocoding APIで住所から座標を取得する
        geocoder.geocode({ 'address': addr}, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                
                //最初の候補を表示する
                map.setCenter(results[0].geometry.location);
            } else {
                alert('検索できませんでした');
            }
        });
        
    }, false);
    
    /*
     * 目的地表示
     */
    document.getElementById('move-dest').addEventListener('click', function(){
        map.setCenter(new google.maps.LatLng(destPos.lat, destPos.lng));
    }, false);
    
    /*
     * 現在地表示
     */
    document.getElementById('move-current').addEventListener('click', function(){
        map.setCenter(new google.maps.LatLng(currentPos.lat, currentPos.lng));
    }, false);
    

}, false);

おすすめ記事

記事・ニュース一覧