LoginSignup
2
1

【PDF印刷】html2canvasとjsPDFでの複数ページ印刷時にautoTableを導入した話

Posted at

はじめに

「印刷」ボタンクリックでテーブルをPDF出力する機能を作ることになりました。
今回導入したautoTableに関する日本語のドキュメントが少なかったこともあり、
結構な時間試行錯誤したので、記録しておきます。

本題

html2canvasとjsPDFだけでは複数ページに渡るテーブルの印刷はうまくいかなかった

このテーブル、ユーザ入力により行数が変動するので少ない時は
印刷時に1ページに収まってくれるのですが、多い時は2ページ以上になります。
この時、これらのライブラリだけだとどう頑張っても表示崩れが起きてしまいました。
表示崩れの調整で各種ドキュメントやstackoverflowなどを眺め、
試行錯誤していたら丸1日経過していました。
その上うまくいきませんでした。

試行錯誤の結果:autoTable導入

調査する中で知ったautoTableという、テーブル描画に特化した
jsPDFのプラグインを導入してみることにしました。
すると少ないコード量で、美しいテーブルが印刷されたではありませんか。
(以下サイトより引用)

This jsPDF plugin adds the ability to generate PDF tables either by parsing HTML tables or by using Javascript data directly.

導入前後で変わったコードの量

これが(長いしうまくいかないやつ)↓

qiita.js

  $(".print-btn").click(() => {
    screenshot(document.getElementById("print-area")).then((canvas) => {
        window.jsPDF = window.jspdf.jsPDF;
        var pdf = new jsPDF("p", "mm", "a4");
        var imgData = canvas.toDataURL("image/png");
        var imgWidth = 210;
        var pageHeight = 297;
        var imgHeight = (canvas.height * imgWidth);
        var heightLeft = imgHeight;
        position = heightLeft - imgHeight + 10;
        pdf.addImage(imgData, "PNG", 10, position, imgWidth, imgHeight);
        heightLeft -= pageHeight;

        while (heightLeft >= 0) {
            position += heightLeft - imgHeight;
            pdf.addPage();
            pdf.addImage(imgData, "PNG", 10, position, imgWidth, imgHeight);
            heightLeft -= pageHeight;
        }
        pdf.save("fileName.pdf");
    });
});

function screenshot(element, options) {
    let cropper = pdfument.createElement("canvas").getContext("2d");
    // (中略)
    return html2canvas(element, options).then(function (c) {
        cropper.canvas.width = finalWidth;
        cropper.canvas.height = finalHeight;
        cropper.drawImage(c, -(+options.x || 0), -(+options.y || 0));
        return cropper.canvas;
    });
}

こうなりました。↓

qiita2.js

$(".print-btn").click(function () {
    window.jsPDF = window.jspdf.jsPDF;
    var pdf = new jsPDF("p", "pt", "a4");
    pdf.autoTable({ // autoTable導入
        theme: "striped", // striped, gridなどから選択
        html: "#pdf-table",
        styles: {
            font: "Aフォント", // 任意のフォントファイルをjsに変換後使用
            fontStyle: "normal",
            fontSize: 10,
        },
    });
    pdf.save("fileName.pdf");
});

最後に

以上です。相当久しぶりに記事を書いて楽しかったけれど、アウトプットって難しい。
需要があれば日本語フォントの導入方法詳細やHTML側のソースも追記したいと思います。
お気軽にご指摘やコメントいただけたら幸いです。
また書けたらいいな。

余談:元々候補だったライブラリたち

ライブラリ ざっくり調べたこと
laravel-dompdf CSS対応が微妙
laravel-snappy CSS対応はいい感じだが導入が大変
(※大変かどうかは未検証なので不明)
ブラウザの印刷機能 簡単だけどブラウザによって表示崩れが起きそう

色々と良し悪しあるのですが、、
ブラウザによらず、確実にこちらが意図したレイアウトで印刷できるのは
html2canvasとjsPDFの併用っぽい、ということで頑張ってみることになりました。
なお、今回はいずれのライブラリもCDNで導入しました。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1