JavaScript 向けブラウザスクリーンショットライブラリ html2canvas で画面の一部分のみのスクリーンショットをとってみました

CX事業本部の熊膳です。html2canvasというJavaScriptでスクリーンショットを取得するライブラリを使ってみたので紹介します。

html2canvasとは

html2canvasは、JavaScriptでWebページ(もしくはその一部)のスクリーンショットを取る(実際にはCanvas上に描画する)ためのライブラリです。 独自にDOM解析やレンダリングなどを行っているため、完全にブラウザで表示しているものと同じものになるとは限りませんが、かなり再現性高いです。

公式サイトは、こちらです。

html2canvas - Screenshots with JavaScript

使い方(公式サイトより)

html2canvas(document.body).then(function(canvas) {
    document.body.appendChild(canvas);
});

ブラウザのスクリーンショットを撮る方法はいくつかあります(OSの標準機能を使うChromeのDevToolsを使う)が、 html2canvasを使うメリットは、そのものずばり、JavaScriptで記述できるということです。 Webアプリでグラフを生成したあとダウンロードさせるとか、JavaScriptでいろいろ操作してからスクリーンショットを撮るなど思いつきますね。

やってみた

html2canvasを使ってスクリーンショットを撮ってみます。 今回、以下を使っています。

  • Google Chrome 78.0.3904.97
  • html2canvas 1.0.0-rc.5
  • jQuery 3.4.1

本来であれば自作のWebアプリなどでhtml2canvasを活用すればいいのですが、今回は、自分用のChrome機能拡張に組み込んで動かしてみました。 使い方は同じですので、適宜読み替えて下さい。

スクリーンショットを撮る対象

GitHub Projectsのスクリーンショットを撮ってみます。対象は、レーンの部分です。

対象の要素を指定してみる

取得したい対象の要素を指定してみます。

html2canvasの第1引数に、対象の要素を指定できます。今回は、レーンのみとしたいため project-columnsクラスを指定します。 レンダリング完了時に、canvasの内容をBlobに変換し、それを事前に用意したaタグに指定することでダウンロードを行います。

$(() => {
  // ボタン追加
  const menu = $('div.project-header-controls');
  menu.append(
    '<button id="ss">SS</button><a hidden href="" id="download"></a>'
  );
  // 画面キャプチャー
  $(document).on('click', '#ss', () => {
    html2canvas(document.querySelector(".project-columns"), {
      }).then(canvas => {
        canvas.toBlob(blob => {
          $("#download").attr("download", `${document.title}.png`).attr("href", window.URL.createObjectURL(blob));
          $('a#download')[0].click();
      })
    })
  })
})
  • ボタン(#ss)は、スクリーンショット実行用
  • リンク(a#download)は、画像ダウンロード用

結果は、以下のようになりました。 どうやら、html2canvasは、ブラウザで表示している部分を対象にしているようです。画面ではReviewer approvedレーンまで表示されていますが、実際に取得した画像でも同様です。

試しにブラウザを狭めたところ、範囲が狭くなりました。レーン数が3本しか取得できていません。

html2canvasのオプションを指定してみる

広いモニターを繋いでいればいいのですが、ノートPCではなかなか無理があるので、html2canvasの機能を使って画像取得部分を広げてみます。 Options をみると、windowWidth というパラメータがありました。

Window width to use when rendering Element, which may affect things like Media queries

早速使ってみます。

    html2canvas(document.querySelector(".project-columns"), {
      windowWidth: 2500
      }).then(canvas => {
      :

思い切って2500と指定しましたが、変わらないようです。

Optionsを再度確認したところ、width というそのものずばりのパラメータがありました。

The width of the canvas

どうやら、widthはcanvasのサイズを決め、windowWidthは、ブラウザのサイズを決めるようです。言い換えると、widthはキャプチャーするエリアのサイズ、windowWidthはブラウザのサイズを指定するということですね。

指定してみます。

   html2canvas(document.querySelector(".project-columns"), {
      windowWidth: 2500,
      width: 2500
      }).then(canvas => {
      :

思ったとおりです。

あとは、適切にサイズを計算し指定すれば良さそうです。レーンの幅、マージンは計算可能ですので指定できます。

overflowによるスクロールの対応

html2canvasは、ブラウザの表示領域を対象としますが、overflowによるブラウザ内のスクロールは、表示通りに取得するため、スクロールで隠れた部分の取得ができません。 To doレーンは、3つのカードがありますが、overflowが指定されており、スクロールしないとすべてのカードが見えません。他のレーンも同様です。

今度は高さを指定し、heightとwindowHeightを指定することでうまくいきそうです。ただし、カードの高さを簡単に計算する方法が思いつきませんでした。そこで今回は、overflowを無効化する作戦をとってみます。

overflowを無効にする方法はいくつかあると思いますが、今回はheightをautoにする方法で行ってみます。具体的には、project-columns-containerクラスに指定されているheight: 0height: autoにすることで一時的に解除します。

以下を用意しておきます。

.expandLane {
  height: auto !important;
}

クラスを指定して、heightとwindowHeightを指定します。

    $('.project-columns-container').addClass('expandLane'); // overflowを無効
    html2canvas(document.querySelector(".project-columns"), {
      windowHeight: $('.project-columns-container').height(),
      height: $('.project-columns-container').height()
      }).then(canvas => {
      :
    $('.project-columns-container').removeClass('expandLane');

結果は、以下のとおりです。縦方向にはサイズが変わりましたが、Canvasに描画しているエリアが異なるようです。

いろいろ試した結果、windowHeightをスクロール含めたブラウザの高さに指定し、canvasサイズはhtml2canvasにおまかせする方法でうまくいくことがわかりました。

    $('.project-columns-container').addClass('expandLane'); 
    html2canvas(document.querySelector(".project-columns"), {
      windowHeight: document.getElementsByTagName('body')[0].scrollHeight
      }).then(canvas => {
      :

初期位置

これで完成かと思いましたが、ブラウザの表示領域をスクリーンショットで保存するという仕様のため、表示位置がスクロールされた状態だと、ずれた位置の状態で取得する事がわかりました。

対応方法は簡単です。無理やりですが、左上にスクロールさせてあげればよいです。

    $('.project-columns-container').addClass('expandLane');
    $('.project-columns-container').scrollTop(0);   // スクロール
    $('.project-columns-container').scrollLeft(0);  // スクロール
    html2canvas(document.querySelector(".project-columns"), {
        :

最終的に取得したスクリーンショットは、こちらです。

さいごに

html2canvasを使ってブラウザのスクリーンショットを撮ってみました。 また、取得するエリアを指定することや、overflowなどで隠れた部分でもhtml2canvasのオプションを指定することで、期待するスクリーンショットを撮ることができました。 Web画面の一部をダウンロードする用途に活用できそうです。