Adding Charts to a Coconut Application

Charts can be integrated into Coconut using a variety of mature JavaScript charting libraries. For an application in Uganda we developed a dashboard that features charts rendered using the D3 javascript library. The library provides a powerful set of functions that can be used by Coconut applications to make it easier for users to interpret data.

Image demonstrating the use of charts in Coconut.

 Making sure all the data arrives when needed

The charts are activated in the home route. Coconut uses Jquery’s deferred.promise() capability to ensure that all of the data, which is assembled from asynchronous queries to CouchDB views, is available when rendering the charts.

The following sites were very helpful in explaining how to use deferreds:

A side benefit of using deferreds is that the code is alot simpler. You do not have to nest each asynchronous call.

The following code from app.js home route queries two CouchDB views and stores the data in the deferred object:

var reportEducationInstance = new ReportCollection();
reportEducationInstance.db["view"] =
["byDepartmentEducation?reduce=true&group_level=2"];
reportEducationInstance.deferred = reportEducationInstance.fetch({
success: function() {
},
error: function() {
console.log("Error loading Report: " + arguments);
}
});

var reportHealthInstance = new ReportCollection();
reportHealthInstance.db["view"] =
["byDepartmentHealth?reduce=true&group_level=2"];
reportHealthInstance.deferred = reportHealthInstance.fetch({
success: function() {
},
error: function() {
console.log("Error loading Report: " + arguments);
}
});

Data from the views is then added to the HomeView (home route in app.js)

 var page = new Page({
    content: "Default List of Incidents:"
});
 (new HomeView(
{
    model: page,
    el: $("#homePageView"),
    reportEducationInstance: reportEducationInstance,
    reportHealthInstance: reportHealthInstance,
    reportWorksInstance: reportWorksInstance,
    reportOtherInstance: reportOtherInstance
}
)).render();

In the render method in HomeView.js, the jquery when() “waits” until all of those deferred fields are complete before continuing. It is executing the callback when the deferred objects are either resolved or fail.

$.when(this.options.reportEducationInstance.deferred,
this.options.reportHealthInstance.deferred,
this.options.reportWorksInstance.deferred,
this.options.reportOtherInstance.deferred)
.then(function(countData, countData2, worksData, otherData) {
    var departmentReport = new Object({
        date: null,
        education: null,
        health: null,
        works: null,
        other: null
    });
    var reportDate = new Date();
    var education = parseData(reportDate, countData[0]);
    departmentReport.education = education;
    var health = parseData(reportDate, countData2[0]);
    departmentReport.health = health;
    var works = parseData(reportDate, worksData[0]);
    departmentReport.works = works;
    var other = parseData(reportDate, otherData[0]);
    departmentReport.other = other;
    bulletChart(departmentReport);
    rendercharts();
})
.fail(function() {
    console.log('I fire if one or more requests failed.');
});

The code in this page is used to prepare the bullet chart “Cases Per Department” displayed on the lower half of the dashboard screenshot. The code in coco-charts.js has examples of two charts: