summaryrefslogtreecommitdiff
path: root/jrrd.js
diff options
context:
space:
mode:
Diffstat (limited to 'jrrd.js')
-rw-r--r--jrrd.js149
1 files changed, 143 insertions, 6 deletions
diff --git a/jrrd.js b/jrrd.js
index 5fcb670..3f9070a 100644
--- a/jrrd.js
+++ b/jrrd.js
@@ -4,15 +4,27 @@
* Wrappers and convenience fuctions for working with the javascriptRRD, jQuery,
* and flot charting packages.
*
- * javascriptRRD - http://javascriptrrd.sourceforge.net/
- * jQuery - http://jquery.com/
- * flot - http://code.google.com/p/flot/
+ * Designed to work well with the RRD files generated by Collectd:
+ * - http://collectd.org/
+ *
+ * Requirements:
+ * - JavascriptRRD: http://javascriptrrd.sourceforge.net/
+ * - jQuery: http://jquery.com/
+ * - Flot: http://code.google.com/p/flot/
+ * - MochiKit.Async: http://www.mochikit.com/
*/
if(typeof jrrd == 'undefined') {
var jrrd = {};
}
+/**
+ * Download a binary file asynchronously using the jQuery.ajax function
+ *
+ * @param url: The url of the object to be downloaded
+ * @return: A I{MochiKit.Async.Deferred} which will callback with an instance of
+ * I{javascriptrrd.BinaryFile}
+ **/
jrrd.downloadBinary = function(url) {
var d = new MochiKit.Async.Deferred();
@@ -68,6 +80,20 @@ jrrd.RrdQuery = function(rrd, unit) {
};
jrrd.RrdQuery.prototype.getData = function(startTime, endTime, dsId, cfName) {
+ /**
+ * Generate a Flot compatible data object containing rows between start and
+ * end time. The rows are taken from the first RRA whose data spans the
+ * requested time range.
+ *
+ * @param startTime: The I{Date} start time
+ * @param endTime: The I{Date} end time
+ * @param dsId: An index I{Number} or key I{String} identifying the RRD
+ * datasource (DS).
+ * @param cfName: The name I{String} of an RRD consolidation function (CF)
+ * eg AVERAGE, MIN, MAX
+ * @return: A Flot compatible data series I{Object}
+ * eg {label:'', data:[], unit: ''}
+ **/
var startTimestamp = startTime.getTime()/1000;
var lastUpdated = this.rrd.getLastUpdate();
@@ -130,7 +156,13 @@ jrrd.RrdQuery.prototype.getData = function(startTime, endTime, dsId, cfName) {
return {label: ds.getName(), data: flotData, unit: this.unit};
};
-
+/**
+ * A wrapper around RrdQuery which provides asynchronous access to the data in a
+ * remote RRD file.
+ *
+ * @param url: The url I{String} of a remote RRD file
+ * @param unit: The unit suffix I{String} of this data eg 'bit/sec'
+ **/
jrrd.RrdQueryRemote = function(url, unit) {
this.url = url;
this.unit = unit;
@@ -139,6 +171,14 @@ jrrd.RrdQueryRemote = function(url, unit) {
};
jrrd.RrdQueryRemote.prototype.getData = function(startTime, endTime, dsId) {
+ /**
+ * Return a Flot compatible data series asynchronously.
+ *
+ * @param startTime: The start time I{Date}
+ * @param endTime: The end time I{Date}
+ * @returns: A I{MochiKit.Async.Deferred} which calls back with a flot data
+ * series object I{Object}
+ **/
var endTimestamp = endTime.getTime()/1000;
// Download the rrd if there has never been a download or if the last
@@ -180,7 +220,13 @@ jrrd.RrdQueryRemote.prototype.getData = function(startTime, endTime, dsId) {
return ret;
};
-
+/**
+ * Wraps a I{RrdQueryRemote} to provide access to a different RRD DSs within a
+ * single RrdDataSource.
+ *
+ * @param rrdQuery: An I{RrdQueryRemote}
+ * @param dsId: An index or keyname of an RRD DS
+ **/
jrrd.RrdQueryDsProxy = function(rrdQuery, dsId) {
this.rrdQuery = rrdQuery;
this.dsId = dsId;
@@ -188,21 +234,43 @@ jrrd.RrdQueryDsProxy = function(rrdQuery, dsId) {
};
jrrd.RrdQueryDsProxy.prototype.getData = function(startTime, endTime) {
+ /**
+ * Call I{RrdQueryRemote.getData} with a particular dsId
+ **/
return this.rrdQuery.getData(startTime, endTime, this.dsId);
};
+/**
+ * A class for creating a Flot chart from a series of RRD Queries
+ *
+ * @param template: A I{jQuery} containing a single element into which the chart
+ * will be drawn
+ * @param options: An I{Object} containing Flot options which describe how the
+ * chart should be drawn.
+ **/
jrrd.Chart = function(template, options) {
this.template = template;
this.options = jQuery.extend(true, {yaxis: {}}, options);
this.data = [];
var self = this;
+
+ // Listen for clicks on the legend items - onclick enable / disable the
+ // corresponding data source.
$('.legend tr', this.template[0]).live('click', function(e) {
self.switchDataEnabled($(this).children('.legendLabel').text());
self.draw();
});
+
this.options['yaxis']['ticks'] = function(axis) {
+ /**
+ * Choose a suitable SI multiplier based on the min and max values from
+ * the axis and then generate appropriate yaxis tick labels.
+ *
+ * @param axis: An I{Object} with min and max properties
+ * @return: An array of ~5 tick labels
+ **/
var siPrefixes = {
0: '',
1: 'K',
@@ -250,6 +318,16 @@ jrrd.Chart = function(template, options) {
};
jrrd.Chart.prototype.addData = function(label, db, enabled) {
+ /**
+ * Add details of a remote RRD data source whose data will be added to this
+ * chart.
+ *
+ * @param label: A I{String} label for this data which will be shown in the
+ * chart legend
+ * @param db: The url of the remote RRD database
+ * @param enabled: true if you want this data plotted on the chart, false
+ * if not.
+ **/
if(typeof enabled == 'undefined') {
enabled = true;
}
@@ -257,6 +335,12 @@ jrrd.Chart.prototype.addData = function(label, db, enabled) {
};
jrrd.Chart.prototype.switchDataEnabled = function(label) {
+ /**
+ * Enable / Disable a single data source
+ *
+ * @param label: The label I{String} of the data source to be enabled /
+ * disabled
+ **/
for(var i=0; i<this.data.length; i++) {
if(this.data[i][0] == label) {
this.data[i][2] = !this.data[i][2];
@@ -265,12 +349,26 @@ jrrd.Chart.prototype.switchDataEnabled = function(label) {
};
jrrd.Chart.prototype.setTimeRange = function(startTime, endTime) {
+ /**
+ * Alter the time range of this chart and redraw
+ *
+ * @param startTime: The start time I{Date}
+ * @param endTime: The end time I{Date}
+ **/
this.startTime = startTime;
this.endTime = endTime;
this.draw();
}
jrrd.Chart.prototype.draw = function() {
+ /**
+ * Draw the chart
+ * A 'chart_loading' event is triggered before the data is requested
+ * A 'chart_loaded' event is triggered when the chart has been drawn
+ *
+ * @return: A I{MochiKit.Async.Deferred} which calls back with the chart
+ * data when the chart has been rendered.
+ **/
this.template.trigger('chart_loading');
var result;
var results = [];
@@ -333,6 +431,7 @@ jrrd.Chart.prototype.draw = function() {
'text-align': 'right'});
self.template.append(yaxisUnitLabel);
yaxisUnitLabel.position(self.template.position());
+ return data;
}, this)
.addErrback(
function(self, failure) {
@@ -347,6 +446,15 @@ jrrd.Chart.prototype.draw = function() {
jrrd.Chart.fromRecipe = function(template, recipe) {
+ /**
+ * A factory function to generate a I{Chart} from a recipe
+ *
+ * @param template: A I{jQuery} containing the element in which the chart is
+ * drawn.
+ * @param A recipe I{Object} eg
+ * {title: '', data: [rrdUrl, rrdDs, label, unit], options: {}}
+ * @return: A I{Chart} instance
+ **/
template.find('.title').text(recipe['title']);
var c = new jrrd.Chart(template.find('.chart'), recipe['options']);
var dataDict = {};
@@ -365,20 +473,33 @@ jrrd.Chart.fromRecipe = function(template, recipe) {
}
+/**
+ * Presents the user with a form and a timeline with which they can choose a
+ * time range and co-ordinates the refreshing of a series of charts.
+ *
+ * @param ui: A one element I{jQuery} containing an input form and placeholders
+ * for the timeline and for the series of charts.
+ **/
jrrd.ChartCoordinator = function(ui) {
this.ui = ui;
this.charts = [];
var self = this;
+
+ // Update the time ranges and redraw charts when the form is submitted
this.ui.bind('submit', function(e) {
self.update();
return false;
});
+ // Reset all the charts to the default time range when the reset button is
+ // pressed.
this.ui.bind('reset', function(e) {
self.reset();
return false;
});
+
+ // Style and configuration of the range timeline
var rangePreviewOptions = {
grid: {
borderWidth: 1
@@ -400,12 +521,15 @@ jrrd.ChartCoordinator = function(ui) {
var MONTH = DAY * 31;
var YEAR = DAY * 365;
+ // Dummy data for the range timeline
var data = [
[now - WEEK, null],
[now, null]];
- this.rangePreview = $.plot(this.ui.find('.range-preview'), [data], rangePreviewOptions);
+ this.rangePreview = $.plot(this.ui.find('.range-preview'), [data],
+ rangePreviewOptions);
+ // When a selection is made on the range timeline, redraw all the charts.
this.ui.bind("plotselected", function(event, ranges) {
self.setTimeRange(new Date(ranges.xaxis.from),
new Date(ranges.xaxis.to));
@@ -413,6 +537,10 @@ jrrd.ChartCoordinator = function(ui) {
};
jrrd.ChartCoordinator.prototype.update = function() {
+ /**
+ * Grab the start and end time from the ui form, highlight the range on the
+ * range timeline and set the time range of all the charts and redraw.
+ **/
var startTime = new Date(this.ui[0].startTime.value);
var endTime = new Date(this.ui[0].endTime.value);
var ranges = {
@@ -428,12 +556,21 @@ jrrd.ChartCoordinator.prototype.update = function() {
};
jrrd.ChartCoordinator.prototype.setTimeRange = function(startTime, endTime) {
+ /**
+ * Set the start and end time fields in the form and trigger an update
+ *
+ * @param startTime: The start time I{Date}
+ * @param endTime: The end time I{Date}
+ **/
this.ui[0].startTime.value = startTime.toString().split(' ').slice(1,5).join(' ');
this.ui[0].endTime.value = endTime.toString().split(' ').slice(1,5).join(' ');
this.update();
};
jrrd.ChartCoordinator.prototype.reset = function() {
+ /**
+ * Reset all charts and the input form to the default time range - last hour
+ **/
this.setTimeRange(new Date(new Date().getTime()-1*60*60*1000),
new Date());
};