Titanium graphs with a WebView

By | February 15, 2013

HTML graphGot data to graph in Titanium? On its own, Ti doesn’t provide a graphing component. There is an iOS-only module in the Marketplace. But if you also need to support Android or want other graph types, you’re out of luck.

Fortunately, we can use the WebView, a suitable HTML graphing library, and some app-level events to rig up live graphs in our Titanium apps. The example shown here isn’t super-pretty, but it demonstrates the basic concept.

Let’s get started. First we’ll need a graphing library. Older versions of the Android browser don’t support the Canvas element. You’re probably wise to steer clear of the many Canvas-based graphing libraries (even though many of them offer stunning graphs). Instead, you’ll want to use something like flot, jqPlot, or Sparklines.

The example I’m showing here uses jqPlot. For my example, we have three TextFields in a Titanium native view. The graph is in a local HTML page loaded in a WebView. Clicking the Update button uses an app-level event to pass the fields’ data to the WebView, where local JavaScript on the page updates the graph. I’m going to assume you know the Titanium basics for creating those fields and views.

WebViews in Titanium have no direct access to the Titanium API. And the reverse is generally true. Titanium native components don’t have direct access to objects or variables defined in a WebView. We’ll use Titanium App-level events to communicate between these contexts. Let’s look first at the web view controller code:

var updateWebView = function() {
  Ti.App.fireEvent('updateGraph', {
    a: Math.floor($.a.value), 
    b: Math.floor($.b.value), 
    c: Math.floor($.c.value)});
var calcC = function() {
  $.c.value = String(Math.round(100 - $.a.value - $.b.value));

$.submit.addEventListener('click', updateWebView);
$.a.addEventListener('change', calcC);
$.b.addEventListener('change', calcC);

In that code, $.submit is our update button. When clicked, it calls the updateWebView() function, which fires an app-level event named updateGraph, passing in the values of the three text fields. (As an aside, the value of the third text field is calculated such that the sum of the three add up to 100. That’s just to make the pie chart lay out as you’d expect.)

Next, let’s look to the HTML code. Most of the contents of the app/assets/graph.html file are lifted straight from the jqPlot example. I’ve added an event listener in the head section, as shown here:

var plot;
Ti.App.addEventListener('updateGraph', function(e) {
  var newData = [['iOS',e.a],['Android',e.b],['Other',e.c]]; 
  plot1.series[0].data = newData; 

This code listens for that same updateGraph event. It receives the event data in the e object, then uses it to call the jqPlot replot() function. Again, most of this is taken from the jqPlot example code.

With this in place, enter numbers in the text fields, click Update, and the graph is redrawn with your new data. The illustrated code works in both iOS and Android (both 2.x and 4.x).

One last WebView tidbit. We can use the meta viewport tag to control scaling and “zoomability” of the web view. In my case, I wanted the HTML content to fill its parent container (the WebView), be zoomed to 100%, and not let the user zoom in or out. Check out the head section and you’ll see the meta tag I used:

<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

You can grab the full code, which I wrote for the Titanium Certified Developer course, from the Appcelerator S3 bucket. It’s an Alloy-based project. So you’ll need a recent build of Titanium Studio and the 3.0.0.GA SDK. Look to the project’s app directory for the relevant code.

As a final tip, use your mobile device to determine if a graphing library is going to work for you. Open up your device’s browser and visit the library’s samples page. If their samples display on all your target devices, you can use it in a WebView in your app.