Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I dynamically split chunk of text into pages for jsPDF?

I have a React app, page displaying some post containing title, text, few images etc. I'm trying to generate PDF file out of that.

The actual page is quite twisty, dynamic and complicated, so instead of trying to convert HTML to PDF I am using jsPDF package and as a content I insert state variables from Redux store. And it would have been ideal situation for that - I have tools to generate layout, I have bits of content, but... I bumped into a problem. Text of my post can vary from very little to few pages long, so in that case it should be passed to the next page. I have worked out how to get "pageHeight" and "textHeight", so when "textHeight" is bigger than "pageHeight" I can add another page by doc.addPage(), however the text stays on one page only and gets cut off by the end of the page (please see attached screenshot). This is where I am so far with my code:

const pdfGenerator = () => {
    // Default export is a4 paper, portrait, using millimeters for units
    const doc = new jsPDF();
    const pageHeight = doc.internal.pageSize.height;

    const wrappedText = doc.splitTextToSize(post.text, 200);
    doc.setFontSize(14);
    const dim = doc.getTextDimensions(wrappedText);
    const textHeight = dim.h;
    doc.text(15, 10, wrappedText);
    if (textHeight >= pageHeight) {
      doc.addPage();
    }
    // const textPages = Math.ceil(dim.h / pageHeight);
    // Don't know what to do with it....

    doc.save(`${post.title}.pdf`);
  };

One of the possible solutions would be to split whole text into array of chunks that can fit the page and then do a loop or map it through adding doc.addPage() every time. Big problem with that - it will split text in random places, like in the middle of the word.

I tried my best to find solution, lots of time wasted with no result...

Please help!

Generated PDF page break

like image 350
waway Avatar asked Oct 21 '25 03:10

waway


1 Answers

The splitTextToSize function will return an array with the text splitted into lines, we just need to work with it controlling the interactions. The code below should resolve your problem.

const pdfGenerator = () => {
    // Default export is a4 paper, portrait, using millimeters for units
    const doc = new jsPDF();
    const pageHeight = doc.internal.pageSize.height;

    const wrappedText = doc.splitTextToSize(post.text, 180);
    doc.setFontSize(14);
    let iterations = 1; // we need control the iterations of line
    const margin = 15; //top and botton margin in mm
    const defaultYJump = 5; // default space btw lines
    
    wrappedText.forEach((line) => {
      let posY = margin + defaultYJump * iterations++;
      if (posY > pageHeight - margin) {
        doc.addPage();
        iterations = 1;
        posY = margin + defaultYJump * iterations++;
      }
      doc.text(15, posY, line);
    });

    doc.save(`${post.title}.pdf`);
  };
like image 194
Thiago Moura Avatar answered Oct 23 '25 16:10

Thiago Moura



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!