お詫び
アドベントカレンダーの記事と同時にリリースする予定で作成していましたが、
バックエンドで使用するAPIのproduction Licence
が間に合わず、リリースできませんでした...
来月くらいにリリースする予定ですので、もしご興味を持っていただけたならば、ストックをお願いします。
(記事の更新で通知させていただきます。)
作ったもの(というか作っているもの)
"Digest-of-Life"
人生を要約するサービスを作ってます。
提供するものは、大切にしたい言葉を、きれいな画像とともに保存するサービスです。
こっそり記録していってもいいし、その場で画像に合成して共有してもいい
文字を画像にしたいとき、きれいな画像で言葉をドーンと伝えたいとき等にご利用ください。
動機(なぜ作ろうと思ったか)
伊坂幸太郎著「モダンタイムス」の作中のセリフですが、昔読んでからずーっと頭の片隅に残ってまして、、、
でも、個人的には哲学は人生の要約だと信じているので、それを形にできたらなと思い、
今回、個人の哲学を記録するサービスを作るに至りました。
アプリケーション構成
ほぼすべてFirebaseで作成しました。
API
もデータベース
もログイン機能
もjavascript
ちょこっと書くだけで実装できるFirebase
先生素晴らしい!
ホスティングサービス: Firebase Hosting
- これがないとWebサービスが動かない。
- ローカルのエミュレータで動作確認したあと、コマンド1つでデプロイできる。
API: Firebase Functions
- 面倒なサーバーサイドのAPIを
javascript
で数行書いてデプロイするだけで動く。 - 今回は、
Unsplush api
のapi key
を秘匿するために使用。
データベース: Firebase Realtime Database
- メソッド1つ書くだけで、clientからDBにCRUDできる。すごい。。。
- 今回は、ユーザーが保存した言葉や写真のデータを永続化するために使用。
ユーザー管理: Google アカウント
-
Firebase
側にGoogle ログインをアプリに統合
する機能が用意されていたので。 - ユーザーを管理せずに、ユーザーを識別できるって素晴らしい。
画像サービス: Unsplush api
- 今回の目玉、めちゃきれいな画像が大量にあるサイトのAPI
- APIを利用すると、細かい検索機能が使える。
- 普通の
developアカウント
だと50requests/hour
、ガイドラインに沿ってることを示せれば、Production版
のapi key
がもらえる
要素技術
使用した技術要素と検証に使ったサンプルコードを書きます。
vuetify
なるべくCSS書かないマン
- https://vuetifyjs.com/ja/
-
<v-XXXX>
のような独自のコンポーネントを使用して、独自のクラスでflex
margin
padding
等を適用します。 - 今回の見た目はほぼ
vuetify
のコンポーネントの見た目そのままになってます。 -
モーダル
やページング
、トースト
等がすごく楽になります。
html2canvas
Webページの一部を画像にする
-
「Webページをレンダリングして
Canvas
上に描画する」処理を行います。 -
2種類のやり方のうち後者を採用しています。
①読み込んだ要素をtoDataURL
にして<img>
のsrc
に埋め込むタイプ
(こちらの記事より: [JavaScript] JSだけでスクリーンショットを撮ってダウンロードもする方法(Qiita))
<div id="target">
<!-- ここがキャプチャされる -->
</div>
<!-- 下に生成した画像が出る -->
<img src="" id="result" />
html2canvas(document.getElementById("target"),{
onrendered: function(canvas){
//imgタグのsrcの中に、html2canvasがレンダリングした画像を指定する。
var imgData = canvas.toDataURL();
document.getElementById("result").src = imgData;
}
});
②読み込んだ要素を指定した場所の子要素にcanvas
を挿入する
<div id="target">
<!-- ここがキャプチャされる -->
</div>
<div id="result">
<!-- ここに生成した画像が出る -->
</div>
html2canvas(document.querySelector("#target"))
.then(function(canvas) {
var result = document.querySelector("#result");
result.innerHTML = "";
result.appendChild(canvas);
}
ハマったところ
vuetify
の<v-text-field>
でvue.js
のv-model.lazy
が使えない
イベントリスナーを使用して手動で行う必要があります
- https://github.com/vuetifyjs/vuetify/issues/1810
- 使えないようです。「入力が完了したら自動で検索」を実装したかったのですが、できませんでした。
- エンターキーで検索に切り替えました。
<v-text-field v-model="serchWords" @keydown.enter="execSearch(serchWords)"/>
html2canvas
で、外部から読み込んだ画像が表示されない
デフォルトだとCORS
で引っかかって、描画できないみたいです。
attribute: allowTaint
type: boolean
default: false
description: Whether to allow cross-origin images to taint the canvas
- こちらを参考に、
option
を追加したらうまくいきました。
tml2canvas(document.querySelector("#target"), {
+ letterRendering: 0,
+ useCORS: true,
+ allowTaint: true
}).then(function(canvas) {
var result = document.querySelector("#result");
result.innerHTML = "";
result.appendChild(canvas);
});
Firebase Funtions
で外部通信ができない
Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions
- 無料枠(Sparkプラン)だとダメみたいです。
- Flameプラン($25/月)に切り替えて解決しました。
- 参考:Cloud Functions for Firebaseに関する雑記(Qiita)
firebase emulators
のAPIの向き先がクラウドになる。
$ firebase emulators:start
上記コマンドで Hosting
とFunctions
を起動した状態で、Hosting上のvue.js
からAPI(Functions)
を叩くと、クラウドのFunctions
を見に行ってしまい、CROS
エラーになる。(404とかではなくて)
-
emulator
ではHosting
だけを上げて、Functions
はデプロイしてテストするようにしました。(functions.https.onCall()
の方を使ってます。) - 見逃してるだけできっと設定があると思います。
今後の展望
-
Unsplush
からProduction api key
がいただけたらサービスとしてリリースしようと思います。(1月予定) - 欲しい機能とかあれば気軽にコメントください!!喜びます
- googleでログインでき、「個人の言葉」を美しい画像ともに保存できる
- 画像と言葉の組み合わせで、「5秒でエモい画像が作れる」
- 画像のランダム生成で大喜利
- Twitterでの共有
最後に
ここまで、お読みいいただきありがとうございます!
最後に、開発途中で特に意味もなく作った画像を添えておきます。