連載
» 2011年05月25日 00時00分 公開

クラウドとgaedirectでできる緊急対応マッシュアップ(3):動画とGoogle Maps APIで作る「津波、不忘の記録」 (2/3)

[清野克行,有限会社サイバースペース]

地図・動画情報管理におけるgaedirectの使い方

 リスト1は今回のサンプルでの地図・動画情報管理の部分です。

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8"/> 
<title>Google Maps API</title>    
<script type="text/javascript" src="/jslib/gaedirect.js"></script>
<script type="text/javascript" src="/jslib/jquery-1.5.min.js"></script>
<script 
  src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAA7BH7CggsNmHOlKjr9pP9WBQQHituv_dQvmyzddsqjI99D3nK1hTA4etykWuI0c0HB0eZzw_Lo60aZg"
  type="text/javascript"></script>
<script type="text/javascript">
$(function(){
    var query = ginit();    //(1)
    query["kind"] = "gmaps";    //(2)
    query["key"] = "none";    //(3)
    query["id"] = "area,lon,lat,comment,type";    //(4)
    var tags = "";
    var lon = 0.0, lat = 0.0, comment = "", type = "";
    var kind = "gmaps";
    var props1 ="pref,area,do:lon,do:lat,comment,type";    //(4)
    var props2 ="pref,area,lon,lat,comment,type";
    var propsa = props2.split(",");
    // データ登録
    $("#add").click(function(){
        var key = $("#key").val();
        $.post(gae(), add(kind, key, props1), function(res){
            $("#stat").html(res);
        });
    });
    // データ参照
    $("#rev").click(function(){
        var key = $("#key").val();
        $.get(gae(),rev(kind, key, props2),function(res){
            if ((res).substr(0, 3) != "NO:") {
                var dat= res.split("<p>");
                for (var i = 0; i < props2.length; i++){
                    $("#"+propsa[i]).val(dat[i]);
                }
            }else{
                $("#stat").html(res.substr(3));
            }
        });
    });    
    // データ更新
    $("#upd").click(function(){    
        var key = $("#key").val();
        $.post(gae(), upd(kind, key, props1),function(res){
            $("#stat").html(res);     
        });
    });    
    // クリア
    $("#clr").click(function(){    
        $.each(["key","pref","area","lon","lat","comment"], function(){
            $("#" + this).val("");
          });
      $("#stat").text("");
      $("#key").focus();
    });
    // 地図表示
    $("#revmap").click(function(){    //(5)
         $.get(gae(), query, function(res){    //(6)
              if ((res).substr(0, 3) != "NO:") {    //(7)
                    var map = new GMap2(document.getElementById("map"));    //(A)
                    map.setCenter(new GLatLng(38.688215, 140.8693558), 8);    //(B)
                    map.addControl(new GLargeMapControl());    //(C)
                      map.addControl(new GMapTypeControl());    //(D)
                    var pname = new Array();
                    var ents = res.split("<e>");    //(8)
                    for (var i = 0; i < ents.length; i++) {       //(9)
                         area = ents[i].split("<p>")[1];    //(10)
                         lon = ents[i].split("<p>")[2];       //(10)
                         lat = ents[i].split("<p>")[3];       //(10)
                         comment = ents[i].split("<p>")[4];    //(10)
                        map.addOverlay(setMarker(lat, lon , comment));    //(E)
                    }
                }else{
                    $("#stat").html(res.substr(3));
                }
         });    
});
 
//   条件検索のコード
    function setMarker(lat,lon, msg){
        var marker = new google.maps.Marker(new google.maps.LatLng(lat, lon));    //(F)
        google.maps.Event.addListener(marker, "click", function() {    //(G)
            marker.openInfoWindowHtml(msg);    //(H)
        });
        return marker;
    }
});    
</script>
</head>
<body>
<h1 style="color: #aa0022">津波、不忘の記録</h1>
<h2>2011年3月11日</h2>
<p>
    <h3>◆動画情報管理◆</h3>    
    <input type="button" id="add" value=" 登録 "/>
    <input type="button" id="rev" value=" 参照 "/>
    <input type="button" id="upd" value=" 更新 "/>
    <input type="button" id="clr" value=" クリア "/>
    ステータス<div id="stat"></div>
    キー:<input type="text" id="key" size="10"/><br/>
    都県:<input type="text" id="pref" />
    地域:<input type="text" id="area" />
    lon(経度):<input type="text" id="lon" size="16" />
    lat(緯度):<input type="text" id="lat" size="16" /><br/>
    コメント:<br/>
    <textarea id="comment" rows="10" cols="110" wrap="hard"></textarea><br/>
</p>    
<p>
    <ul id="out" type="square"></ul> 
    <h3>◆地図情報表示◆</h3>    
    マーカクリックで吹き出しを表示する
    <input type="button" id="revmap" value="地図表示"/>
    <div id="map" style="width:580px; height:1100px"></div>
</p>
</body>
</html>
リスト1

gaedirectでの登録・参照・更新

 gaedirectでの登録・参照・更新処理については、もう何度も紹介しているので説明の必要はほとんどないと思います。

 ただし今回は緯度、経度をdouble型(8bytes浮動小数点型)にしているため、(1)の登録と更新で使用されるプロパティリストでは「do」を指定しています。

 Google Mapsの表示ではgaedirectによる分散KVSのデータ参照と、Google Maps APIでの地図表示処理の2つが組み合わさっているので、それぞれの処理を分けて見ていきます。

gaedirectで全件参照する場合の条件検索の仕方

 今回はgaedirectの条件検索についても紹介することになっていますが、その最初として、このサンプルでは全件検索が使用されています。

 サンプルの「地図表示」ボタンをクリックすると、(5)で匿名関数が起動され、次の(6)ではgaedirectモードの$.getでサーバへの参照リクエストを行います。

 ただし、ここでの参照では、これまでのキーを使用したケースとは異なり、第2引数はjQuery標準の連想配列として「query」を使用しています。このqueryに対する値設定は、リスト上部の(1)から行います。次ページで詳細を解説しますが、条件検索では基本的に、次のパターンで連想配列の値を設定します。

  1. (1)のように、ginit()でのjQueryの初期化を最初に行う
  2. (2)のように、kind名として「gmaps」を指定
  3. キー値は(3)のように「none」を指定(条件検索では、この例のようにキー値指定は全て「none」となる)
  4. (4)のように、条件検索で参照するプロパティ項目を指定(全てのプロパティ項目を参照する場合は「*」を指定し、「query["id"] = "*";」とすることもできる)

 これで全件参照の場合の連想配列のセッティングは終わります。後は、(6)で参照リクエストを実行し、サーバ側での参照処理が正常に行われた場合は、(7)のif文判断が成立して、地図・マーカなどの表示処理に移ります。この部分ではGoogle Maps APIでの描画処理を行いますが、それについては、この後解説します。

 その前に、gaedirectでの処理を見てくと、(8)でサーバからの受信データを「<e>」(エンティティ区切り)で文字列分割して配列「ents」にエンティティごとにセットし、(9)のfor文で、エンティティごとのプロパティ値を対応する変数に、それぞれ(10)でセットしています。

 以上がgaedirectでの処理ですが、この処理を基にGoogle Maps(以後、GMaps)APIでの描画処理を行います。

Google Maps APIでの地図表示の基本

 最初にGMaps APIで地図表示を行うためには、グーグルが発行するキーを取得する必要があります。これはGoogleのクラウド上でも同様でリスト1の9行目のように<script>タグでkey値を指定してGMaps APIのライブラリ、定数などを読み込みます。

初期化処理

 (A)のGMaps2は地図表示用のJavaScriptクラスで、描画処理の最初にnew演算子インスタンス「map」を生成します。引数では、地図を描画するコンテナをノードオブジェクトのID値で指定しますが、ここでは幅が580px、高さが1100pxという、かなり大きなサイズにしています。これは、地図上に主要市町名が表示されるスケールを選択した結果です。

 この後は、生成したインスタンス「map」のメソッドを使用した処理になっていきます。

地図中心の緯度、経度とズームサイズを指定

 (B)では、.setCenterで地図中心の緯度、経度とズームサイズ(ここでは「8」)を指定しています。地図中心は東北・北関東の太平洋沿岸を表示しやすい位置を指定しています。

コントロールを地図に追加

 (C)では、addControlで地図の移動とズームレベルを操作するためのコントロールを地図に追加しますが、GLargeMapControl()のインスタンスを引数に指定すると、図6の大型のコントロールが追加されます。

図6 大型のコントロール 図6 大型のコントロール

 (D)では、同様にGMapTypeControl()のインスタンスを指定しています。これによって図7のマップタイプ選択用のコントロールが追加され、地図(Map)、衛星写真(Satellite)、およびこの2つの組み合わせ(Hybrid)で地図を表示できます。

図7 マップタイプ選択用のコントロール 図7 マップタイプ選択用のコントロール

 ここで、図7のSatelliteまたはHybridを選択して地図表示のズームレベルを上げていくと、沿岸地域の衛星写真は全て津波被災後のものになっています。このことはご存じの方も多いと思います。

マーカの表示

 この後はgaedirectでの処理が少しあり、マーカの表示処理に移ります。

 GMapsには地図上のポイントを示すマーカ用のアイコンが用意されており、(E)では、この標準アイコンを使用してマーカを表示しています。マーカ表示にはaddOverlayを使用しますが、引数のsetMarker指定で標準マーカが使用されます。setMarkerの引数は、その下に定義されている、setMarker関数を呼び出す形になっています。マーカが1つだけの場合は、このような関数呼び出し形式にする必要はありません。

 setMarker関数では(F)のgoogle.maps.Markerでマーカを表示しますが、引数にはLatLngで生成した緯度、経度を指定します。

吹き出しの表示

 それぞれのマーカは、マウスでクリックすると、吹き出しを表示します。この設定は(G)と(H)で行われています。(G)のリスナ設定がGMaps特有の設定ですが、(F)で設定されたマーカのクリックイベントで(H)のopenInfoWindowHtmlメソッドが、表示データ「msg」を引数にとって実行され、吹き出しを表示します。

次ページからは話の内容を変えて、gaedirectでの条件検索機能を見ていきます。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。