No more boring posts, I promise. Go for it! the problem is:
- You have a form where you submit some data
- The server-side script handling this posted data generates a PDF file
- Some elements are rendered weirdly or not rendered at all
Notice that we are not talking about printing a web page or the like but generating a dynamic PDF in server-side.
The example: Charts.js
We want to show a cool chart in our PDF file generated with the amazing ChartsJS library
. Take a look, this is a HTML5-based charts library that rocks.
The big deal is that you are using probably a (PHP) library look here
. Then you are experiencing some trouble because your PDF doesn't look good and you can not attach that chart to your PDF when generating the view to pass to the PDF generator library.
Some of good practices here:
- Use simple html, css
- Avoid floating elements
- Use images for complex stuff
"Use images for complex stuff" (yes, the chart is a good example) but, how?
In a nutshell:
- Your form has to post an image for your chart in a hidden field
- To generate this image just add a invisible div and put your chart (based on form data) inside.
- When you submit your form just call yourchart.toBase64Image() and store the result in a hidden field.
Magic! The you are ready to go. Get this hidden field value (a image/png) in server-side and add it to your PDF.
Hang on... how it works?
Well, even though I haven't dug into the guts in Chartjs, I'm pretty sure it uses .toDataURL()
since the charts generated are HTML5-canvas-based. In general terms you can use this hidden-image-post workaround for any complex stuff you are able to render in a canvas. Just create a canvas in a invisible div and store in a hidden field the yourcanvas.toDataURL() when submitting.
Not perfect or universal solution but quite handy work-around.
As usual, many thanks to @kotfire
(who brought light here) and @moraDmp30
(who implemented a solution like that in one of our projects). You guys are awesome.
Thanks for reading this. Don't hesitate to drop any comment below!