Creating a PDF from React Components

I am creating a survey application. People can create their own polls and receive data on the questions they ask. I would like to add functionality so that users can download the results as a PDF.

For example, I have two components that are responsible for capturing the issue and data.

<QuestionBox /> <ViewCharts /> 

I am trying to output both components to a PDF file. The user can then download this PFD file. I found several packages that allow PDF rendering inside a component. However, I could not find a file that could generate a PDF from an input stream consisting of a virtual DOM. If I want to achieve this from scratch, which approach should I take?

+24
source share
7 answers

Rendering as pdf is usually a pain, but there is a way around this using canvas.

The idea is to convert: HTML → Canvas → PNG (or JPEG) → PDF

To achieve the above, you will need:

  1. html2canvas &
  2. jsPDF

 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>); } } 

The snippet will not work here because the necessary files are not imported.

This answer uses an alternative approach when the middle steps are omitted and you can simply convert from HTML to PDF. It is possible to do this in the jsPDF documentation, but from personal observation, I feel that the best accuracy is achieved when converting dom to png for the first time.

Update 0: September 14, 2018

Text in PDF files created using this approach will not be selected. If this is a requirement, you may find this article helpful.

+61
source

You can use canvans with jsPDF

 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"); }); } 

and you are a div with capturing id:

example

 <div id="capture"> <p>Hello in my life</p> <span>How can hellp you</span> </div> 
+2
source

This may or may not be the optimal way to do things, but the simplest solution to the multi-page problem I discovered was to make sure that all rendering is done before calling the jsPDFObj.save method.

As for the rendering of hidden articles, this is solved similarly to a correction similar to replacing text in a CSS image, I place absolutely the element that will be displayed -9999px to the left of the page, this does not affect the layout and allows the element to be visible for html2pdf, especially when using tabs , accordions, and other user interface components that depend on {display: none} .

This method wraps the preconditions in the promise and calls pdf.save() in the finally() method. I cannot be sure that this is a reliable protection or template, but it may seem that in most cases this works.

 // 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(); }); 
+1
source
 npm install jspdf --save 

// reaction code

 import jsPDF from 'jspdf'; var doc = new jsPDF() doc.fromHTML("<div>JOmin</div>", 1, 1) onclick // doc.save("name.pdf") 
+1
source

You can use ReactDOMServer to render your component in HTML and then use it in jsPDF.

First import:

 import React from "react"; import ReactDOMServer from "react-dom/server"; 

then:

 var doc = new jsPDF(); doc.fromHTML(ReactDOMServer.renderToStaticMarkup(this.render())); doc.save("myDocument.pdf"); 

Prefer to use:

renderToStaticMarkup

instead:

renderToString

As the first include HTML code that responds to.

0
source

I used to print the current page in pdf format using js pdf, I also created a demo version for which you can go to or refer to this [ https://github.com/AkashMishraMS/React-Pdf†[1], you You can get more clarity also for Multipage creation of PDF, you can calculate the size of the canvas and SVG and print. and soon I will create a demo for this too.

[1]: https://github.com/AkashMishraMS/React-Pdf .

0
source

You can use ReactPDF

Allows you to easily convert div to PDF.

0
source

Source: https://habr.com/ru/post/1245269/


All Articles