summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Wall <richard@aziz>2010-04-12 02:41:24 +0100
committerRichard Wall <richard@aziz>2010-04-12 02:41:24 +0100
commit936f85faa33fb7781565f8b650c9554f3125d067 (patch)
tree1e4cb89299e5172734e3ac4da8ecb116b67b3796
parente5716002c8d9cc092bd4ee87db9c9b5551f41309 (diff)
Add argument validation, a time range form and various docs and comments
-rw-r--r--LICENSE20
-rw-r--r--index.html72
-rw-r--r--jrrd.js73
3 files changed, 133 insertions, 32 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3402ea0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2010 Richard Wall <richard (at) the-moon.net>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/index.html b/index.html
index d52776b..810e1f0 100644
--- a/index.html
+++ b/index.html
@@ -5,6 +5,14 @@
<title>untitled</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<style type="text/css">
+ body {
+ font-family: sans;
+ }
+
+ form div {
+ text-align: center;
+ }
+
.chart {
width:800px;
height:200px;
@@ -114,11 +122,47 @@
return c;
}
+ var ChartCoordinator = function(ui) {
+ this.ui = ui;
+ this.charts = [];
+
+ var self = this;
+ this.ui.bind('submit', function(e) {
+ self.update();
+ return false;
+ });
+
+ this.ui.bind('reset', function(e) {
+ self.reset();
+ return false;
+ });
+ };
+
+ ChartCoordinator.prototype.update = function() {
+ var startTime = new Date(this.ui[0].startTime.value);
+ var endTime = new Date(this.ui[0].endTime.value);
+ for(var i=0; i<this.charts.length; i++){
+ this.charts[i].draw(startTime, endTime);
+ }
+ };
+
+ ChartCoordinator.prototype.setTimeRange = function(startTime, endTime) {
+ 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();
+ };
+
+ ChartCoordinator.prototype.reset = function() {
+ this.setTimeRange(new Date(new Date().getTime()-1*60*60*1000),
+ new Date());
+ };
+
$(function() {
+ var cc = new ChartCoordinator($('.chartRangeControl'));
var chartTemplate = $('.chart').remove();
- var charts = [
- dnsChartFactory(
- chartTemplate.clone().appendTo('.charts')),
+ cc.charts = [
+ //dnsChartFactory(
+ // chartTemplate.clone().appendTo('.charts')),
loadChartFactory(
chartTemplate.clone().appendTo('.charts')),
@@ -133,23 +177,25 @@
chartTemplate.clone().appendTo('.charts'))
];
- jQuery.each(charts, function(i, chart) {
- chart.draw(new Date('10 April 2010 19:30:00'),
- new Date());
- });
+ cc.reset();
- $('.chart').bind("plotselected", function(event, ranges) {
- var startTime = new Date(ranges.xaxis.from);
- var endTime = new Date(ranges.xaxis.to);
- jQuery.each(charts, function(i, chart) {
- chart.draw(startTime, endTime);
- });
+ $('.charts').bind("plotselected", function(event, ranges) {
+ cc.setTimeRange(new Date(ranges.xaxis.from),
+ new Date(ranges.xaxis.to));
});
});
</script>
</head>
<body>
+ <form method="GET" class="chartRangeControl">
+ <div>
+ <label>Start: <input type="text" name="startTime" /></label>
+ <label>End: <input type="text" name="endTime" /></label>
+ <input type="submit" value="Update" />
+ <input type="reset" value="Reset" />
+ </div>
+ </form>
<div class="charts">
<div class="chart"></div>
</div>
diff --git a/jrrd.js b/jrrd.js
index 9104875..9cc7580 100644
--- a/jrrd.js
+++ b/jrrd.js
@@ -1,3 +1,13 @@
+/* Copyright (c) 2010 Richard Wall <richard (at) the-moon.net>
+ * See LICENSE for details.
+ *
+ * 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/
+ */
if(typeof jrrd == 'undefined') {
var jrrd = {};
@@ -38,46 +48,71 @@ jrrd.downloadBinary = function(url) {
return d;
};
-
+/**
+ * A wrapper around an instance of javascriptrrd.RRDFile which provides a
+ * convenient way to query the RRDFile based on time range, RRD data source (DS)
+ * and RRD consolidation function (CF).
+ *
+ * @param startTime: A javascript {Date} instance representing the start of query
+ * time range, or {null} to return earliest available data.
+ * @param endTime: A javascript {Date} instance representing the end of query
+ * time range, or {null} to return latest available data.
+ * @param dsId: A {String} name of an RRD DS or an {Int} DS index number or
+ * {null} to return the first available DS.
+ * @param cfName: A {String} name of an RRD consolidation function
+ * @return: A flot compatible data series object
+ **/
jrrd.RrdQuery = function(rrd) {
this.rrd = rrd;
};
-jrrd.RrdQuery.prototype.getData = function(startTime, endTime, dsId) {
+jrrd.RrdQuery.prototype.getData = function(startTime, endTime, dsId, cfName) {
var startTimestamp = startTime.getTime()/1000;
- var endTimestamp = endTime.getTime()/1000;
+
+ var lastUpdated = this.rrd.getLastUpdate();
+ var endTimestamp = lastUpdated;
+ if(endTime) {
+ endTimestamp = endTime.getTime()/1000;
+ // If end time stamp is beyond the range of this rrd then reset it
+ if(lastUpdated < endTimestamp) {
+ endTimestamp = lastUpdated;
+ }
+ }
if(dsId == null) {
dsId = 0;
}
var ds = this.rrd.getDS(dsId);
- var consolidationFunc = 'AVERAGE';
- var lastUpdated = this.rrd.getLastUpdate();
- // If end time stamp is beyond the range of this rrd then reset it
- if(lastUpdated < endTimestamp) {
- endTimestamp = lastUpdated;
+ if(cfName == null) {
+ cfName = 'AVERAGE';
}
- var bestRRA = null;
+
+ var rra, step, rraRowCount, firstUpdated;
for(var i=0; i<this.rrd.getNrRRAs(); i++) {
// Look through all RRAs looking for the most suitable
// data resolution.
var rra = this.rrd.getRRA(i);
- if(rra.getCFName() != consolidationFunc) {
+ // If this rra doesn't use the requested CF then move on to the next.
+ if(rra.getCFName() != cfName) {
continue;
}
- bestRRA = rra;
- var step = rra.getStep();
- var rraRowCount = rra.getNrRows();
- var firstUpdated = lastUpdated - (rraRowCount - 1) * step;
+
+ step = rra.getStep();
+ rraRowCount = rra.getNrRows();
+ firstUpdated = lastUpdated - (rraRowCount - 1) * step;
+ // We assume that the RRAs are listed in ascending order of time range,
+ // therefore the first RRA which contains the range minimum should give
+ // the highest resolution data for this range.
if(firstUpdated <= startTimestamp) {
break;
}
}
-
- if(!bestRRA) {
- throw new Error('Unrecognised consolidation function: ' + consolidationFunc);
+ // If we got to the end of the loop without ever defining step, it means
+ // that the CF check never succeded.
+ if(!step) {
+ throw new Error('Unrecognised consolidation function: ' + cfName);
}
var startRow = rraRowCount - parseInt((lastUpdated - startTimestamp)/step) - 1;
@@ -87,10 +122,10 @@ jrrd.RrdQuery.prototype.getData = function(startTime, endTime, dsId) {
var timestamp = firstUpdated + (startRow - 1) * step;
var dsIndex = ds.getIdx();
for (var i=startRow; i<=endRow; i++) {
- var val = bestRRA.getEl(i, dsIndex);
- flotData.push([timestamp*1000.0, val]);
+ flotData.push([timestamp*1000.0, rra.getEl(i, dsIndex)]);
timestamp += step;
}
+
return {label: ds.getName(), data: flotData};
};