Monday, 2 March 2015

Server side chart generation using PhantomJs

If you've ever worked on visualization or currently working on one of the charting libraries , at some point of time you will be required to provide the Export as Excel or PDF option for your charts and graphs and unfortunately this feature is taken as granted by the customers or the clients. Generally if the charts are too large in number it's a good practice to build those charts at the server side and then combine it together into an excel or a pdf.

Note: The problem that most developers face is using the same charting library at the client as well as the server side. Using the same charting library will allow you to maintain uniformity among the charts.

To make this possible a full web stack was developed known as PhantomJs. It's a headless Webkit scriptable with a JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG. That means you can run HTML5 on the server without a user interface. That's kinda weird if you're reading it for the first time. But trust me this has made server-side report generation extremely flexible. That is you can use your same charting library at both the client and server side.

I will cover two of the open source charting libraries namely D3.js and Dy Charts.

Since this is a PhantomJs tutorial, I am assuming that you are comfortable with at least one of these charting libraries so I won't be explaining these in detail.

Let's get started!!!

The first thing you need to do is download the PhantomJs binary from the following link:
http://phantomjs.org/download.html

The current version as of this post is v2.0.
You can download the latest binary available.

Then you must see the phantomjs.exe file. This is the binary which we will use to run our Js scripts.
Now just to verify whether the binary works as expected copy the colorwheel.js file from the examples folder into the current directory (containing the phantomjs executable)

Note: Throughout the entire tutorial we will be using the same directory to run our js files

Now Press Shift + Right Click and select the "Open the command window here...". This will launch a command prompt in the current directory. Then run the command
"phantomjs colorwheel.js". If everything goes well you should see a colorwheel.png file being generated. Open the image and it should look something like this:



All Good???

Excellent. Now first we'll create a simple bar chart using D3.js library.


phantom.libraryPath = ".";

var page = require('webpage').create();
page.viewportSize = { width: 400, height : 400 };
page.content = '<html><body></body></html>';

var isSuccessful = page.injectJs('d3.v3.min.js');

if(isSuccessful){

        page.evaluate(function() {
var dataset = [ 5, 10, 15, 20, 25 ];

d3.select("body").selectAll("div")
.data(dataset)
.enter()
.append("div")


.style("height", function(d) {
var barHeight = d * 5;
return barHeight + "px";
})
.style("width", 20 + "px")
.style("background-color", 'teal')
.style("display", 'inline-block')
.style('margin-right',  2 + "px");
});

    document.body.style.backgroundColor = 'white';
    document.body.style.margin = '0px';

page.render('d3.png');

phantom.exit();
}




To run this code, save it as d3Chart.js and using the command window run the following command:
> phantomjs d3Chart.js

You should see a d3.png image being generated in your current directory. When you view the image you should see a simple bar chart.

Now lets go through the code step by step.
Talking about the code we first create a web page object which we will use for rendering the d3 charts. Then we define the width and height of the page and some basic HTML tags. Next we will inject the d3.v3.min.js library using the injectJs method of the phantom library. 

Notice in the first line we've given a "."(dot) as the libraryPath of phantom. Here dot refers to the current directory. This is where the phantomJs library searches for the files(mostly Js files) and injects them while rendering the charts.

Note: The libraryPath variable is not generally required. If you're getting an error while injecting the Js library don't forget to define the libraryPath variable.

Once the library is successfully loaded, we are calling the evaluate function to evaluate Javascript code in the context of the web page. This execution is 'sandboxed', there is no way for the code to access any JavaScript objects and variables outside its own page context.
Inside the evaluate function we are creating a simple bar chart in d3. Then we are just defining a margin and giving a background color to the page document.

Note: If you're new to d3 and want to know more about this charting library you can read one of my other blogs: http://maharshi-d3-tuts.blogspot.in/

Next we will render the page as an image by passing in the name of the image to the page.render function. Finally, we are calling the exit function of phantom to terminate the execution. Note
it is very important to call phantom.exit at some point in the script, otherwise phantomJs will not be terminated at all.


Next we'll create a simple multi line chart using Dy charts.


phantom.libraryPath = ".";

var page = require('webpage').create();
page.viewportSize = { width: 400, height : 400 };
page.content = '<html><body><div id="surface"></div></body></html>';

var isSuccessful = page.injectJs('dygraph-combined.js');

if(isSuccessful){

        page.evaluate(function() {
g = new Dygraph(document.getElementById("surface"),
              [
                [1,10,100],
                [2,20,80],
                [3,50,60],
                [4,70,80]
              ],
              {
                labels: [ "x", "A", "B" ]
              });

});

    document.body.style.backgroundColor = 'white';
    document.body.style.margin = '0px';

page.render('dy.png');

phantom.exit();

}


Similarly to run this code, save it in a file dyCharts.js and run it using the command line as
> phantomjs dyCharts.js

Note here that the phantom code is the same as that for the d3 chart. The only difference is the way we are generating the charts. Here we are creating a Dygraph object and passing in some of the parameters such as data and label for demo purpose. Also notice that Dy charts require a div element for the chart generation which we've defined in the page content method.

Done!!!
Now you must be thinking how is this chart generated at the server side because we've used command line to generate all those charts and You are correct! Until now we've only seen how to generate charts using phantomJs library. To do so at the server side, we'll have to run the phantomjs executable using a server-side scripting language.

Since this post has come too far, I will give you folks a break and explain the server side generation part in my next post.
Keep Reading!!!

In case you've got any doubts do comment below and I'll be happy to help :)

No comments:

Post a Comment