NCMBにはいくつかの機能がありますが、アプリと親和性の高い機能としてはプッシュ通知と位置情報機能が挙げられます。デバイスから位置情報を取得し、それをマッピングしたり、自分の今いる場所に近い情報を得たりする際にも位置情報検索が利用できます。
今回はMonacaとNCMB、さらにMapboxや国土地理院APIを使って地図メモアプリを作ります。前回は地図の表示とデータ登録までを作成しましたので、今回はデータの検索による一覧表示と、詳細表示までを行います。
一覧表示について
データの一覧表示は www/pages/list.html
にて行います。HTMLはulタグがある程度です。
<template> <div class="page"> <div class="navbar"> <div class="navbar-bg"></div> <div class="navbar-inner sliding"> <div class="title">メモ一覧</div> </div> </div> <div class="page-content"> <div class="list media-list"> <ul id="memos"> </ul> </div> </div> </div> </template>
JavaScriptについて
タブが表示されたタイミングで、データを取得して一覧表示します。この時、位置情報はストアから取得します。
export default async function (props, {$f7, $f7router, $on, $store }) { // タブが表示された際に実行されるイベント $on('page:tabshow', async function(e, page) { // ストア(共通変数)から位置情報を取得 const { longitude, latitude } = $store.state.coords; // 位置情報に基づいてメモを取得 const ary = await getAllMemo({ longitude, latitude }); // メモを表示 showMemo(ary, { longitude, latitude }); }); }
getAllMemo
は次のようになります。 withinKilometers
を使って、ある位置情報を中心に5km以内のデータを取得します。
// NCMBのデータストアから付近のメモデータを取得する関数 const getAllMemo = ({ longitude, latitude }) => { // メモクラス(DBでいうテーブル相当) const Memo = ncmb.DataStore('Memo'); // 位置情報オブジェクトを作成 const geo = new ncmb.GeoPoint(latitude, longitude); // 5キロ圏内のメモを検索 return Memo .withinKilometers('geo', geo, 5) .fetchAll(); }
データが返ってきたら、showMemoを使ってデータの描画を行います。この時使っている distance
関数は2つの位置情報の距離をメートルで返すものです。緯度経度から2地点間の距離 (km) を計算する JavaScript - Qiitaで紹介されているものをメートルに変更しています。関数は js/app.js
に定義しています。
// メモを一覧表示する const showMemo = (ary, { longitude, latitude }) => { $f7.$el.find('#memos').html(ary.map(memo => ` <li> <a href="#" class="item-link item-content" data-object-id="${memo.objectId}"> <div class="item-inner"> <div class="item-title-row"> <div class="item-title">${memo.address}</div> <div class="item-after">${distance(memo.geo.latitude, memo.geo.longitude, latitude, longitude)}m</div> </div> <div class="item-text">${memo.body}</div> </div> </a> </li> `) .join('')); // 後述 } // 2点間の距離を求める(メートルで返す) const R = Math.PI / 180; const distance = (lat1, lng1, lat2, lng2) => { lat1 *= R; lng1 *= R; lat2 *= R; lng2 *= R; return parseInt(6371 * Math.acos(Math.cos(lat1) * Math.cos(lat2) * Math.cos(lng2 - lng1) + Math.sin(lat1) * Math.sin(lat2)) * 1000); }
HTMLを出力した後、そのままタップイベントのバインドを行っています。ユニークキーであるobjectIdを取得してメモを特定し、地図のタブに移動します。この時、タブ切り替えではデータを渡せないので、ストアを使っています。
// 一覧表示したリストに対してタップイベントを追加 $f7.$el.find('#memos a').on('click', e => { // タップしたデータのキー(objectId)を取得 const objectId = $(e.target).parents('a').data('object-id'); // 対象になるメモデータを取得 const memo = ary.filter(m => m.objectId === objectId)[0]; // ストア(共通変数)に入れる $store.dispatch('setMemo', memo ); // 地図のタブを表示 app.tab.show('#view-home') }); }
地図画面でのメモ表示
一覧画面では、タブ表示のイベントを使ってメモがあるかどうかを確認します。もしあれば、そのメモデータを地図の中央にポップアップで表示します。
// この画面が表示された時のイベント $on('page:tabshow', async function(e, page) { // 一覧画面からメモが送られてきているかチェック const { memo } = $store.state; // なければ終わり if (!memo) return; // メモの位置情報を取得 const coords = [memo.geo.longitude, memo.geo.latitude]; // 位置情報を地図の中心に、かつズームをセット map.setCenter(coords); map.setZoom(14); // メモした内容でポップアップを作成 new mapboxgl.Popup() .setLngLat(coords) .setHTML(`<h3>${memo.body}</h3>`) .setMaxWidth('300px') .addTo(map); // メモはストア(共通変数)から削除 $store.dispatch('setMemo', null); });
これでメモ一覧画面から地図上でのポップアップ表示までが完成となります。
コード
今回のコードはNCMBMania/Monaca_MapMemo: Monacaを使った地図メモアプリですにアップロードしてあります。実装時の参考にしてください。
まとめ
今回は以下のサービスを利用して地図メモアプリを開発しました。
また、NCMBのデータストアで、次の機能を利用しました。
- データストアへの保存
- データストアの位置情報を使った検索
NCMBでは他にもファイルストア(ファイルストレージ)、認証、プッシュ通知など、皆さんのアプリ開発をサポートする機能を数多く提供しています。ぜひ、そちらも使ってみてください。