Render charts on the server

Render charts on the server, Highcharts blog
Please note that the technology discussed in this article has been upgraded. For more information, please visit Introducing the Node.js Export Server. 

 

We’re proud to present our new feature, true server side generation of charts without the use of a web client. It’s the perfect solution for email and report generation.

The export module has always been an important feature for Highcharts. With this module, your users can download an image copy of a chart. This image is generated by the browser post an SVG file to the export server where it generates an image in the desired format and returns it for download. However, until now, a browser was required in order to generate the SVG and send the post.

DOWNLOADS RELATED TO THIS ARTICLE

RUNNING HIGHCHARTS ON THE SERVER SIDE

We have released a script which makes it possible to run Highcharts on the server. Why?

  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

For running Highcharts on the server, we need to emulate a browser environment on the server. For this, we use PhantomJS, a headless WebKit with JavaScript API. The Phantom process takes our highcharts-convert.js script as an argument plus command line parameters. With the command line parameters, we pass over the Highcharts configuration, the name of the output file and parameters for the graphical layout. Example usage:

phantomjs highcharts-convert.js -infile options.json -outfile chart.png -scale 2.5 -width 300 -constr Chart -callback callback.js

For a detailed explanation of the parameters, see Example usage of PhantomJS.

ALSO FEATURED ON THE EXPORT SERVER

We included the above PhantomJS script also on the Java-based export server and with this, you can POST a Highcharts configuration to the export server and return an image of the chart. The chart is created and rendered on the server.

An online demo with a GUI can be viewed at export.highcharts.com/demo. For an overview of possible POST parameters, see here

See for a schematic overview of the architecture the image here below.

DEFINING THE RIGHT COMBINATION OF TOOLS

We came across a lot of tools when searching for the optimal solution for running Highcharts server side. Here is an overview of our findings:

Batik and Rhino + env.js or jsdom
env.js or jsdom have no good concept of the box-model. We ran into problems when placing labels because we couldn’t get SVG’s getBBox method to work reliably.
PhantomJS in PHP
Call PhantomJS with the highcharts-convert.js script from PHP and let PhantomJS convert JSON or SVG files to different image formats. Although local benchmarks show a great performance of rasterizing with PhantomJS, in production we ran into trouble when converting SVG files with more than 1500 data points. It simply took too long time in our server environment, perhaps due to creating files locally and the number of concurrent users?
Imagemagick, PhantomJS in PHP
The idea was to let PhantomJS generate the SVG file and let ImageMagick do the image conversion. In production, we couldn’t get Imagemagick (version 6.8) to run stable on the server. Approximately once a day CPU went up to 100% and we had to restart the export server. We followed up several hints found on forums, like compiling natively and setting specific settings, but in the end, we gave up. Another disadvantage was that semi-transparent shapes where rasterized in PDF export. This is better handled in Batik.

This search resulted in using Batik natively in a Java web application which calls Phantom via a system command. We’re quite satisfied with the result of the produced images, response time and stability. Probably a combination of PhantomJS and Batik in PHP would also be a good choice, but we preferred to run Batik natively and avoid creation of temporary files. If you would like to setup your own Highcharts export-server, see here for an installation description.

After a period of time we came to the conclusion that we don’t need BATIK any longer. All request are now forwarded to PhantomJS

Example usage of PhantomJS and highcharts-convert.js

phantomjs highcharts-convert.js -infile options1.json -outfile chart1.png -scale 2.5 -width 300 -constr Chart -callback callback.js

Description of command line parameters

-infileThe file to convert, the script have to find if this is a javascript file with a options object or a svg file.  It checks the input file for beginning with “<svg”, “<?xml” or “<!doctype”. Then it’s a svg file, otherwise it’s presumed to be an options file.
-outfileThe file to output. Must be a filename with the extension .jpg, .png .pdf or .svg.
-typeThe type can be of jpg, png, pfd or svg. Ignored when outfile is defined. This is used when specifying the outfile has no usage. For example in servermode, when the output isn’t a file but a 64bit string. When not running in servermode the file is stored in ‘tmpdir’
-scaleTo set the zoomFactor of the page rendered by PhantomJs. For example, if the chart.width option in the chart configuration is set to 600 and the scale is set to 2, the output raster image will have a pixel width of 1200. So this is a convenient way of increasing the resolution without decreasing the font size and line widths in the chart. This is ignored if the -width parameter is set.
-widthSet the exact pixel width of the exported image or pdf. This overrides the -scale parameter.
-constrThe constructor name. Can be one of Chart or StockChart. This depends on whether you want to generate Highstock or basic Highcharts.
-callbackFilename containing a callback JavaScript. The callback is a function which will be called in the constructor of Highcharts to be executed on chart load. All code of the callback must be enclosed by a function. Example of contents of the callback file:

function(chart) {
    chart.renderer.arc(200, 150, 100, 50, -Math.PI, 0).attr({
        fill : '#FCFFC5',
        stroke : 'black',
        'stroke-width' : 1
     }).add();
}
-hostSpecify the host for running the script as an lightweight http-server. The server responds to JSON objects send to the server in a POST
-portSpecify the port which the http-server listens on.
-tmpdirSpecify where the scipt stores temporary- or output files, when output isn’t defined.

 

DESCRIPTION OF POST PARAMETERS FOR THE HIGHCHARTS EXPORT SERVER

svgThe string representation of a SVG file you want to export. Can be overridden by the options parameter.
optionsUse this parameter if you want to create a graph out of a Highcharts configuration. The options are sent as a JSON string. This parameter overrides the svg option.
typeThe content-type of the file to output. Can be one of ‘image/png’, ‘image/jpeg’, ‘application/pdf’, or ‘image/svg+xml’.
filenameThe name of the exported file. Defaults to ‘Chart’.
scaleTo scale the original SVG. For example, if the chart.width option in the chart configuration is set to 600 and the scale is set to 2, the output raster image will have a pixel width of 1200. So this is a convenient way of increasing the resolution without decreasing the font size and line widths in the chart. This is ignored if the -width parameter is set. For now we allow a maximum scaling of 4. This is for ensuring a good repsonse time. Scaling is a bit resource intensive.
widthSet the exact pixel width of the exported image or pdf. This overrides the -scale parameter. The maximum allowed width is 2000px
constrThe constructor name. Can be one of ‘Chart’ or ‘StockChart’. This depends on whether you want to generate Highstock or basic Highcharts. Only applicable when using this in combination with the options parameter.
callbackString containing a callback JavaScript. The callback is a function which will be called in the constructor of Highcharts to be executed on chart load. All code of the callback must be enclosed by a function. Only applicable when using this in combination with the optionsparameter. Example of contents of the callback file:

function(chart) {
    chart.renderer.arc(200, 150, 100, 50, -Math.PI, 0).attr({
        fill : '#FCFFC5',
        stroke : 'black',
        'stroke-width' : 1
     }).add();
}
asyncCan be of true or false. Default is false. When setting async to true a download link is returned to the client, instead of an image. This download link can be reused for 30 seconds. After that, the file will be deleted from the server. See these example to get an idea of what you can do with async downloading. https://jsfiddle.net/highcharts/DXQSU/ and https://jsfiddle.net/highcharts/fFPNP/