○○mapを作るアプリを作ってみた！

この記事は、シビックテックをテーマにした、「Civic Tech Advent Calendar 2015」企画の12日目の原稿です。他の記事は
http://qiita.com/advent-calendar/2015/civictech

# この記事を書いた理由
私は[ニフティクラウド mobile backend](http://mb.cloud.nifty.com/)の中の人ですが、今年ハッカソンを通して、多くのCivic Techの作品に使っていただいたので、今年の最後に恩返しのアウトプットとして書きました。
今回はよくcivic techで見かける「○○map」（保育園map、消火栓map）を簡単に作れるアプリを作ってみたのを記事にします！

#使うサービス
[ニフティクラウド mobile backend](http://mb.cloud.nifty.com/)
mobile backend as a Service 略して mBaaS
スマホアプリのサーバー側の機能、プッシュ通知、データベースなどの機能をAPI,SDKを作り込み簡単に導入できるようになっているサービス。位置情報検索といった、データベース上にGPS情報などを保存し、現在地から近いポイントを絞り込んで検索できる機能もある。（今回はJSSDKでこの機能を使う）

[Monaca](https://ja.monaca.io/)
HTML5,JSでハイブリットアプリが作れるツール。JSでコードをカメラや加速度センサ、GPSなどのセンサ情報にもアクセスできるという強力なツール、デバッガーもあり、ビルドなしで実際のアプリの挙動もみれるのが強力。

[OpenStreetMap](https://openstreetmap.jp/)
オープンに使えるマップ、マーカーなんかも描画できる。

#作ったアプリの使用
※以下は全部monacaデバッガーでのスクショ
まずホーム画面で、現在地を中心として地図を表示できます。上野駅でアプリを立ち上げたとすると下のように表示される。
<img width="320" alt="home.png" src="https://qiita-image-store.s3.amazonaws.com/0/55227/d69d6608-d66e-527a-36a4-da1fbca9043a.png">


ポイントを保存するボタンを押すと以下のようになる

<img width="320" alt="input.png" src="https://qiita-image-store.s3.amazonaws.com/0/55227/cc08d52f-5028-b240-1e4d-3e7fa59a9603.png">

ポイントを見るボタンを押すと以下のように周囲（5km以内）の登録されたポイントを見れる

<img width="320" alt="hyouji.png" src="https://qiita-image-store.s3.amazonaws.com/0/55227/4a4cf0f7-854a-9c4c-4b6e-8ce1137f9bde.png">


#各サービスの登録設定及びコードは。。。

・ニフティクラウドmobile backend(mBaaS)の登録、初期設定（アプリケーションキー、クライアントキーの取得）に関しては下記の記事をご確認ください
[mBaaS利用登録](http://qiita.com/fumishitan/items/8abae38db286138f23bf#mbaas%E3%81%AE%E5%88%A9%E7%94%A8%E7%99%BB%E9%8C%B2%E3%82%92%E8%A1%8C%E3%81%86)

・Monacaの登録に関しては下記の記事をご確認ください
[Monaca利用登録](http://qiita.com/fumishitan/items/cb4153a5fca8af1d49a7#monaca%E3%81%AE%E5%88%A9%E7%94%A8%E7%99%BB%E9%8C%B2)
またMonacaに関しては[ここ](https://github.com/NIFTYCloud-mbaas/ncmb_js)で公開されているニフティクラウドmobile backendのJSSDKのncmb.min.jsを下記のように配置してください

![スクリーンショット 2015-12-12 14.22.31.png](https://qiita-image-store.s3.amazonaws.com/0/55227/6801d93d-96c9-a4f2-16ba-2e1aed9ddc02.png)

下記のようにMonacaコンポーネント類を導入して下さい
![スクリーンショット 2015-12-12 14.23.11.png](https://qiita-image-store.s3.amazonaws.com/0/55227/8beedae8-93c3-bda8-854a-ad082d6547d0.png)

・OpenStreetMapに関しては何も設定がいらない！（一番素晴らしい！）

そして,Monaca上のwwwフォルダ直下にindex.htmlを、www>js配下にapp.jsをそれぞれ配置します。その中身は以下になります。

```html:index.html
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <script type="text/javascript" src="js/ncmb.min.js"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <script src="components/loader.js"></script>
    <link rel="stylesheet" href="components/loader.css">
    <link rel="stylesheet" href="css/style.css">
    <script type="text/javascript" src="js/app.js"></script>
    <script type="text/javascript" src="http://www.openlayers.org/api/OpenLayers.js"></script>
</head>
<body>
 <script type="text/javascript">
       navigator.geolocation.getCurrentPosition(onGeoSuccess, onGeoError, geoOption);
</script>

<button onclick="save_geopoint()">ポイントを保存する</button>
<button onclick ="find_geopoint()" style="width:100%;">ポイントを見る</button>
    
<div class="wrapper">
    <div id="canvas" style="width:100%; height:400px"></div>
</div>
</body>
</html>
```

```app.js
//各種設定値記載
var current;
var YOUR_APP_KEY = "登録後アプリ作成した場合に自動で発行されますのでそれを貼り付け";
var YOUR_CLIENT_KEY = "登録後アプリ作成した場合に自動で発行されますのでそれを貼り付け";
var ncmb;
var map;

//ニフティクラウドmobile backendの準備
 $(function(){
    ncmb = new NCMB(YOUR_APP_KEY,YOUR_CLIENT_KEY);
});

//OSMの描画
function writemap(lat,lon) {
    map = new OpenLayers.Map("canvas");
    var mapnik = new OpenLayers.Layer.OSM();
    map.addLayer(mapnik);
    console.log(lat+":"+lon+":");
    var lonLat = new OpenLayers.LonLat(lat,lon)
        .transform(
            new OpenLayers.Projection("EPSG:4326"), 
            new OpenLayers.Projection("EPSG:900913")
        );
    map.setCenter(lonLat, 15);
    var markers = new OpenLayers.Layer.Markers("Markers");
    map.addLayer(markers);
    
    var marker = new OpenLayers.Marker(
    new OpenLayers.LonLat(lat,lon)
        .transform(
            new OpenLayers.Projection("EPSG:4326"), 
            new OpenLayers.Projection("EPSG:900913")
        )
    );
    markers.addMarker(marker);
}

 
//OSMの描画時に位置情報取得に成功した場合のコールバック
var onGeoSuccess = function(position){
    current = new CurrentPoint();    
    current.geopoint = position.coords; //位置情報を保存する
    writemap(current.geopoint.longitude,current.geopoint.latitude);
};

//位置情報取得に失敗した場合のコールバック
var onGeoError = function(error){
    console.log("現在位置を取得できませんでした");
};

//位置情報取得時に設定するオプション
var geoOption = {
    timeout: 6000
};

//現在地を保持するクラスを作成
function CurrentPoint(){
    geopoint=null;  //端末の位置情報を保持する
}

//現在地をポイントとして登録する
 function save_geopoint(){
     navigator.geolocation.getCurrentPosition(onSaveSuccess, onGeoError, geoOption);
     console.log("save_geopoint");
}

//ポイントの登録時に位置情報取得に成功した場合のコールバック
var onSaveSuccess = function(location){
        navigator.notification.prompt(
            ' ',  // メッセージ
            onPrompt,                  // 呼び出すコールバック
            'ポンイントの登録',            // タイトル
            ['登録','やめる'],             // ボタンのラベル名
            'ポイント名'                 // デフォルトのテキスト
        );
        
        function onPrompt(results) {
            current.geopoint = location.coords; 
            var geoPoint = new ncmb.GeoPoint(location.coords.latitude, location.coords.longitude);
            console.log(location.coords.latitude + ":" + location.coords.longitude);
            var Places = ncmb.DataStore("PlacePoints");
            var point = new Places();
            point.set("name",results.input1);
            point.set("geo", geoPoint);
        
            point.save()
            .then(function(){})
            .catch(function(err){// エラー処理
            });
        }
        
    };

//登録されたポイントを引き出し地図上に表示する
function find_geopoint(){
    navigator.geolocation.getCurrentPosition(onFindSuccess, onGeoError, geoOption);
    console.log("find_geopoint");
}
    
//登録ポイントの表示時に位置情報取得に成功した場合のコールバック
var onFindSuccess = function(location){
        current.geopoint = location.coords; 
        var geoPoint = new ncmb.GeoPoint(location.coords.latitude, location.coords.longitude);
        console.log("findpoints:"+location.coords.latitude + ":" + location.coords.longitude);
        var PlacePointsClass = ncmb.DataStore("PlacePoints");
        //ニフティクラウド mobile backendにアクセスして検索開始位置を指定
        PlacePointsClass.withinKilometers("geo", geoPoint, 5)
                        .fetchAll()
                        .then(function(results){
                            var data = [];
                            for (var i = 0; i < results.length; i++) {
                                var result = results[i];
                                var markers = new OpenLayers.Layer.Markers("Markers");
                                map.addLayer(markers);
                                var regist_location = result.get("geo");
                                var marker = new OpenLayers.Marker(
                                    new OpenLayers.LonLat(regist_location.longitude,regist_location.latitude)
                                                .transform(
                                                new OpenLayers.Projection("EPSG:4326"), 
                                                new OpenLayers.Projection("EPSG:900913")
                                            )
                                );
                                markers.addMarker(marker);
                            }
                        });
        
    };
    
```

これでアプリはできました。まさに手でオープンデータのDBを作れるアプリ、本当に便利かは置いておいて、みんなで○○Mapを作る場合には重宝しそうです。明日は実際にこのアプリを使った○○mapを作った話を書きます。