TILDE.SE

rrdtool charts in adobe flex 2

Flattr this

RRDtool is an excellent application for storing measurement data in a effective way.
Adobe Flex 2 provides a new and exciting opportunity for web developers to access the flexibility and usability provided by Flash in an form more suited to software development. By combining the two you get a powerful data solution with excellent presentation abilities. This content requires Adobe Flash Player 9!

This article will go thru the process of creating a data source in rrdtool and then presenting this data in the simples possible way in an flex-application.

To complete this you need a server with rrdtool and php. You need to be familiar with both rrdtool and webb development in general. The php-scripts that I use are simple to follow and shouldn't be to hard to replicate in any other server side language like Java, Perl etc.

Start by setting up your server with php. Create an test.php in a directory of your choice, with the following lines: (adapt the path of rrdtool to suit your environment)

<pre><?
     system('/usr/local/bin/rrdtool --help 2>&1');
?></pre> 

When you direct your browser to this page you should get something like this:

If you don't, then you have a problem that's out of the scope of this article. And as I said before there are a number of different ways to get web access to rrdtool. Use the method you like best.

Now, let's create the data. We'll use the one in the rrdtool tutorial. Type:

rrdtool create test.rrd             \
         --start 920804400          \
         DS:speed:COUNTER:600:U:U   \
         RRA:AVERAGE:0.5:1:24       \
         RRA:AVERAGE:0.5:6:10 

That should create a file called test.rrd in your directory. Now insert some data:

rrdtool update test.rrd 920804700:12345 920805000:12357 920805300:12363
rrdtool update test.rrd 920805600:12363 920805900:12363 920806200:12373
rrdtool update test.rrd 920806500:12383 920806800:12393 920807100:12399
rrdtool update test.rrd 920807400:12405 920807700:12411 920808000:12415
rrdtool update test.rrd 920808300:12420 920808600:12422 920808900:12423

If no errors occurred you can move on to creating your XML-encoder.

Using the rrdtool xport-command we can convert a dataset to neat XML with one simple command. It's quick and provides full access to rrdtool's excellent RPN-toolset. Change the test.php page so that it reads the dataset and export the values in the speed-column as XML:

<?
     header("content-type: text/xml");
     system('/usr/local/bin/rrdtool xport --start 920804400 --end 920809200 DEF:myspeed=test.rrd:speed:AVERAGE XPORT:myspeed');
?> 

The header-line tells the browser that the information provided by this page is in the XML-format. The second line contains our xport-function with a start and stop time (again according to the tutorial) and a DEF-statement that reads the test.rrd for the average speed value. The last statement XPORT tells rrdtool to use the value myspeed as the value in the XML. Notice how similar it is to the graph-statement.

Reload the browser and you have a nice XML-version of your dataset.

Now let's move on to the flex-gui. I use Adobe flex-builder 2.0, it does cost some money, but if you are serious in your flex-development, it does save some time. There is a free 30-day trial, so you have nothing to lose trying it for a while. The SDK is free, and should get you by, but I don't know about the charting component. And yes, you will be needing it.

Download them all from Adobe.

Now let's create a new basic project in flex builder. After the hard drive is done spinning you should have something like this:

<?xml version="1.0" encoding="utf-8"?>
   <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

   </mx:Application> 

Change the application to layout=vertical, it makes it nice and simple to add elements. I use a simple panel as a base for everything. Make it 500 wide and 300 high and give it a title. Finally add a AreaChart with a width and a height of 100%. Sort of like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
  <mx:Panel title="RRDTool Chart Test" width="500" height="300" layout="vertical">
    <mx:AreaChart id="areachart1" width="100%" height="100%"/>
  </mx:Panel>
</mx:Application>

Have a look at your application now by saving it and pressing the play-button on the toolbar in flexbuilder.

You should see a nice panel with a empty chart in it. If not, check your code for errors etc.

Next step is to fill the chart with some data. We have a nice server side script with some XML-data. So lets add that.

First you need to add a component called <mx:HTTPService>, this component is responsible for collecting the XML-data and making it available to the rest of the application. We name it myRRDService for later reference and give it an url pointing to the script that we have created. Areachart gets a dataprovider pointing to the HTTPService and the property lastresult. Here you also define how deep you should travel in the data to find each row. The Areachart also gets a series specifying which value should be used for x-axis and which is for the y-axis. Finally we make the application call the function myRRDService.send() when it is done loading. This will load the XML-data from the server and update the chart. All this should look something like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="{myRRDService.send();}">
  <mx:HTTPService id="myRRDService" useProxy="false" url="http://tilde.se/rrdtoolchartsinadobeflex2/data.xml"/>
  <mx:Panel title="RRDTool Chart Test" width="500" height="300" layout="vertical">
    <mx:AreaChart id="areachart1" width="100%" height="100%" dataProvider="{myRRDService.lastResult.xport.data.row}">
      <mx:series>
        <mx:AreaSeries yField="v" xField="t" form="curve" />
      </mx:series>
    </mx:AreaChart>
  </mx:Panel>
</mx:Application>

Replace the http://tilde.se/rrdtoolchartsinadobeflex2/data.xml url with the url of your test.php. I also gave the series a curve-form, it looks much nicer.

Save the page and update your browser:

If you don't it is possible that flash is protecting your site from unwanted access. Then you might need to add a crossdomain.xml to the root of your web site, like this one: http://tilde.se/crossdomain.xml more information here.

OK, so the chart is displaying your data, but the date-axis is all wrong and the speed is actually the speed in kilometers per second. Ok, lets fix that. First lets change the speed to km/hour.

Let's change test.php and add a simple CDEF called kmh:

<?
   header("content-type: text/xml");
   system('/usr/local/bin/rrdtool xport --start 920804400 --end 920809200 DEF:myspeed=test.rrd:speed:AVERAGE CDEF:kmh=myspeed,3600,* XPORT:kmh');
?>

Don't forget to change the xport-statement in the end. Now the values looks more like the speed we know it.

OK, let's make something of these labels. The speed is simple, we just add a verticalaxis-object, a LinearAxis and a title. However the date-axis is a bit harder. RRDtool uses a unixtimestamp-format, that is seconds since January 1st 1970. Flex on the other hand is using a format which is milliseconds since January 1st 1970. Not that hard to convert, but it still needs some work. So we add a DateTimeAxis which will format the date and time in a nice and relevant way and then we add a custom parse function called myDateParseFunction. In this function we get the input string and multiply it with 1000, then we create a new date-object using the millisecond value and return it to the chart. When all is done it should look something like this:

<?xml version="1.0" encoding="utf-8"?>
  <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="{myRRDService.send();}">
  <mx:Script>
   <![CDATA[
     public function myDateParseFunction(s:String):Date {
       var newDate:Date = new Date;
       newDate.setTime(int(s)*1000);
       return newDate;
       delete newDate;
     }
   ]]>
  </mx:Script>
  <mx:HTTPService id="myRRDService" useProxy="false" url="http://tilde.se/rrdtoolchartsinadobeflex2/data2.xml"/>
  <mx:Panel title="RRDTool Chart Test" width="500" height="300" layout="vertical">
    <mx:AreaChart id="areachart1" width="100%" height="100%" showDataTips="true" dataProvider="{myRRDService.lastResult.xport.data.row}">
      <mx:verticalAxis >
        <mx:LinearAxis title="Speed kph"/>
      </mx:verticalAxis>
      <mx:horizontalAxis>
        <mx:DateTimeAxis title="When" parseFunction="myDateParseFunction" displayLocalTime="true"/>
      </mx:horizontalAxis>
      <mx:series>
        <mx:AreaSeries yField="v" xField="t" form="curve" />
      </mx:series>
    </mx:AreaChart>
  </mx:Panel>
</mx:Application> 

With all that you should get a nice and relevant date-axis. I also added the property showDataTips to give us some nice mouse-over tooltips.

Ok, that's it. You now have a functional chart with real time data from your RRDtool dataset. Below are some links for more resources regarding flex development.

Flex 2 style explorer
Flex 1.5 chart explorer
Flex Development Center
Lynda.com Flex 2 Essential Training with David Gassner