NCMBにはいくつかの機能がありますが、データベースのように使えるデータストアや写真などを保存しておくファイルストアはよく使われる機能になります。
今回はそのデータストアとファイルストアを組み合わせて、マンガビューワーアプリアプリを作ります。まず初回となる今回は、アプリの概要とNCMBの初期化を行います。
完成版のコード
作成したデモアプリのコードはNCMBMania/Monaca_Comic: MonacaとNCMBを使ったマンガアプリのサンプルですにアップロードしてあります。実装時の参考にしてください。
ベースについて
今回はMonacaを利用し、UIフレームワークとしてFramework7を用いています。その際のベースとしてNCMBMania/MonacaFramework7Base: Monaca × Framework7 × NCMBのベースアプリです。を利用しています。執筆時点でのFramework7のバージョンは7.0.2です。
このベースアプリにFramework7のUI部分(NCMB部分除く)を実装したハンズオンテンプレートが下記になります。まず、これをダウンロードして、Monaca IDEにてアップロードします。
NCMBMania/Monaca_Comic_Handson: Monacaを使ったマンガアプリのハンズオンデータです
画面について
今回のアプリは以下の2つの画面を持っています。
- 書籍一覧画面
- 書籍閲覧画面
書籍一覧画面
pages/list.html
として作成します。データストアから書籍データを取得し、一覧表示します。
書籍閲覧画面
pages/view.html
として作成します。一覧画面で選択された書籍の画像データを取得し、マンガビューワーで表示します。
利用するライブラリ
今回は以下のライブラリ・SDKを利用しています。
- NCMB SDK
- laymic
- Framework7
NCMB SDKとFramework7は上記ベースアプリに元々含まれています。laymicはWebベースのマンガビューワーになります。
laymicのインストール(実装済み)
laymicをGitHubのリポジトリからダウンロードし、distの中身を www/assets/laymic
以下に保存します。そして www/index.html
にて読み込みます。
<!-- 記述済み -->
<link rel="stylesheet" href="assets/laymic/laymic.min.css">
<script src="assets/laymic/laymic.iife.min.js"></script>
ルーティングの設定(実装済み)
今回の2画面に合わせてルーティングを変更します。 js/routes.js
を以下のように修正します。
// 記述済み
const routes = [
{
path: '/',
url: './index.html',
},
// コミック一覧画面
{
path: '/comics/',
componentUrl: './pages/list.html',
},
// コミック詳細画面
{
path: '/comics/:key',
componentUrl: './pages/view.html',
},
{
path: '(.*)',
url: './pages/404.html',
},
];
index.htmlの修正
index.htmlでは初期表示でコミック一覧画面を読み込むように修正します。まだ pages/list.html
はないので、画面が真っ白になってしまいます。
<!-- 記述済み -->
<div id="app">
<div class="views tabs safe-areas">
<div id="view-home" class="view view-main view-init" data-url="/comics/">
</div>
</div>
</div>
</div>
NCMB SDKの初期化
NCMBのWebサイトでアプリを作成し、アプリケーションキーとクライアントキーを取得します。そして www/js/config.json
を開いてそれぞれのキーを記述します。
{
"applicationKey": "ここにアプリケーションキー",
"clientKey": "ここにクライアントキー"
}
この config.json
は js/app.js
にて読み込まれ、NCMBを初期化処理に利用されます。
// 記述済み
// NCMBの初期化用
const event = window.cordova ? 'deviceready' : 'DOMContentLoaded';
document.addEventListener(event, async (e) => {
const config = await (await fetch('./js/config.json')).json();
window.ncmb = new NCMB(config.applicationKey, config.clientKey);
window.app = new Framework7({
name: 'My App', // App name
theme: 'auto', // Automatic theme detection
el: '#app', // App root element
// App store
store: store,
// App routes
routes: routes,
});
});
これでNCMBが初期化され、利用準備が整いました。
データの用意
マンガデータ
今回はCCなどで公開されている以下のマンガデータを利用しました。ありがとうございます。
これらのデータをダウンロードし(一部はPDFから画像にした上で)、ページ毎に連番で保存します。たとえばブラックジャックによろしくであれば、bj_1.jpeg・bj_2.jpeg…といった具合です。
そうしたデータをまとめてNCMBのファイルストアにアップロードします。
※ ハンズオン用に画像データを以下にアップロードしてあります。ダウンロード、展開してください。
データストア
次にデータストアでComicクラスを作成します。フィールドは次のように作成します。
フィールド名 | 型 | 意味 |
---|---|---|
title | 文字列 | マンガのタイトル |
key | 文字列 | 画像ファイル名のプリフィックス(bj_など) |
そしてマンガデータを作成します。
以下は例です。
title | key |
---|---|
ブラックジャックによろしく | bj_ |
ダーウィン事変 | darwinsincident_ |
聖☆おにいさん | sym001_p01 |
一覧画面の作成
www/pages/list.html
を作成します。HTMLを含めた基本形は次の通りです。
<!-- 記述済み -->
<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 links-list">
</div>
</div>
</div>
</template>
<script>
export default (props, { $onMounted, $update }) => {
// ここにJavaScriptを記述
return $render;
};
</script>
書籍データを取得する
JavaScriptで書籍データを取得する処理を記述します。これは $onMounted
関数内で記述します。この関数はDOMのマウントが終わった際に呼ばれます。
// 要記述
let comics = [];
// DOMがマウントされたタイミングで実行
$onMounted(async () => {
// 1. コミックデータを取得する
const Comic = ncmb.DataStore('Comic');
comics = await Comic
.order('title')
.fetchAll();
// 取得したら表示更新
$update();
});
変数 comics
の中にデータが入った段階で $update
関数を呼ぶことで、HTML側に表示を反映できます。 div.list
の中に一覧表示を追加します。
<!-- 記述済み -->
<div class="list links-list">
<!-- ここに追加(ここから) -->
<ul>
${ comics.map(comic => $h`
<li><a href="/comics/${comic.key}?title=${comic.title}">${comic.title}</a></li>
`)}
</ul>
<!-- ここに追加(ここまで) -->
</div>
これでデータの取得と、画面への反映が完了します。
ビューワー画面の実装
www/pages/view.html
を作成します。HTMLを含めた基本形は次の通りです。
<!-- 記述済み -->
<template>
<div class="page">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner sliding">
<div class="left">
<a href="#" class="link back">
<i class="icon icon-back"></i>
<span class="if-not-md">戻る</span>
</a>
</div>
<div class="title">${ title }</div>
</div>
</div>
<div class="page-content">
<div class="laymic" data-viewer-id="laymic">
</div>
</div>
</div>
</template>
<script>
export default (props, { $f7route, $on, $f7router, $update, $tick }) => {
// ここにJavaScriptを記述
return $render;
};
</script>
変数を準備
まず画面で表示するための変数を準備します。基本的に一覧画面から送られてきた変数を受け取るだけです。
// 記述済み
const { key } = props; // 検索キー
const { title } = $f7route.query; // 画面表示用のマンガタイトル
let pages = []; // マンガ画像が入る配列
画面表示処理
画面表示時のイベントでは、以下の処理を行います。
- ローディングアイコンの表示
- ファイルストアからの画像取得
- マンガビューワーの立ち上げ
- ローディングアイコンの非表示
コードで書くと、次のようになります。
// 記述済み
// 画面を表示する前に実行されるイベント
$on('page:beforein', async () => {
// ローディング表示
app.preloader.show();
// ファイルストアのデータを取得
const blobs = await getPage();
// ファイルストアのデータをblob形式に変換
pages = blobs.map(p => URL.createObjectURL(p));
// 表示更新
$update();
// 描画完了を待つ
await $tick();
showLaymic();
// ローディングを消す
app.preloader.hide();
});
ファイルストアからの画像取得
ファイルストアからは、先ほどの key
を使って取得対象の画像を絞り込みます。また、ファイル名ごとに並べることでページ番号順に取得しています。
ファイルストアを検索しただけではデータのダウンロードまでは行っていませんので、さらに ncmb.File.download
を使ってダウンロード処理も行っています。
// 要記述
// ファイルストアからデータを取得する関数
const getPage = async () => {
// 1. ファイル名のキーで検索
const files = await ncmb.File
.regularExpressionTo('fileName', `^${key}.*`)
.order('fileName', false)
.fetchAll();
// 2. 写真データをblob形式でダウンロード
const promises = files.map(f => ncmb.File.download(f.fileName, 'blob'));
// Promiseで処理を返す
return Promise.all(promises);
};
マンガビューワーの立ち上げ
マンガビューワーlaymicの立ち上げ処理は次のようになります。注意点としては、Framework7の画面が邪魔をしてビューワーが後ろに開いてしまうことです。そのため、今回はlaymicが開いた段階で一旦Framework7全体を非表示にし、laymicを閉じた段階で表示を戻すと言ったことを行っています。
// 記述済み
// 電子書籍を表示する処理
const showLaymic = () => {
// Laymicの表示
const applicator = new laymic.LaymicApplicator(".laymic", {
pageWidth: 690,
pageHeight: 976,
});
applicator.open('laymic');
// Framework7自体を一旦隠す
app.el.style.display = 'none';
// 電子書籍を閉じる際にFramework7を表示する
$('.laymic_close').on('click', e => {
app.el.style.display = 'block';
// 一覧ページに戻る
$f7router.back();
});
}
画面描画内容
pages
変数にはblob:ではじまるURLが配列になっています。これを画面上に表示します。
<!-- 記述済み -->
<div class="laymic" data-viewer-id="laymic">
<!-- 追記(ここから)-->
${ pages.map(page => $h`
<img data-src="${page}" />
`)}
<!-- 追記(ここまで)-->
</div>
さらに標準のCSP(Content-Security-Policy)ではblobが使えないので www/index.html
を修正します。
<!-- 記述済み -->
<meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: gap: content: blob:"> <!-- 最後に blob: を追加-->
これでマンガビューワーが立ち上がるでしょう。