Using Google Visualization with wkhtmltopdf

Published on March 17, 2014 by

The wkhtmltopdf tool, which converts HTML markup to a PDF document, is quite powerful compared to most other solutions that I have come across. It uses the WebKit rendering engine, which powers many Mac OS X applications such as Safari – and previously Google Chrome. If you have attempted to make wkhtmltopdf work with the Google Visualization API, you quickly noticed that it is unfortunately not as easy as one might think. While the wkhtmltopdf tool does execute JavaScript, rendering graphs (or visualizations) with Google Visualization API does not work out of the box. This article shows you how to easily get it working.

After searching and searching, and trying many different things, I finally got it to work by improvising and hacking away. I am using the Linux 64-bit binary version 0.12.0 available at wkhtmltopdf downloads page on an Ubuntu server. Please note that this article does not cover how to install wkhtmltopdf.

First, you need to use the javascript-delay argument, which allows you to delay the execution of JavaScript code for a given number of milliseconds. In my code, I have set it to 1000, and so far I have not had any problems. You could probably set it lower if you need the PDF to be rendered quickly.

That is the only argument you have to change. Below follows my template file used for generating the charts.


<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript" src="https://www.google.com/jsapi"></script>

        <script type="text/javascript">
            function init() {
                google.load("visualization", "1.1", { packages:["corechart"], callback: 'drawCharts' });
            }

            function drawCharts() {
                drawAccountImpressions('chart-account-impressions');
            }
            
            function drawAccountImpressions(containerId) {
            	var data = google.visualization.arrayToDataTable([
                    ['Day', 'This month', 'Last month'],
                    ['01', 1000, 400],
                    ['05', 800, 700],
                    ['09', 1000, 700],
                    ['13', 1000, 400],
                    ['17', 660, 550],
                    ['21', 660, 500],
                    ['23', 750, 700],
                    ['27', 800, 900]
                ]);

                var options = {
                    width: 700,
                    height: 400,
                    hAxis: { title: 'Day',  titleTextStyle: { color: '#333' } },
                    vAxis: { minValue: 0 },
                    curveType: 'function',
                    chartArea: {
                        top: 30,
                        left: 50,
                        height: '70%',
                        width: '100%'
                    },
                    legend: 'bottom'
                };

                var chart = new google.visualization.LineChart(document.getElementById(containerId));
                chart.draw(data, options);
            }
        </script>
    </head>
    
    <body onload="init()">
    	<div id="chart-account-impressions"></div>
    </body>
</html>

There are few things to notice here. First of all, notice the onload attribute on the body tag. This is what triggers our chain of JavaScript function calls. In the init function, I am loading the Google Visualization API as one typically would, except that I am passing in the name of a function, which will be used as a callback when the API is loaded. I found this to be necessary in order for Google Visualization to work with wkhtmltopdf.

When the library is ready, the drawCharts function is invoked. This is simply a function that I made because for my own use case, I need to draw several different charts. So all this function does is call other functions that each draw a chart. You could just as well draw your chart directly in the drawCharts function if you prefer; in other words, you are free to choose how to go about it.

The drawAccountImpressions function is just an example of how to create a line chart. There is nothing in this function that is special for wkhtmltopdf, so you can use the code examples from the Google Visualization API.

All there is left to do is to invoke wkhtmltopdf to generate your PDF, be it on the command line or through a wrapper library such as Snappy for PHP.

I hope this article has helped you save you the hours of searching and experimenting that I went through to figure out a solution. I wish you the best of luck!

Featured

Learn Laravel today!

Take an online course and learn the most popular PHP framework!

Here is what is covered:

  • Laravel basics (routing, controllers, blade templating, etc.)
  • Working with databases (including Eloquent ORM and raw SQL)
  • Forms and validation
  • Middleware
  • ... and much more!
Laravel logo
Author avatar
Bo Andersen

About the Author

I am a back-end web developer with a passion for open source technologies. I have been a PHP developer for many years, and also have experience with Java and Spring Framework. I currently work full time as a lead developer. Apart from that, I also spend time on making online courses, so be sure to check those out!

5 comments on »Using Google Visualization with wkhtmltopdf«

  1. Diego Delon

    If you need a module in Zend Framework 2 that allow easy to thumbnail, snapshot or PDF generation from a url or a html you can take a look to MvlabsSnappy based on Snappy PHP (5.3+) wrapper for the wkhtmltopdf & wkhtmltoimage conversion utility.

  2. Jesse Sternberg

    YES! This works! Apparently wkhtmltopdf + charts requires callbacks to be wired up in a very specific way to work properly.

  3. Furbee

    This was absolutely helpful. I am so excited that I can incorporate javascript into the PDF process instead of sending it to the client to render the charts and such. I am having an issue running it from Apache, though. It generates the html in the temp location, then returns with an error code -6 for the CalledProcessError. I can run the command parts from the command line and it works perfectly. I think it has to do with Apache2 not being able to fork a child process. Perhaps I need to use Celery to be able to do this from Django on Apache. Do you have some other way of getting it to work with Apache? I noticed you were running it off Ubuntu, but are you using a different web server than Apache?

    Thanks for your help, great find with the javascript-delay getting the charts to render!

  4. Unsa

    Hi,
    I tried ur solution but its not working

  5. mezaga

    Thank you! How do you propose though to do it, if there is more than one google graph integrated into the page?

Leave a Reply

Your e-mail address will not be published.