Overview | Time | Select | Simple Image | Bar Chart | Geocode

 

This example assumes that you are already familiar with the concepts from the previous examples.

The Bar Chart widget is a simple widget that uses the Google Charts API to produce bar charts based on data on the page. Since Google Charts produces bitmapped images, it does not provide interactive features such as selection.

If you have Mash Maker installed then you can try out the Bar Chart widget by comparing prices on Amazon.

Files

The Bar Chart widget is defined by the following files:

For the HTML files, open in your normal browser, and then use "View Page Source" to see the code behind the widget.

Configuration File

The Configuration File should look fairly familiar:

<widget title="Bar Chart - Google Charts"
    description="Display the data on this page using a Google Charts Bar Chart"
    icon="http://mashmaker.intel.com/icons/chart_bar.png"
    version="14">

    <feature name="resizenotify"/>

    // we don't update incrementally. The Chart widget must be manually refreshed
    <settings href="http://mashmaker.intel.com/newwidgets/googlechart_bar_settings.html"/>
    <content href="http://mashmaker.intel.com/newwidgets/googlechart_bar.html"/>
    <testsettings href="http://mashmaker.intel.com/testwidgets/googlechart_bar_settings.html"/>
    <testcontent scroll="yes" href="http://mashmaker.intel.com/testwidgets/googlechart_bar.html"/>
</widget>

The only new feature is that we use the resizenotify feature to have Mash Maker call us when the user has finished resizing the widget. We use this, rather than just listening to the window's resize event, because requesting a new chart from Google is fairly expensive, so we don't want to do it repeatedly while the user is adjusting the widget size.

Settings Panel

Like Simple Image and Select, the Bar Chart widget uses the Patterns Library to help generate its settings panel. However in this case, we use several new features:

  • We include some of our own settings in the settings table, alongside the generated ones
  • We register custom updateData and updateUi functions to syncronize these parts of our settings UI with our settings data
  • One of the slots is a multi slot, that allows the user to pick several paths (in this case the different bars to show)
Since most of the settings panel code is similar to code from Simple Image and Select, we will only show the parts that are new. You may want to open the full settings panel page and follow along through the source.

Multi Slots

The first new feature in this code is a more complex call to the Patterns Library settings function:

    var opts = {
        odd:true,
        path:true,
        slots:["x",{name:"y",mode:"multi",text:true}],
        updateData: update_data,
        updateUi: update_ui
    }
    mashmaker_patterns.itemsByProp.settings("table",opts);

The first slot is the property to use for the x axis. This is a simple text property, like we saw in Simple Image. The second property however is something rather more complex. This is a multi slot. Rather than finding just one text property on each item, we will instead look for multiple properties, where the set of properties to look for is chosen by the user.

The text field is a requirements specification, in the same format as used for getPaths. This says what kind of properties the user is allowed to pick.

The odd, updateData and updateUi fields are discussed in the next section.

Custom Settings

Sometimes it is useful to mix custom settings with auto-generated settings from the Patterns Library. In the case of the Bar Chart widget, the widget uses the Patterns Library to create the x, y, and Target Items properties, but manages its other properties itself.

The HTML for the settings panel is as follows:

  <table class="mm-table">
    <tbody id="table">
      <tr class="mm-oddrow">
        <td class="mm-name">Chart Title:</td>
        <td class="mm-val"><input type="text" class="mm-select" id="title"/></td>
      </tr>
      <tr class="mm-evenrow">
        <td class="mm-name">Axis Origin:</td>
        <td class="mm-val"><select class="mm-select" id="cliporigin">
            <option value="false">Zero</option>
            <option value="true">Minimum Value</option>
        </select></td>
      </tr>
      <tr class="mm-oddrow">
        <td class="mm-name">Orientation:</td>
        <td class="mm-val"><select class="mm-select" id="orient">
            <option value="h">Horizontal</option>
            <option value="v">Vertical</option>
        </select></td>
      </tr>
      <tr class="mm-evenrow">
        <td class="mm-name">Set Arrangement:</td>
        <td class="mm-val"><select class="mm-select" id="arrange">
            <option value="g">Side by Side</option>
            <option value="s">Stacked</option>
        </select></td>
      </tr>
      <tr class="mm-oddrow">  <!-- TODO: allow different operations on different columns -->
        <td class="mm-name">Group Operation:</td>
        <td class="mm-val"><select class="mm-select" id="op">
            <option value="avg">Mean - Average</option>
            <option value="max">Maximum</option>
            <option value="min">Minimum</option>
            <option value="rng">Range</option>
            <option value="sum">Sum</option>
            <option value="cnt">Count</option>
        </select></td>
      </tr>
      <tr class="mm-evenrow">
        <td class="mm-name">Maximum Label Length:</td>
        <td class="mm-val"><input type="text" class="mm-select" id="namelength"/></td>
      </tr>
    </tbody>
  </table>

The widget explicitly fills in table entries for the custom settings, and leaves the Patterns Library to add the remaining settings at the bottom of the table. To ensure visual consistency with the settings added by the Patterns Library, the table uses the same class names as the Patterns Library. The odd field in the options structure tells the Patterns Library whether its added settings should start with an odd or even strip, depending on which color the custom settings ended with.

These custom settings need to be synchronized with the persistent settings object that stores the settings. To do this, the widget provides updateData and updateUi functions to the Patterns Library:

function update_data(){
  global_settings.title = renul(document.getElementById("title").value);
  global_settings.cliporigin = document.getElementById("cliporigin").value == "true";
  global_settings.orient = document.getElementById("orient").value;
  global_settings.arrange = document.getElementById("arrange").value;
  global_settings.op = document.getElementById("op").value;
  global_settings.namelength = renul(document.getElementById("namelength").value);
}

function update_ui(){
  document.getElementById("title").value = denul(global_settings.title);
  document.getElementById("cliporigin").value = global_settings.cliporigin;
  document.getElementById("orient").value = global_settings.orient;
  document.getElementById("arrange").value = global_settings.arrange;
  document.getElementById("op").value = global_settings.op;
  document.getElementById("namelength").value = denul(global_settings.namelength);
}

The Patterns Library maintains a global object called global_settings that these functions should synchronize with the UI components.

Content Frame

Most of the code in the content frame concerns itself with the details of formatting data for the Google Charts API. We will focus on the code that deals with the custom settings and multi slots.

Much of the interesting code is found the googlecharts.js file, which implements functionality common for the various Google Charts widgets.

The options passed to the Patterns Library pass a setItems function, rather than the addRemoveItems function used by Simple Image. This is a simpler function that is passed all the data on the page that matches the widget's criteria, rather than describing differences from a previous data set.

    var opts = {
        path : true,
        slots : ["x",{name:"y",mode:"multi"}],
        guess: guess,
        setItems : set_items         // called when a single item is added
    };

The set_items function calls a make_url function to create the URL for the Google Chart. The make_url function in turn calls group_by_x which is the function that does the actual work of getting data from the page and understanding the Multi Slots:

function group_by_x(items){
	var groups = {};
	for(i in items){
		var item = items[i];
		var key = getstr(item.slots.x);
		if(!groups[key]) groups[key] = {};
		
		for(var j in item.slots.y){
			var col = item.slots.y[j];
			var val = to_int(col.items);
			if(!groups[key][col.path]) groups[key][col.path] = [];
			groups[key][col.path].push(val);						
		}		
	}
	return groups;
}

function getstr(x){
	if(!x) return null;
	if(!x[0]) return null;
	return x[0];
}

Here we have a list of items, similar to the items passed to Simple Image. The x slot is a normal slot following the same format we saw in Simple Image. The y slot is a multi slot, and so is a bit different.

While the value of a normal slot is just a list of strings for a single matching property. The value of a multi slot is a list of several matching property paths, with the string lists for each one, each corresponding to a property that we want to show on one of our parallel bars.

For example, the value of y might be the following:

[{path:"list price",items:["$10"]},{path:"sale price",items:["$5"]},{path:"used price",items:["$3"]}]

To use one of those custom properties we set up earlier, all we have to do is look at the same global_settings object that we referred to in the settings panel. For example the following code creates a Google Charts chart type based on the orient and arrange properties.

	args.cht="b"+global_settings.orient+global_settings.arrange;