Using Google Visualization with wkhtmltopdf

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!

3 Comments

  1. Diego Delon said:

    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.

    September 25, 2014
    Reply
  2. Jesse Sternberg said:

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

    June 23, 2016
    Reply
  3. Furbee said:

    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!

    December 1, 2016
    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *