Puppeteer with Chart.js
Asked Answered
T

1

1

I'm trying to generate a PDF using Puppeteer and insert there a Chart.js graph (but the whole PDF should be a text based - not a webpage screenshot). When I open the template I can see graph loaded, but in PDF there is just a blank space instead. I'm generating it like this:

async function generatePdf() {
  let data = { value: "myValue" };
  getTemplateHtml()
    .then(async (res) => {
      // Now we have the html code of our template in res object
      // you can check by logging it on console
      // console.log(res)
      console.log("Compiing the template with handlebars");
      const template = hb.compile(res, { strict: true });
      // we have compile our code with handlebars
      const result = template(data);
      // We can use this to add dyamic data to our handlebas template at run time from database or API as per need. you can read the official doc to learn more https://handlebarsjs.com/
      const html = result;
      // we are using headless mode
      const browser = await puppeteer.launch({ args: ["--no-sandbox"] });
      const page = await browser.newPage();
      // We set the page content as the generated html by handlebars
      await page.setContent(html);
      // We use pdf function to generate the pdf in the same folder as this file.
      await page.pdf({
        path: "output2.pdf",
        format: "A4",
        displayHeaderFooter: true,
        margin: {
          top: "2.5cm",
          right: "2.5cm",
          bottom: "2.5cm",
          left: "2.5cm",
        },
        headerTemplate: "<div></div>",
        footerTemplate:
          '<div style="width: 100%; font-size: 11px !important; overflow: auto; margin-left: 2.5cm; margin-right: 2.5cm; color: ghostwhite;"><span>TEST</span><a href="http://test.com" style="float: right; color: #1E90FF; text-decoration: none;">www.test.com</a></div>',
      });
      await browser.close();
      console.log("PDF Generated");
    })
    .catch((err) => {
      console.error(err);
    });
}
generatePdf();

Thanks

Taradiddle answered 1/9, 2020 at 16:54 Comment(2)
Hi, if you have, can you please share the node js and html code of this, I am trying to do a similar thing, and couldn't figure it out. Thanks a lotFetal
See also How to create a bar chart image on nodejs without a browser?, puppeteer can't find the helpers of nodejs handlebars and using async await and .then together (you're not awaiting or returning your promise chain)Cortney
T
9

You need to have Puppeteer wait for the Javascript to execute and render the graph.

You can supply a waitUntil option to page.setContent (doc):

await page.setContent(reuslt, {
    waitUntil: ["load","networkidle0"]
});

Also, you should disable animation on your chart by setting options.animation.duration to 0.

You haven't shared your HTML/Javascript so I can't say for sure, but if your Javascript still isn't executed then you can use waitForFunction to wait until your graph has loaded. See this answer for details.

Tello answered 4/9, 2020 at 17:6 Comment(4)
Completely forgot about the loading animations here. Thanks so much for this tip.Carving
Thanks so much for the tip about the animations when it comes to printing!Ur
networkidle0 did the trick for me. Thanks a lot @TelloKinata
Since networkidle0 is a lot stricter than load, this can simply be: waitUntil: "networkidle0". Now, networkidle is slow, so I'd use this as a last resort. You can get a faster result waiting for the specific network response or DOM mutation you expect, rather than waiting for everything to settle, then waiting 500 ms after that.Cortney

© 2022 - 2024 — McMap. All rights reserved.