Murray Picton

How to render Fusioncharts completely on the server

I recently had a need at work where I needed to render some nice looking charts and insert them into a pdf. I found Fusioncharts after a quick search and figured these charts look good, are easy to program and provide the functionality to output to an image which is perfect to insert into a pdf. I didn’t want to render the charts on the client side as would generally be necessary with flash, as I don’t know the connection speed and capability of the clients computer. This left me with a big issue – how do you render Fusioncharts without using a client?

There are a few main issues, they are:

Setting up the system to render the charts

First step is to set up the system we are going to use to render all the charts. I generally use Unix servers, but in this situation as I need a GUI to render the Flash and a browser that I can open and close easily, I have settled with a Windows environment, specifically XP. I soon discovered that in order to render Flash, the Flash movie has to be visible on the screen. I am guessing this is a Flash performance enhancement to only load movies that can be seen, but in my situation this is a big issue (If anyone knows the real reason please let me know). To get round this, I cannot use a remote desktop connection as when you log out, there is no longer a display being used. What I needed here was a PC that is constantly left on and logged in so that Flash always renders.

Now I have my operating system sorted, I now need to decide on my browser. What I need here, is a browser that is easy to open and close through script without causing any popups and also supports the Adobe Flash plugin. What I discovered here is that Internet Explorer 7 can be opened to a specific page through the command line and, due to poor programming, can be closed through javascript (discovered after a quick search here).

This is how my system is going to work:

My Fusioncharts rendering system

My Fusioncharts rendering system

Sending the data to the system

Sending the data to the system is relatively easy. The way it is going to work is I am going to send a URL to my new rendering machine that will open in a browser window and load the page. This means that to send the data to the page, all I have to do is store it in a database and then on the client side, open a page that I can send a unique id to that recalls the data and renders the charts. To open a new ie window, there is a simple command:

C:\PROGRA~1\INTERN~1\IEXPLORE.EXE "http://www.urltogoto.com"

Here we encounter a problem – for Flash to render the charts they must be visible on the screen and this command will open Internet Explorer as a child process of our HTTP server (Apache) and keep it hidden from the UI. To get round this, I found PsTools and the contained program PsExec, this is a command line utility available for Windows that allows us to load a program as it’s own process (detached from Apache):

psexec -i -d -s C:\PROGRA~1\INTERN~1\IEXPLORE.EXE "http://www.urltogoto.com"

The options used are -i (Run the program in the UI instead of command line), -d (Don’t wait for application and continue running our process) and -s (Run in the system account). Using this tool, we can load up a page in Internet Explorer as it’s own process and using the UI so that Flash can display. Now we’re nearly ready to start our charting…

Rendering all the charts at the same time

Let’s take a look at my PHP code that will take an input of the URL to load an open an Internet Explorer window on that page:

<?php
set_time_limit(300);
$url = $_GET["url"];
$pass = $_GET["pass"];
if($pass != "8tuz#-rA7asuzaya_?RuB8*u4_ekabra=a8UpHaT") {
	exit();  //You shouldn't be here!
}
echo "1";
ignore_user_abort(true);
ob_end_flush();
flush();
ob_end_clean();
exec('psexec -i -d -s C:\PROGRA~1\INTERN~1\IEXPLORE.EXE "'.$url.'"');
?>

First of all, I set the time limit to 5 minutes – this should be long enough to render all my charts. Then, check for a password so that we are the only people that can use this. The next section before we open our Internet Explorer window is to output a 1 to the browser and flush the output so that the browser doesn’t have to wait until we finish rendering.

Now I have my internet explorer window opening, let’s take a look at how I render the chart. I am using the Fusioncharts PHP class that is provided with the product. I am going to use javascript to check the status of each chart and upload it to the server as each one completes.

My PHP, this should make sense to anyone who has used Fusioncharts (Remember to set up FCExporter.php):

<?php
$FC=new FusionCharts("Pie2D",600,425,"myChart");
$FC->setSWFPath("/path/to/fusioncharts");
$paramStr = "animation=0;startingAngle=0;showPercentValues=1;exportEnabled=1;exportAtClient=0;exportAction=save;exportHandler=http://mysite.com/FCExporter.php;";
$FC->setChartParams($paramStr);
$FC->addChartData(33, 'label=Part 1;');
$FC->addChartData(37, 'label=Part 2;');
$FC->renderChart();
?>

My Javascript:

<script type="text/javascript">
var charts = new Array;
var numberOfCharts = 1;
function FC_Rendered(DOMId) {
	charts[charts.length] = DOMId;
	if(charts.length==numberOfCharts) {
		for(i=0;i<=charts.length-1;i++) {
			chartObject = getChartFromId(charts[i]);
			chartObject.exportChart();
		}
	}
}
var exportedFiles = new Array;
var exportedStr = '';
//Callback handler method which is invoked after the chart has saved image on server.

function FC_Exported(objRtn){
	if (objRtn.statusCode=="1"){
		exportedFiles[exportedFiles.length] = objRtn;
		$.get('uploadAjax.php', {
			name: objRtn.fileName,
			domId: objRtn.DOMId
		}, function() {
			if(exportedFiles.length==numberOfCharts) {
				closeWindow(); //Close window function from earlier
			}
		}
		);
	}else{
		alert("The chart could not be saved on server. There was an error. Description : " + objRtn.statusMessage);
	}
}
</script>

This quite simply uses the methods provided by the Fusioncharts Javascript library to render all the charts one by one, and as each one completes submits the uploaded filename and DOMId to an PHP script that just submits this information to a database ready to be read out later.

One trick that I learnt quite quickly here is that I needed to have all the charts displayed at the same time on the screen. I do this by setting the Flash movies to all display as floats, on top of each other and slightly out of line with each other, the easiest way to do this was with jQuery and CSS:

<script type="text/javascript">
var left = 0;
var zindex = 10;
$(document).ready(function(){
	$('OBJECT, EMBED').each(function() {
		$(this).css('left', left);
		$(this).css('z-index', zindex);
		left = left + 10;
		zindex = zindex + 10;
	});
});
</script>
<style>
OBJECT, EMBED {
	position: absolute;
	top: 0px;
	left: 0px;
}
</style>

One final thing needs to be done to get everything rendering correctly, in the Fusioncharts PHP Class we need to add:

$strHTML .= "chart_$chartId.setTransparent(true)\n";

To the Fusioncharts_Gen.php Class on line 1562 (In the renderChartJS function).

Outputting a loading page to the user that knows how many charts have been completed

This part should be easy now once everything else has been done. Quite simply, I just write a simple PHP script that returns how many charts we currently have in the database and then on our loading page regularly check it and return the number. When we have all the charts, redirect to our next page or do whatever we want with all our charts.

So, we have all our charts rendering completely without using the client’s computer at all.

If you have liked this tutorial, please tell your friends and take a look at some of my other post. Make sure you check back soon for other great posts on loads of awesome techniques!