Improved image export with PhantomJS

Posted on May 08, 2013 by Torstein Hønsi. Last modified on April 04, 2016.

We would like to announce a new release of serverside rendering by using PhantomJS. We newly added the option to start a webserver from the highcharts-convert.js script. This has been a successful approach and we decided to use this technique also for our featured Highcharts export server (only Java version). By using PhantomJS as headless browser in the export server, we have been able to improve performance and stability.

Serverside rendering revisited

With the last release of the export-server in January 2013, we already introduced serverside rendering as a new feature. This is for creating charts on the server, without a client involved. We use PhantomJS, which emulates a browser environment (Webkit) on the server. PhantomJS comes with a JavaScript API and we used this for making a script for converting our graphs to another file format. In summary it works like this; the script (highcharts-convert.js) starts a browser, opens a page with Highcharts loaded in it and produces a chart and saves it as an image, PDF or SVG.

PhantomJS is started from the command line with our highcharts-convert.js script as first parameter and with the other command line parameters we pass over the Highcharts configuration, the name of the output file and parameters for the graphical layout. Example usage on the commandline:

phantomjs highcharts-convert.js -infile options.js -outfile chart.png -scale 2.5 -width 300

With this you can for example use it for;

  1. you want to include your charts in emails or automated management reports
  2. you want to have a consistency between graphs you present on your website and your backend produced reports

NEW: Start PhantomJS as a webserver

With this new release we enhanced the existing highcharts-convert.js script, by making it optional to let it start a webserver. By doing so, we don't have to start a PhantomJS process over and over again for every conversion job and this results in a better performance. While running the script in webserver mode, the result isn’t saved to a file, but returned as a base64 string, unless when you want to export to SVG or PDF.

How to run the script as a webserver

  1. This is how you start a webserver in PhantomJS with the highcharts-convert.js script, change the host and port to your needs. However do not expose the PhantomJS webserver to the outside world, it’s not intended as a general production server.
    phantomjs highcharts-convert.js -host 127.0.0.1 -port 3003
  2. The webserver listens only to POST-requests. Use the same parameters as for command line usage, but wrap them in a JSON structure. See this example for the content of a POST request;
    "{"infile":"{xAxis: {categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']},series: [{data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]}]};","callback":"function(chart) {chart.renderer.arc(200, 150, 100, 50, -Math.PI, 0).attr({fill : '#FCFFC5',stroke : 'black','stroke-width' : 1}).add();}","constr":"Chart","outfile":"//tmp//chart.png"}"

Note that it's still possible to use the command line syntax when you don’t want to start the script as a webserver. For a more detailed explanation of how to use the script with PhantomJS read more on docs.highcharts.com

New release for the export-server

Our experience with PhantomJS have been overall positive and we decided to integrate PhantomJS in the featured Highcharts export-server. Basically we’re running the highcharts-convert.js script as a webserver and communicate with it. When the Highcharts export-server starts up we let PhantomJS start several webservers in a serverpool. This speeds up things drastically, because now we can serve requests concurrently and we benefit from not having to start a PhantomJS process for every conversion any longer.

Read more on installing and using the export server on docs.highcharts.com

Benchmarking the new server

We compared generation time with the last release with the new release. The last release uses PhantomJS for generating SVG from a Highcharts configuration and it uses Batik for converting from SVG to other file formats. The new release uses only PhantomJS for converting and simplifies the whole process. Benchmark on a local machine, just for getting an impression;

&nbspNew release, using only PhantomJS,
generation time in milliseconds
Last release using PhantomJS/Batik,
generation time in milliseconds
Small SVG to PNG 79 90
Large SVG to PNG 566 256 (faster with Batik?)
Small JSON to PNG 161 760
Large JSON to PNG 821 1480

We tested with a large file containing 2000 datapoints and a small file contained 12 points. Maybe you'll notice the longer generation time for larger SVG files. Well, I guess we have to run more benchmarks to draw a final conclusion about that. In all we recommend though, the Java Export server based on PhantomJS. We feel it's a more stable and repsonsive server. Not only by using PhantomJS, but also by implementing a serverpool. Your clients who use the export server, don't have to wait for eachother to get served anymore. And this is something you have to take into account to.