Open Flash Chart API, JQuery, and Drupal
Several weeks back I was charged with the task of graphically displaying various sets of statistical data for the project that I have been working on. They were looking for some simple charts and graphs to make sense of the mountains of user stats that the site collects. After researching a few solutions, I decided to go with Open Flash Chart API (OFC). A few things fueled this decision, but mainly it seemed very simple and straight forward, and the previous developer had already taken a stab at the problem using this package. However a problem quickly arose. It was necessary for me to provide some sort of navigation or "control panel" for these charts. For the expected tasks of changing the focus of the time interval (i.e. day, month, week, year, moving through the data set, etc...). As we have several graphs displaying on a page, a typical form submit was out of the question, as it would refresh the page, and generally make everything feel very kludgy. JavaScript was the obvious answer. There is a brief tutorial on manipulating OFC using AJAX, however I quickly discovered that the way that OFC is implemented in the Drupal module would not allow this type of functionality. So I thought I would share how I overcame this obstacle using a bit of jQuery.
The Open Flash Chart API module is the current port of this package to Drupal. On this site I am using the 6.x-2.9 release and the examples here will be for Drupal 6, but will work with Drupal 5 with only minor adjustments. I have a small helper module that I use for "glue" code on this site. I decided to create the graph for this example there. The module name is "zygot" and I will not change that in the code posted here, but of course you will need to when implementing this in your code (unless of course you call your module "zygot"). I will not go into how to build a graph with OFC, as there is decent documentation on this already. The graph I am using is basically the same as the on posted here. The code for this graph is as follows:
<?php //a simple function to return a random dataset function zygot_random_data() { for( $i=0; $i<6; $i++ ) { } return $data; } //this function instanciates and returns a graph object // taking a dataset(to be graphed) as a parameter function zygot_build_graph($data) { $g = new open_flash_chart_api(); $g->set_title( 'Random Data', '{font-size: 20px;}' ); $g->set_bg_colour('#FFFFFF'); $g->set_width(200); $g->set_data( $data ); $g->bar( 50, '#F87100', '#F87100', 'Page views', 10 ); $g->set_x_label_style( 10, '#000000', 0, 2 ); $g->set_y_max( 10 ); $g->y_label_steps( 4 ); $g->set_y_legend( 'Open Flash Chart', 12, '#736AFF' ); return $g->render(); } //a simple theme function to call up and display our graph passing along it's dataset parameter, // and wrapping the graph in an div function theme_zygot_graph($data) { $output = ''; $output .= '<div id="zygot">'; $output .= zygot_build_graph($data); $output .= '</div>'; return $output; } ?>
Now we simply grab some data and call our theme function
$data = zygot_random_data();
So here we have our simple graph. Now into the real meat of this problem. In this example we will simply generate new random data and update the graph without having to reload the page. To do this, as I mentioned, we need a bit of javascript. We are going to use a jQuery function called load. Which takes the HTML from a remote file (specified by the URL parameter) and inject it into a DOM element on our current page. For this to work we need to create a URL that, when called, will generate our new graph. So from here we turn to the Drupal menu system. For this example I have created a simple menu callback that will fire a function when zygot/graph is hit.
function zygot_menu() { 'title' => t('Zygot Graph'), 'page callback' => 'zygot_display_graph', 'type' => MENU_CALLBACK, ); return $items; }
The callback function grabs a new dataset and outputs the graph. Essentially this is the exact call that we made to display the graph in the first place, but this is the crucial function. In this example things are very simple, as all we are doing is creating a new random dataset. In a more realistic application this is where the various actions on your graph will be taking place. (i.e pulling new stats from the database, reworking the dataset, altering graph settings, displaying an entirely different graph, etc...)
function zygot_display_graph() { $data = zygot_random_data(); $output = zygot_build_graph($data); }
As for the javascript we will need to have some sort of event to fire our function. Click seems appropriate, and after creating a simple button and modifying our theme function a bit...
function zygot_form() { //I went ahead and placed the call to include our .js file here // so if our button is called up it comes with the necessary javascript drupal_add_js(drupal_get_path('module', 'zygot').'/zygot.js'); '#type' => 'button', '#value' => t('New Random Data'), ); return $form; } function theme_zygot_graph($data) { $output = ''; $output .= '<div id="zygot">'; $output .= '<div id="zygot-ahah">'; $output .= zygot_build_graph($data); $output .= '</div>'; $output .= drupal_get_form('zygot_form'); $output .= '</div>'; return $output; }
...we will have something to hook our javascript onto. Note that the zygot.js file is added using drupal_add_js in the form function. It isn't necessary that it be included specifically in the form function, but it should be somewhere that insures the javascript is included on our page. The zygot.js file is short and sweet:
//wait until the document has finished loading $(document).ready( function() { //we're using the Drupal given id of our form as the selector for our event $("#edit-zygot").click( function(event) { //this prevents the button from performing its default submit action event.preventDefault(); //the selector here is the div containing just the graph which will be replaced //by our new graph at zygot/graph $("#zygot-ahah").load('/zygot/graph'); }); });
So we are binding the click event to our button using the the drupal given id edit-zygot as the selector. When this event is triggered (the button is clicked) it will fire a function that interrupts the default submit action of the button, then loads our new graph, by firing our menu callback function at zygot/graph, into our zygot-aha div. Truthfully this post is really describing how to do a simple AJAX call in Drupal, more than it is about OFC. You can use this method to do a variety of things, other than simply updating a graph.
As an aside, I was very excited to implement this here on my Drupal 6 site, as I thought it would give me a chance to leverage the #ahah attribute in Drupal's new form API. It would render needing a custom .js file unnecessary. I gave it a couple goes, but soon realized that passing back javascript via JSON just wasn't going to work. I was never quite able to figure out how I could get around that, and if anyone has any thoughts or ideas on this I would love to hear it. I should also note, if it isn't obvious, that I have just a bit of CSS in play here, but only to make the graphs look better in the post. Nothing fancy.








Post new comment