ポーリングアプリケーションを作成しています。人々は投票を作成し、彼らが尋ねる質問に関するデータを取得することができます。ユーザーが結果をPDF形式でダウンロードできるようにする機能を追加したいと思います。
たとえば、質問とデータを取得する2つのコンポーネントがあります。
<QuestionBox />
<ViewCharts />
両方のコンポーネントをPDFファイルに出力しようとしています。ユーザーはこのPFDファイルをダウンロードできます。コンポーネント内でPDFのレンダリングを許可するいくつかのパッケージを見つけました。しかし、仮想DOMで構成される入力ストリームからPDFを生成できるものを見つけることができませんでした。これをゼロから達成したい場合、どのアプローチに従うべきですか?
Pdfとしての反応は一般に苦痛ですが、canvasを使用して回避する方法があります。
アイデアは変換することです:HTML-> Canvas-> PNG(またはJPEG)-> PDF
上記を実現するには、次のものが必要です。
import React, {Component, PropTypes} from 'react';
// download html2canvas and jsPDF and save the files in app/ext, or somewhere else
// the built versions are directly consumable
// import {html2canvas, jsPDF} from 'app/ext';
export default class Export extends Component {
constructor(props) {
super(props);
}
printDocument() {
const input = document.getElementById('divToPrint');
html2canvas(input)
.then((canvas) => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF();
pdf.addImage(imgData, 'JPEG', 0, 0);
// pdf.output('dataurlnewwindow');
pdf.save("download.pdf");
})
;
}
render() {
return (<div>
<div className="mb5">
<button onClick={this.printDocument}>Print</button>
</div>
<div id="divToPrint" className="mt4" {...css({
backgroundColor: '#f5f5f5',
width: '210mm',
minHeight: '297mm',
marginLeft: 'auto',
marginRight: 'auto'
})}>
<div>Note: Here the dimensions of div are same as A4</div>
<div>You Can add any component here</div>
</div>
</div>);
}
}
必要なファイルがインポートされていないため、スニペットはここでは機能しません。
this answer では別のアプローチが使用されており、中間ステップが削除され、HTMLからPDFに簡単に変換できます。 jsPDFドキュメントにもこれを行うオプションがありますが、個人的な観察から、domが最初にpngに変換されると、より良い精度が達成されると感じています。
アップデート0:2018年9月14日
この方法で作成されたPDFのテキストは選択できません。それが要件である場合は、 この記事 が役立つ場合があります。
jsPDFでcanvansを使用できます
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
_exportPdf = () => {
html2canvas(document.querySelector("#capture")).then(canvas => {
document.body.appendChild(canvas); // if you want see your screenshot in body.
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF();
pdf.addImage(imgData, 'PNG', 0, 0);
pdf.save("download.pdf");
});
}
そして、IDキャプチャのdivは次のとおりです。
<div id="capture">
<p>Hello in my life</p>
<span>How can hellp you</span>
</div>
ReactDOMServerを使用してコンポーネントをHTMLにレンダリングし、jsPDFでこれを使用できます。
最初にインポートを実行します。
import React from "react";
import ReactDOMServer from "react-dom/server";
その後:
var doc = new jsPDF();
doc.fromHTML(ReactDOMServer.renderToStaticMarkup(this.render()));
doc.save("myDocument.pdf");
使用することを好む:
renderToStaticMarkup
の代わりに:
renderToString
前者には、依存するHTMLコードが含まれています。
npm install jspdf --save
//反応時にコード
import jsPDF from 'jspdf';
var doc = new jsPDF()
doc.fromHTML("<div>JOmin</div>", 1, 1)
onclick //
doc.save("name.pdf")
ReactPDF を使用できます
DivをPDFに簡単に変換できます。 ReactPDFマークアップを使用するには、既存のマークアップと一致させる必要がありますが、その価値はあります。
これは物事を行う最適な方法ではないかもしれませんが、私が見つけた複数ページの問題に対する最も簡単な解決策は、jsPDFObj.saveメソッドを呼び出す前にすべてのレンダリングを確実に行うことでした。
非表示の記事のレンダリングに関しては、これはcss画像のテキストの置換と同様の修正で解決されます。レンダリングされる要素を-9999px離れたページに絶対に配置します。 、特に{display: none}
に依存するタブ、アコーディオン、およびその他のUIコンポーネントを使用する場合。
このメソッドは、前提条件をプロミスにラップし、pdf.save()
メソッドでfinally()
を呼び出します。これが絶対確実であること、またはアンチパターンであることを確信することはできませんが、私がそれに投げかけたほとんどの場合に機能するようです。
// Get List of paged elements.
let elems = document.querySelectorAll('.elemClass');
let pdf = new jsPDF("portrait", "mm", "a4");
// Fix Graphics Output by scaling PDF and html2canvas output to 2
pdf.scaleFactor = 2;
// Create a new promise with the loop body
let addPages = new Promise((resolve,reject)=>{
elems.forEach((elem, idx) => {
// Scaling fix set scale to 2
html2canvas(elem, {scale: "2"})
.then(canvas =>{
if(idx < elems.length - 1){
pdf.addImage(canvas.toDataURL("image/png"), 0, 0, 210, 297);
pdf.addPage();
} else {
pdf.addImage(canvas.toDataURL("image/png"), 0, 0, 210, 297);
console.log("Reached last page, completing");
}
})
setTimeout(resolve, 100, "Timeout adding page #" + idx);
})
addPages.finally(()=>{
console.log("Saving PDF");
pdf.save();
});