html2canvasをつかってコラ画像生成アプリをつくってみた


つくったもの


Oicollamaker(GitHubはこちら

できました。明治おいしい牛乳のパッケージのコラージュ画像を生成できるアプリです。

Q. こんなアプリだれがつかうんですか?
A. 知りません

Q. スマホにも対応していますか?
A. 完全非対応です。

なぜつくったか

JavaScriptでDOMを操作する方法を学び、何かをつくりたくなったからです。

html2canvas

明治おいしい牛乳(以下「おい牛」という)のパッケージ部分はHTMLでできています。
そのため右クリックで保存することができません。

もちろんスクショを撮ってトリミングすれば保存できますが、ちょっとめんどうです。

そこで、おい牛のパッケージ部分を画像化する機能をつけてみました。
その部分ではhtml2canvasというJavaScriptのライブラリを利用しています。

公式サイトはこちら:
html2canvas - Screenshots with JavaScript

つかいかたは至ってかんたんです。
たとえばHTML内の画像化したい要素にtargetというidをつけておいて、

JavaScript
html2canvas(document.getElementById("target")).then(canvas => {
      document.body.appendChild(canvas);
});

という魔法を唱えると、targetの内容が描画されたcanvasbodyの子要素として追加することができます。

問題点

肝心のおい牛パッケージを画像化する機能ですが、いろいろと問題があります。

たとえば、

これをhtml2canvasで画像化すると・・


こうなります。

ヨとグのあいだの長音符(のばし棒)の向きがおかしいですね。
おそらくhtml2canvasが縦書きのテキストに対応していないのでしょう。

また、画面最上部からいくらか下にスクロールした状態でボタンを押して画像化を実行すると・・

このように、スクロールした分だけ下にずれた画像が生成されてしまいます。
このバグはなんとかしたら直せそうなので、気が向いたらやってみようとおもいます。

工夫した点

はじめは、input要素をHTMLに直接記述することで入力用のテキストボックスを設置していました。

HTML
<form>
  <input type="text" placeholder="明治">
  <input type="text" placeholder="おいしい牛乳">
  <input type="text" placeholder="ナチュラルテイスト製法">
</form>

<section>
  <div class="output">明治</div>
  <div class="output">おいしい牛乳</div>
  <div class="output">ナチュラルテイスト製法</div>
</section>

こんなかんじです(コードは説明のために簡略化しています)。

このうえでJavaScriptを次のように書いていました。

JavaScript
const inputs = document.querySelectorAll("input");
const outputs = document.querySelectorAll(".output");

for (i = 0; i < inputs.length; i++) {

  // 入力した文字がリアルタイムで反映されるように設定
  inputs[i].addEventListener("input", e => {
    outputs[i].textContent = e.target.value; 
}

このままでもいいのですが、HMTLのほうで重複している箇所が多いのが気になります。

たとえば「おいしい牛乳」を「世界一おいしい牛乳」にさしかえたい場合、
input要素のplaceholder属性の値と、div内のテキストの2箇所を修正しなければなりません。
これはちょっとめんどうです。

そこで、ページが読み込まれたときにDOMを操作することによって、
入力用のテキストボックスが自動的に設置されるようにしてみました。

まず、HTMLを次のように修正します。

HTML
<form></form>

<section>
  <div class="output">明治</div>
  <div class="output">おいしい牛乳</div>
  <div class="output">ナチュラルテイスト製法</div>
</section>

input要素をすべて取りのぞきました。

そしてJavaScriptを次のように修正します。

JavaScript
const outputs = document.querySelectorAll(".output");

for (i = 0; i < outputs.length; i++) {
  const form = document.querySelector("form");

  // input要素を作成
  const input = document.createElement("input");

  // 作成したinput要素に属性を付与
  input.setAttribute("type", "text");
  input.setAttribute("placeholder", outputs[i].textContent);

  // 入力した文字がリアルタイムで反映されるように設定
  input.addEventListener("input", e => {
      outputs[i].textContent = e.target.value;
  });

  // formの子要素としてinputを追加
  form.appendChild(input);
}

このようにすれば、ページが読み込まれたときに、
outputクラスをつけておいたHTML要素それぞれについて、
対応する入力用のテキストボックスが設置されるようになります。

もしもコラージュの対象を明治エッセルスーパーカップに変更したくなったら、
HTML内の該当する部分をスーパーカップ仕様にかきかえて、
編集させたい要素にoutputクラスをつけるだけでOKです。ラクチンですね。

おわりに

なんか明治のまわしものみたいになってしまいましたが、
いっさい関係ありません。。。

最近はPHPもさわりはじめたので、今度はPHPもつかって何かつくってみようとおもいます。