たった8行!キャンバスをワンクリックで保存させるJavaScriptコード(IEも大丈夫)

前回の「コピペでOK!Chart.js の数字を3桁カンマで表示する方法」でも書きましたけど、HTML5のcanvasを使ってグラフを描く開発をしてます。

canvasは久しぶりにさわりましたけど、よく考えたらこれって結構使い勝手いいですよね。chart.jsがやってるみたいに可変的に画像を変更できますし、速度も遅くはありませんので。

で、その後キャンバスを画像で保存する必要がでてきたんで色々と探ってみた結果、なんと(DL部分は)たった8行で実現できることが分かったんで、シェアをしたいと思います。(しかもあのにっくきインターネットエクスプローラーでも動きますよ!)

ダウンロード・サンプル

いきなり完成版コード

今回はコードが少ないんで先に完全版コードから紹介します。

なお、ネイティブJavaScript で書いてます。
つまり、jQueryを使ってなくてもOKですし、あなたがReactフリークでも動きますよ!

(※ちなみに最近海外のサイトを見るとドンドン「脱jQuery」が進んでるみたいです。あと、やっぱりES6が急激に増えている印象ですね。)

コード

<html>
<head></head>
<body>
<!--キャンバス-->
<canvas id="my_canvas" width="400" height="200"></canvas>
<br>
<!--ダウンロード用ボタン-->
<button id="download_button">ダウンロードする</button>
<!--ダウンロード用リンク-->
<a id="download_link"></a>
<script>

    window.onload = function(){

        var canvas = document.getElementById('my_canvas');
        var downloadLink = document.getElementById('download_link');
        var filename = 'your-filename.png';

        /*  テストのために描画  */
        var ctx = canvas.getContext('2d');
        ctx.fillStyle = '#eee';
        ctx.fillRect(0, 0, 400, 200);
        ctx.font = '18px sans-serif';
        ctx.fillStyle = '#e00';
        ctx.fillText('このキャンバスを画像でダウンロードします', 25, 100);

        var button = document.getElementById('download_button');
        button.addEventListener('click', function(){

            if (canvas.msToBlob) {
                var blob = canvas.msToBlob();
                window.navigator.msSaveBlob(blob, filename);
            } else {
                downloadLink.href = canvas.toDataURL('image/png');
                downloadLink.download = filename;
                downloadLink.click();
            }

        });

    };

</script>
</body>
</html>

中身を説明

まずHTML側に必要なのは以下の3つです。


  1. canvasタグ ・・・ 当たり前ですね(笑)
  2. ダウンロード用ボタン ・・・ クリックイベントでダウンロードを実行します。
  3. ダウンロード用リンク ・・・ キャンバスを画像で保存するときに必要になってきます。隠し要素です。

で、JavaScript側の流れはこんなカンジです。

  1. window.onload でページロードが完了したら処理を開始
  2. (テストのために)キャンバスを描画
  3. ボタンをクリックしたときに起動するイベントを設定

そして、ダウンロードの本体部分はこちら。

if (canvas.msToBlob) {
    var blob = canvas.msToBlob();
    window.navigator.msSaveBlob(blob, filename);
} else {
    downloadLink.href = canvas.toDataURL('image/png');
    downloadLink.download = filename;
    downloadLink.click();
}

1行目にいきなりifがきてるのは、(問題児の^^;)IE、Edgeに対応するためです。
つまりifの中身はマイクロソフト用、elseはChromeなど他社用ってことになります。

それにしても、ウェブ開発を初めて十年余。マイクロソフトはいつまでインターネットの発展を阻害し続けるんでしょうか・・・・・・。
そろそろ、こういうのもちゃんとサポートしなはれ・・・(汗)

ちなみにマイクロソフト用だと保存は image/png 形式になりました。もしかすると image/jpeg に設定する方法があるのかもしれませんけど、僕の中ではもう彼等は見限っているのでパスします・・・(笑)

では、その他のブラウザ用のコードがどんな流れで動くのか見ていきましょう。

  1. キャンバスからtoDataURL()を使って画像データを取得
  2. リンクの href に画像データ、downloadプロパティにファイル名を設定
  3. リンクがクリックされたことにする

というものです。つまり、IE、edgeでは<a>タグのdownloadプロパティが使えないので、ダメみたいですね。 Oh my…

ということで、今回のテクニックはキャンバス描画ライブラリ「JimmyJS」にも使われています。ただし、マイクロソフト製ブラウザには対応してませんし、対応する予定は今の所ありません。(こういうのをやっていかないとマイクロソフトも重い腰をあげないと思うんですよね。まー、もうPC用ブラウザはほぼみんな使わなくなってきてますけどね。)

ということで今回は以上です。
ではでは!



にほんブログ村 IT技術ブログへ  にほんブログ村 IT技術ブログ プログラム・プログラマーへ


BugGUI バグ報告を効率化
たった3分でバグ報告完了!? BugGUI