ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

Monacaと地図を組み合わせた足跡アプリを作ってみよう

MonacaとmBaaSを使ってアプリを作ってみたいと思います。今回は、

  • OpenStreetMap
  • Monaca
  • ニフティクラウド mobile backend

を組み合わせて、地図上にマーカーを立てて、それを記録しておける「足跡アプリ」を作ってみたいと思います。

必要なもの

  • Mapboxのアカウント(無料)
  • Monacaのアカウント(無料)
  • ニフティクラウド mobile backendのアカウント(無料)

MapboxはOpenStreetMapを使うために必要なサービスです。無料でアカウントの作成とプロジェクト作成ができます。利用量によっては有料になるサービスです。Googleマップとの違いとしては、自分独自のコンテンツを追加してオリジナルの地図を作ったり、公開できるのが特徴となっています。

Monacaでプロジェクトを作成する

今回は最小限のテンプレートを選択してはじめます。名前は地図アプリとします(任意です)。

プロジェクトができあがったら、Monacaの設定メニュー>JS/CSSコンポーネントの追加と削除を選択します。そして、ncmbとleafletという2つのライブラリを追加してください。LeafletというのはMapboxプロジェクトを手軽に扱えるようにしてくれるライブラリです。

コンポーネントを追加したら、index.htmlを次のように修正します。修正内容は以下の通りです。

  1. JavaScriptファイルjs/ncmbController.jsの読み込み追加(ファイルはこの後作成します)
  2. 地図を表示するdivタグ追加
  3. 位置情報を追加するためのdivタグ追加
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <meta http-equiv="Content-Security-Policy" content="default-src *; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
    <script src="components/loader.js"></script>
    <link rel="stylesheet" href="components/loader.css">
    <link rel="stylesheet" href="css/style.css">
    <script src="js/ncmbController.js"></script>
</head>
<body>
    <div id="map"></div>
  <div class="add_button" id="add_button">+</div>
</body>
</html>

そしてjs/ncmbController.jsを作成し、内容を次のようにします。ニフティクラウド mobile backendのアプリケーションキーとクライアントキーは取得済みとして、それぞれ読み替えてください(YOUR_APPLICATION_KEYとYOUR_CLIENT_KEYになります)。この処理ではDOMの読み込み完了時のイベントとして ncmbController.init(); を実行しています。

var application_key = "YOUR_APPLICATION_KEY";
var client_key = "YOUR_CLIENT_KEY";

var ncmbController = {
    init: function() {
        var ncmb = new NCMB(application_key, client_key);
    }
};

document.addEventListener("DOMContentLoaded", function(event) { 
  ncmbController.init();
});

最後にスタイルシートの編集をします。 css/style.css を次のように編集します。地図をスマートフォンの画面全体に表示し、ボタン(add_button)のデザインを行っています。

body {
    padding: 0;
    margin: 0;
  position: relative;
}
html, body, #map {
  height: 100%;
}

.add_button {
  position: absolute;
  right: 10%;
  bottom: 10%;
  font-size: 2em;
  border-radius: 1.5em;    
  border: 1px solid blue;
  background-color: blue;
  color: white;
  width: 1.2em;
  text-align: center;
}

現在位置を地図の中央に設定する

まず最初に地図を表示します。js/ncmbController.jsを編集します。先ほどのinit処理を次のように編集します。Mapboxにてプロジェクトを作成すると、トークンとプロジェクトIDが取得できます。下記コードのMAPBOX_TOKENとMAPBOX_PROJECT_IDをそれぞれ読み替えてください。

init: function() {
    var ncmb = new NCMB(application_key, client_key);
    var token = 'MAPBOX_TOKEN';
    navigator.geolocation.getCurrentPosition(function(location) {
        var map = L.map('map').setView([location.coords.latitude, location.coords.longitude], 15);
        L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token='+token, {
            attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
            maxZoom: 18,
            id: 'MAPBOX_PROJECT_ID',
            accessToken: token
        }).addTo(map);
    });

navigator.geolocation.getCurrentPosition はHTML5の機能を使った現在位置の取得処理です。ブラウザから許可を求めるアラートが出ますので、OKを押すと次の処理に進みます。この時、位置情報が取得できますので、

var map = L.map('map').setView([location.coords.latitude, location.coords.longitude], 15);

として地図オブジェクトを生成します。後はレイヤーとしてOpenStreetMapのデータを適用します。これで現在位置を中心として、地図がスマートフォンの画面全体に表示されるようになります。

追加ボタンを押した時のアクションを作る

次に追加(+)ボタンをタップした時のイベントを作ります。同じくncmbController.initの中で作っていきます。

var button = document.getElementById("add_button");
button.addEventListener("click", function(event) {
    var place = prompt("場所の名前を入力してください");
    navigator.geolocation.getCurrentPosition(function(location) {
      var geoPoint = new ncmb.GeoPoint(location.coords.latitude, location.coords.longitude);
      var point = new Places();
      point.set("areaName", place);
      point.set("point", geoPoint);
        point.save().then(function() {
        })
        .catch(function(err) {
            alert("エラーが発生しました。再度行ってください") 
        });
    });
});

add_buttonのクリックイベントとして設定します。最初に場所の名前を求めています。そして位置情報を更新し、その場所をmBaaSに保存します。注意点としては、位置情報をそのままテキストで保存するのではなく、

var geoPoint = new ncmb.GeoPoint(location.coords.latitude, location.coords.longitude);
var point = new Places();
point.set("point", geoPoint);

として、 ncmb.GeoPoint オブジェクトを使っている点です。これによりデータが位置情報オブジェクトとして保存されるようになります。今回は保存処理がうまくいった場合は何も通知などはせず、エラーがあった場合のみアラートを出しています。

保存した位置情報を一覧表示する

最後にデータストアに保存した位置情報を表示する処理を書きます。これは地図を初期化したタイミングで行います。

var current_position = new ncmb.GeoPoint(location.coords.latitude, location.coords.longitude);
Places
.withinKilometers("point", current_position, 1000)
.limit(20)
.fetchAll()
.then(function(places) {
    for (var i = 0; i < places.length; i++) {
        var place = places[i];
        var marker = L.marker([place.point.latitude, place.point.longitude]).addTo(map)
        .bindPopup("<h1>"+place.areaName+"</h1>")
        .on('click', function(event) {
            this.openPopup();
        });
    }
});

位置情報を使った検索の場合でも、まず ncmb.GeoPoint を生成します。そしてデータストアのPlacesクラスに対して、 .withinKilometers("point", current_position, 1000) を実行しています。これは検索対象のフィールド、位置情報、そして距離(今回は1,000km)にあるデータを検索するという意味になります。取り出すデータは20件のみとしていします。

後は取得できたデータをLeafletを使って地図の上にマッピングするだけです。データを取り出す際にはフィールド名+latitude(緯度)とlongitude(経度)と指定します。

試してみる

実際に試してみると、最初に地図が表示されます。そしてプラスをタップするとアラートが出ますので、場所の名前を入力します。

保存したタイミングでは何もしませんので再読み込みすると、地図上にマーカーが表示されます。

マーカーをタップすると先ほど指定した場所の名前が出るはずです。


今回のコードはNCMBMania/ashiato_mapにアップロードしてあります。ぜひ参考にしてみてください。

このようにmBaaSを使うことで簡単に地図と連携したアプリが作れるようになります。他の友人とマーカーを共有したり、マーカーを立てたところにコメントを書いたりと言った応用もできるのではないでしょうか。