JavaScriptでWebアプリを開発できる「Node.js」活用入門 5ページ

newb mapのクライアントサイドスクリプト:index.js

 最後に、newb mapで使用されているクライアントサイドのスクリプトを見てみよう。まず、「<サーバー名>/」というURLにアクセスした際に表示されるHTMLから呼び出される「index.js」から説明する。このファイルの実体は、「/public/javascripts/index.js」ファイルだ。ここでは下記のような処理を行っている。

  • Bing Mapsの表示
  • 「Search」ボタンがクリックされた際に入力された地名を検索し、ヒットした場所にBing Mapsのビューを移動させる
  • Bing Mapsをクリックした際にその場所にピンをセットする
  • 「Publish」ボタンがクリックされた際にピン情報を「<サーバー名>/publish/」というURLにPOSTで送信し、公開IDを受け取ってピン付き地図のURLを表示する

 今回はBing Mapsを利用するため、Microsoftが提供している「Bing Maps AJAX Control SDK」を利用している。なお、このSDKの利用には、Bing Mapsのアカウントや認証キーが必要だ。Bing Mapsのアカウントは「Bing Maps Account Center」で作成できる(図17)。

図17 Bing Mapsのアカウントは「Bing Maps Account Center」で作成できる
図17 Bing Mapsのアカウントは「Bing Maps Account Center」で作成できる

 認証キーはBing Maps Account Centerにログインし、「Create or view keys」をクリックすることで作成できる。ここではアプリケーション名やアプリケーションのURL、アプリケーションの種類などの情報が要求されるので、これらを入力して「Submit」をクリックすると認証用のキー文字列が発行される(図18)。

図18 アクセスキーのアプリケーション名やアプリケーションのURL、アプリケーションの種類などの情報が要求される
図18 アクセスキーのアプリケーション名やアプリケーションのURL、アプリケーションの種類などの情報が要求される

 また、Bing Maps AJAX Control SDKを利用するには、使用するWebページのHTML内で下記のようにmapcontrolスクリプトをロードしておく必要がある。

<script src='http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&mkt=ja-jp'></script>

 mapcontrolスクリプトはMicrosoftが提供するJavaScriptコードで、URL末尾の「mkt=ja-jp」の部分を変更することで地図の表示言語を変更できる。この例では日本語で地図を表示させているが、たとえばドイツ語で表示させるなら「mkt=de-de」とする。この指定がない場合は、デフォルトの言語である英語で地図が表示される。

Bing Mapsの利用準備とドキュメントのロード時に実行するコード

 index.jsでは、まずBing Mapsの操作に使用するMicrosoft.Maps型オブジェクトの生成と、認証キーの指定を行っている。また、ドキュメントのロード時にdocReady関数を呼び出して初期設定を行うよう指定している(リスト14)。

 docReady()関数ではBing Mapsの表示や各フォームがサブミットされた際に呼び出されるハンドラの設定、Bing Mapsがクリックされた際に呼び出されるハンドラ、使用する変数の定義を行っている。

リスト14 Bing Mapsの利用準備とドキュメントのロード時に実行するコード(index.js)

var Bing = Microsoft.Maps;
var mapCredential = 'AvVtoL6WVsQzl-3kfAoxAPR9gnJ_yh5TS6Pf0T59fMrzv86oq2qRRz5jWXqC7kWe';
var map;
$(document).ready(docReady);

function docReady() {
    loadMap();
    $('#search_form').submit(doSearch);
    $('#publish_form').submit(doPublish);
    Bing.Events.addHandler(map, 'mousedown', mapOnMouseDown);
    Bing.Events.addHandler(map, 'mouseup', mapOnMouseUp);
    pinsInfo = new Array();
    subDistances = new Array();
}

Bing MapsをWebページ内に表示する

 Bing MapsをWebページ内に表示するコードがリスト15だ。Bing Mapsの表示はMicrosoft.Maps.Mapオブジェクトを生成することで行われる。引数には地図を表示する要素や認証キー、表示する場所、ズームレベル、表示モードといった情報を与えている。

リスト15 Bing MapsをWebページ内に表示するコード(index.js)

function loadMap() {
    map = new Bing.Map($('#map_body')[0], {
        credentials: mapCredential,
        center: new Bing.Location(35.69, 139.7),
        zoom: 12,
        mapTypeId:Microsoft.Maps.MapTypeId.road
    });
}

地名の検索

 Bing Mapでは、REST APIを利用することで地名などからその位置情報を検索することが可能だ。今回は地図の左上にフォームを用意し、そこから検索を行える。このフォームに対しdocReady関数内でハンドラを登録してあり、サブミット時にdoSearch関数が呼ばれる仕組みだ。

 doSearch()関数では、Bing.MapオブジェクトのgetCredentials関数を呼び出し、検索に必要な認証キーを取得する。この関数は成功すると引数に与えたコールバック関数を実行する形になっている。

function doSearch() {
    map.getCredentials(callSearchService);
    return false;
}

 getCredentials関数から呼び出されるcallSearchService内では、Bing MapsのRESTサービスに対してリクエストを送信し、取得した検索結果を引数にsearchCallback関数を実行するように設定している。

function callSearchService(credentials) {
    var reqUrl = 'http://dev.virtualearth.net/REST/v1/Locations/'
    var data = {
        query: $('#query_text').val(),
        key: credentials,
    }
    $.ajax({
        type: "GET",
        url: reqUrl,
        dataType: "jsonp",
        data: data,
        jsonp: "jsonp",
        success: function (data, dataType) {
            searchCallback(data);
        }
    });
}

 検索結果を引数として実行されるsearchCallback関数は次のようになっている。ここではresp変数に格納される検索結果のデータが正しいか、そして検索結果が1件以上あるかどうかをチェックした後、1番目の検索結果が示すエリアに地図のビューをセットしている。

function searchCallback(resp) {
    if (resp &&
        resp.resourceSets &&
        resp.resourceSets.length > 0 &&
        resp.resourceSets[0].resources &&
        resp.resourceSets[0].resources.length > 0) {

        // 検索結果に該当する範囲がbboxオブジェクトに格納される
        var bbox = resp.resourceSets[0].resources[0].bbox;
        // 地図のビュー範囲を設定するには、Microsoft.Maps.LocationRectオブジェクトを作成して
        // Bing.MapオブジェクトのsetView関数を実行する
        var viewBoundaries = Microsoft.Maps.LocationRect.fromLocations(new Microsoft.Maps.Location(bbox[0], bbox[1]), new Microsoft.Maps.Location(bbox[2], bbox[3]));
        map.setView({ bounds: viewBoundaries});

    } else {
        alert("no result found or error cccured.");
    }
}

地図のクリックを検知する

 地図をクリックした際になんらかのアクションを実行するには、Bing.Mapオブジェクトに対しイベントハンドラを設定すれば良い。今回はdocReady関数内で、以下のようにマウスボタンを押した際に発生する「mousedown」イベントおよびボタンを放す際に発生する「mouseup」イベントに対応するハンドラを設定している。

function docReady() {
  :
  :
    Bing.Events.addHandler(map, 'mousedown', mapOnMouseDown);
    Bing.Events.addHandler(map, 'mouseup', mapOnMouseUp);

 Bing Mapsでは、マウスのドラッグ操作で地図の表示エリアを動かすことができる。そのため、ドラッグ操作には反応せず、クリック操作のみに反応するように処理を記述しなければならない。そこで、、mousedownイベントが発生した際のポインタ位置と、mouseupイベントが発生した際のポインタ位置をチェックし、これが同じであればクリックと見なすことにしている。

 まずmousedownイベントについては、その発生位置のみを記録する。

function mapOnMouseDown(e) {
    mouseDownLocation = new Bing.Point(e.pageX, e.pageY);
}

 mouseupイベントではmousedownイベントハンドラ内で保存した発生位置と、mouseupイベントの発生位置を比較し、同じであれば処理を行うようにしている。

function mapOnMouseUp(e) {
    var pixel = new Bing.Point(e.pageX, e.pageY);
    if (mouseDownLocation != null
        && mouseDownLocation.x == pixel.x
        && mouseDownLocation.y == pixel.y) {
        // マウスクリックに対応する処理を記述する
  :
  :
    }

地図にピンをセットする

 地図にピンをセットするには、ピンをセットする緯度経度情報が必要となる。しかし、前述のmousedownイベントで与えられる位置情報はページ内での位置であるため、これを緯度・経度へ変換する必要がある。これには、Bing MapオブジェクトのtryPixelToLocation関数を使用する。下記では、Bing.Pointオブジェクトから、緯度経度情報を含むBing.Locationオブジェクトへの変換をこの関数を使って行っている。

function mapOnMouseUp(e) {
    var pixel = new Bing.Point(e.pageX, e.pageY);
    if (mouseDownLocation != null
        && mouseDownLocation.x == pixel.x
        && mouseDownLocation.y == pixel.y) {
        var pinIndex = pinsInfo.length + 1;
        var loc = map.tryPixelToLocation(pixel, Microsoft.Maps.PixelReference.page);

 ピンを作成するには、緯度経度を格納したBing.Locationオブジェクトやピンに表示するテキストといった情報を指定してMicrosoft.Maps.Pushpinオブジェクトを作成し、これを引数としてBing.Mapオブジェクトのentities.push関数を実行すれば良い。

        var pushpin = new Microsoft.Maps.Pushpin(loc, {text:String(pinIndex)});
        map.entities.push(pushpin);

 なお、mapOnMouseUp関数内ではピンをセットするだけでなく、その情報を画面下のテーブルに追加したり、ピン間の距離を計算する、といった処理も行っている。これらについてはソースコードを参照していただきたい。

ピンデータをWindows Azureストレージに保存する

 地図の下に表示されている「Publish」ボタンがクリックされた際には、ピン情報を「<サーバー名>/publish/」というURLにPOSTで送信し、公開IDを受け取ってピン付き地図のURLを表示する、という処理を行う。Publishボタンを含むフォームに対してはdocReady関数内でハンドラが登録されており、サブミット時にはdoPublish関数が実行される。

 doPublish関数ではpinsInfo変数に格納しておいたピンの位置情報を整形し、$.post関数を使ってサーバーに送信する処理を行っている。

// Send pins data to publish
function doPublish() {
    var data = {locations: new Array()};
    for (var i = 0; i < pinsInfo.length; i++) {
        loc = pinsInfo[i].getLocation();
        data["locations"].push({
            latitude: loc.latitude,
            longitude: loc.longitude
        });
    }
    $.post("/publish/", data, donePublish, "text");
    return false;
}

 また、POSTに成功した際にはdonePublish関数を呼ぶように設定してある。この関数ではサーバーが返した公開IDからURLを生成して表示する処理を行っている。

function donePublish(data) {
    var result_str = 'route published. url: <a href="/published/' + data + '/">/published/' + data + '</a>';
    $('#publish_result').html(result_str);
    $('#publish_button').attr("disabled", true);
}

newb mapのクライアントサイドスクリプト:published.js

 newb mapでは「<サーバー名>/published.<公開ID>」というURLにアクセスすると、公開IDに対応するピン情報を取得してピン付きの地図を表示する。この処理を記述しているのが、「published.js」ファイル(実体は「/public/javascripts/published.js」ファイル)である。

 published.jsでは、ドキュメントのロード時に実行されるdocReady関数内で/loadpins/へのPOSTリクエストを行い、保存しておいたピン情報を取り出すようにしている。

function docReady() {
    loadMap();
    $('#search_form').submit(doSearch);
    pinsInfo = new Array();
    subDistances = new Array();
    data = {pub_id: pub_id};
    $.post("/loadpins/", data, loadPinsCallback, "json");
}

 ピン情報の取得に成功するとloadPinsCallback関数が実行され、そこでピンの復元処理を行っている。

function loadPinsCallback(data) {
    for (var i = 0; i < data.length; i++) {
        loc = new Bing.Location(data[i]["latitude"], data[i]["longitude"]);
        // 以下、ピンのセット処理などを行う
      :
      :