15

I have seen a lot of posts describing how you can use chart.js to create a graph using canvas and to then save the canvas to png, and import it into a pdf. This is fine but what if you want to bypass the on screen part and go straight to a pdf document and include the image?

For example, I may have two buttons, one that opens the chart on screen using canvas. This page could then handle the chart saving and importing into the pdf without a problem. The other button opens the pdf directly. Is it possible to get the chart into this document, either saving it on the server first somehow or not?

I suspect I might be told to move over to d3 but I was just wondering if it is possible in chart.js?

enter image description here

RGriffiths
  • 5,722
  • 18
  • 72
  • 120

3 Answers3

4

This is fine but what if you want to bypass the on screen part and go straight to a pdf document and include the image

You can still use chart.js exporting as PDF with PhantomJs (a headless browser that will open a html page with your charts, and save it via PDF). If you are working with nodejs there's a good library that abstracts PhantomJs and make the PDF easy: https://github.com/sindresorhus/pageres. It seems like a workaround, but usually these canvas to PDF doesn't render well, specially charts!

Yeah, you still need to create a html page to print your PDF, however you have 2 options:

Community
  • 1
  • 1
Wagner Leonardi
  • 4,226
  • 2
  • 35
  • 41
  • Ah ... brilliant. Would this be considered the correct approach or is this a workaround? – RGriffiths May 12 '16 at 16:57
  • PhantomJS is the best way to render a HTML page as PDF, specially charts. These canvas to PDF stuff doesn't render exactly as we see on browser. – Wagner Leonardi May 12 '16 at 16:59
  • OK but I am not wanting the render the whole html page, nor turn just this image into a pdf as there is loads of other stuff in the pdf from other places. Am I understanding you correctly that I can use phantom js to open the html page that generates the canvas, then saves it on the server, and then opens the pdf doc which imports the saved image? – RGriffiths May 12 '16 at 17:04
  • Yeah exactly. How could you do it on server in another way? Even that looks strange, this is the only way to render the charts as PDF exactly as they look on the browser. Other approach is to use some library that do this in your server/backend, however it will not look as d3 or chart.js, as these charts are made for the front-end. – Wagner Leonardi May 12 '16 at 17:11
2

I was working on a similar problem and built QuickChart. It is a web service that renders Chart.js charts in several static formats including PDF.

The full source code is here: https://github.com/typpo/quickchart

You may be interested in lib/charts.js and lib/pdf.js in particular. The solution is built on top of a Javascript canvas implementation (node-canvas) and a Chart.js wrapper library (chartjs-node-canvas). First the chart is rendered to a PNG image using the canvas. Then the PNG is positioned on a document and rendered using pdfkit.

Hope you find the source code useful. I also host the QuickChart web service for free so you can use the web API directly https://quickchart.io/chart?width=500&height=300&format=pdf&c={chart.js config here}

Here's an example of a PDF chart generated on-the-fly:

https://quickchart.io/chart?f=pdf&bkg=white&c={type:'bar',data:{labels:['January','February','March','April','May'],datasets:[{label:'Dogs',data:[50,60,70,180,190]},{label:'Cats',data:[100,200,300,400,500]}]}}

ty.
  • 10,924
  • 9
  • 52
  • 71
0

While this does not answer the question directly as I could not get chart.js to do what I wanted being client side, I found a good solution using pChart. As the pdf is being generated, the chart is created and is temporarily saved on the server until the pdf is finished. The chart is inserted into the pdf and then deletes the chart from the server. There is a bit of manipulation to correctly size the image.

$myPicture->render("path/imagename.png");

if (file_exists("path/imagename.png")) {
    $ycurrent = $pdf->GetY();
    list($width, $height) = getimagesize("path/imagename.png");
    $imageWidth = 160;
    $ratio = $imageWidth/$width;
    $xpos = 25;
    $pdf->Image("path/imagename.png", $xpos, $ycurrent, $width * $ratio, $height * $ratio, "png", '');
    unlink ("path/imagename.png");
}
RGriffiths
  • 5,722
  • 18
  • 72
  • 120