お詫び
アドベントカレンダーの記事と同時にリリースする予定で作成していましたが、
バックエンドで使用する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>のような独自のコンポーネントを使用して、独自のクラスでflexmarginpadding等を適用します。 - 今回の見た目はほぼ
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での共有
最後に
ここまで、お読みいいただきありがとうございます!
最後に、開発途中で特に意味もなく作った画像を添えておきます。












