Skip to content
Print

A Wicket API for Google Charts

12
Dec
2007

Google made the headlines last week with their announcement of a brand new API for graphical display of data, supporting several different display types (line, bar, pie, etc).  The API (such as it is) works by taking different parameters as part of a URL and then generating a PNG chart based on the data.  For example:

http://chart.apis.google.com/chart?cht=p3&chd=s:hW&chs=250x100&chl=Hello|World

Great, so now you all know that I can read publicly available websites.  What’s cool here is I can tweak the graph however I please, just by messing with the URL:

http://chart.apis.google.com/chart?cht=p3&chd=s:hWj&chs=250x100&chl=Hello|Chicago|London

Pretty magical!  But aside from playing with different ways to represent useless information in 3D, it’s hard to imagine actually using it in one of your own web applications.  Oh sure, maybe you’ll employ it to generate the odd plot for your blog now and again, but for your really solid business needs, you’re going to stick with something which has a slightly more developer-friendly API.

I was pondering different excuses I could use to convince myself to try this new tool somewhere when it struck me: what about Wicket?  Wicket’s entire structure is based around extreme component extensibility.  The framework is designed to allow developers to create their own third-party components and use them as easily as those in the core Wicket API.  In fact, to even use Wicket at all requires the creation of custom components, implicitly or otherwise.

So the idea is to create a nice, object-oriented Chart component backed by Google Charts and usable in any Wicket project.  The API should follow the conventions laid down by the Wicket API itself, and be relatively easy to understand as well.  :-)   Obviously the Google Charts URL “API” follows a very strict set of constraints, thus it should be possible to render some sort of object-oriented MVC representation of a chart down into the required URL.  Thanks to Wicket componentization, it should even be possible to seamlessly utilize the component within a standard page.

I took some time today, and managed to prototype a fully-functional version of just such an API.  Cleverly enough, I’m calling it “wicket-googlecharts”.  Thanks to the inherent complexities of charting and the difficulties of intuitively mapping the concepts into an object-oriented hierarchy, the API is still a bit odd.  However, I’m fairly confident that it’s easier than doing the URLs by hand:

IChartData data = new AbstractChartData() {
    public double[][] getData() {
        return new double[][] {{34, 22}};
    }
};
 
ChartProvider provider = new ChartProvider(new Dimension(250, 100), 
        ChartType.PIE_3D, data);
provider.setPieLabels(new String[] {"Hello", "World"});
 
add(new Chart("helloWorld", provider));
 
data = new AbstractChartData() {
    public double[][] getData() {
        return new double[][] {{34, 30, 38, 38, 41, 22, 41, 44, 38, 29}};
    }
};
 
provider = new ChartProvider(new Dimension(200, 125), ChartType.LINE, data);
 
ChartAxis axis = new ChartAxis(ChartAxisType.BOTTOM);
axis.setLabels(new String[] {"Mar", "Apr", "May", "June", "July"});
provider.addAxis(axis);
 
axis = new ChartAxis(ChartAxisType.LEFT);
axis.setLabels(new String[] {null, "50 Kb"});
provider.addAxis(axis);
 
add(new Chart("lineHelloWorld", provider));

And the HTML:

<html xmlns:wicket="http://wicket.apache.org">
    <body>
        <h2>Hello World</h2>
 
        <img wicket:id="helloWorld"/>
 
        <h2>Line Hello World</h2>
 
        <img wicket:id="lineHelloWorld"/>
    </body>
</html>

The resulting charts look like this:

    

I know, pretty much the same charts that we have above. Not terribly impressive.  What should be impressive is that all of this was configured using Java.  I didn’t have to understand the Google Charts URL structure.  I didn’t have to even think about what goes on behind the scenes.  In fact, as far as the API is concerned, there could be an entirely different chart generating engine working under the surface, the developer doesn’t care.

Architecture

The real component of interest here is the Chart component that we add to the enclosing container at two different points (one instance for each chart).  This is where the actual work goes on, transforming the object hierarchy into a properly formatted URL. 

The class itself is surprisingly simple.  Basically it’s just a bunch of logic that runs through the hierarchy represented in IChartProvider (and yes, I am following the Wicket convention and using interfaces everywhere).  Chart contains almost all of the semantics of the Google Charts API itself, providing a nice separation of concerns from a maintainability standpoint.  This way, if Google changes the API down the road (and you know they will), it’s a simple matter of tweaking the Chart class, allowing the rest of the hierarchy to remain untouched.

As far as Wicket is concerned, here’s the only interesting bit in the entire API:

@Override
protected void onComponentTag(ComponentTag tag) {
    checkComponentTag(tag, "img");
    super.onComponentTag(tag);
 
    tag.put("src", constructURL());
}

Devilishly clever, I know.  See how incredibly easy it is to write your own Wicket component?  Practically speaking, there’s almost nothing going on here.  All we do is listen for the onComponentTag event, verify that we are indeed working with an <img/> tag, modify the src attribute to some generated URL and we’re home free!  I really hate to go on and on about this, but the Wicket devs really deserve their props for making a very slick and extensible API.  Anyway, back to the charts mechanism…

That’s really about the only earth-shattering bit of code in the entire chart API.  constructURL just has a set of all of the attributes in which Google Charts is interested.  It blindly runs through these attributes, checking corresponding values in the IChartProvider instance.  If something is non-null, it’s run through a basic rendering algorithm (dependant on what attribute it is) and a properly formatted character sequence is spit out the other end.  Baby stuff.

More API

One thing that’s worth drawing attention to is that I tried to stick with Java-conventional values within the chart model rather than the more normal HTML values.  For example, setting the first two graph colors might look something like this:

provider.setColors(new Color[] {Color.RED, new Color(255, 0, 255, 127});

Notice the extra integer value in the second color?  Because the API is using proper java.awt.Color instances, we can specify colors not just in RGB, but in full ARGB (the ‘A’ stands for “alpha”), allowing transparency.  Alex Blewitt has an example of dubious usefulness which shows how this can be applied.

Of course, the full API is far too extensive to cover in a non-trivial blog post (much less a single night’s hard coding).  However, I did whip up a demo page that I’ve been using to test the framework.  It’s not hosted live right now, but I did upload the fully-rendered HTML.  Sources for this particular page are also available (java, html).

More importantly, I took the time to pilfer a build script from another project of mine and actually build a proper distributable for the library.  Both tarball and zip archive are available.  Go nuts!

Oh, one more thing…  I assume I don’t have to define the words “untested”, “prototype” and “danger-will-robinson”.  Just remember I warned you if your server inexplicably turns into a piece of fairy cake.

Update: The project has been released as a wicket-stuff subproject. You can get the source via SVN at this URL: https://wicket-stuff.svn.sourceforge.net/svnroot/wicket-stuff/trunk/wicket-googlecharts

Comments

  1. daniel, you beat me to it ;)
    nicely done…

    Cheers,
    Gerolf

    Gerolf Seitz Wednesday, December 12, 2007 at 1:31 am
  2. I didn’t say it was useful, just that it could be done :-) If you wanted to have the same chart shown on multiple pages, but each with their own background colour, then having a transparent background could be useful. It could also be used to have an image on the graph which might be useful for superimposing a company logo, for example.

    The actual example I showed was just to prove a point :-)

    Alex Blewitt Wednesday, December 12, 2007 at 3:39 am
  3. You could add this as a wicket stuff project?

    Johan Compagner Thursday, December 13, 2007 at 5:08 am
  4. Nice – you beat me to it as well ;-)

    Mark Derricutt Friday, December 14, 2007 at 3:33 pm
  5. Sweet! Very nicely put together, it will fit perfectly with my little hobby project, displaying humidity and temperature graphs.

    Per Ejeklint Friday, January 18, 2008 at 5:44 am
  6. Great work!

    If it’s ok with you I’d like to use your “sample” code in my project: http://mareco.sourceforge.net/site/index.html

    I had to fix just one thing – you did not make any of your classes Serializable, and wicket requires that everything in the pages be Serializable.

    Thanks,
    Amir

    Amir Kibbar Sunday, January 20, 2008 at 2:32 am
  7. Ah, good point on the serialization thing! I’ll fix that in trunk/

    The project sources have been released into the wicket-stuff project, licensed under Apache License 2.0. In other words, use away! :-)

    Daniel Spiewak Sunday, January 20, 2008 at 11:18 am
  8. Daniel,

    I’ve checked out your code from the wicket-stuff project and added Serialization all over the place.

    I’ve also created a patch that you can simply apply and commit – where can I send it?

    thanks,
    Amir

    Amir Kibbar Thursday, January 24, 2008 at 5:59 am
  9. djspiewak AT gmail DOT com

    Thanks for doing the patch, I just never got around to fixing it all myself.

    Daniel Spiewak Thursday, January 24, 2008 at 8:20 am
  10. Yeah Serialization would actually be a huge plus

    Shelon Padmore Friday, June 27, 2008 at 9:18 pm
  11. Hey!
    First of all nice work!
    I am wondering, do you have a full example on how to use your code? I am not sure how I actually send the charts to be made. In your code above, there is this method add(Chart) which I am not sure where is located.

    Anyhow, a full example would help

    Thanks :)

    Adrian Wednesday, July 23, 2008 at 4:23 pm
  12. The zip (as well as the wicket-stuff SVN) does contain the full example that I used for testing. To answer your question though, the chart isn’t “sent to be made”, the Chart component merely constructs an <img/> with the appropriate URL. Thus, Google handles all the details of making and caching the chart image.

    Daniel Spiewak Wednesday, July 23, 2008 at 4:54 pm
  13. Hi Daniel, do you have any plans for updating to the latest incarnation of the Google Charts? There are some nice new things with it, like google-o-meter and maps. I did a QAD addition on my own but felt that the overall architecture should be considered to keep code clean. Which I had no time to think more about. :-)

    Per Ejeklint Monday, July 28, 2008 at 7:09 am
  14. I would love to update the API, but I just don’t have time. :-( The code is all in the wicket-stuff SVN though, so you’re perfectly free to make changes directly within the API itself (rather than separate additions). Amir Kibbar also has a fork of the project maintained on his site (see above in comments). Not sure if he’s done much with it other than add serialization, but it might be worth checking out.

    Daniel Spiewak Monday, July 28, 2008 at 11:12 am

Post a Comment

Comments are automatically formatted. Markup are either stripped or will cause large blocks of text to be eaten, depending on the phase of the moon. Code snippets should be wrapped in <pre>...</pre> tags. Indentation within pre tags will be preserved, and most instances of "<" and ">" will work without a problem.

Please note that first-time commenters are moderated, so don't panic if your comment doesn't appear immediately.

*
*