diff --git a/src/app/components/kbn.js b/src/app/components/kbn.js index dacb59f44407a..fce760c9c2e6a 100755 --- a/src/app/components/kbn.js +++ b/src/app/components/kbn.js @@ -208,30 +208,35 @@ function($, _) { return str; }; + kbn.interval_regex = /(\d+(?:\.\d+)?)([Mwdhmsy])/; + // histogram & trends - kbn.interval_to_seconds = function(string) { - var matches = string.match(/(\d+(?:\.\d+)?)([Mwdhmsy])/); - switch (matches[2]) { - case 'y': - return matches[1]*31536000; - case 'M': - return matches[1]*2592000; - case 'w': - return matches[1]*604800; - case 'd': - return matches[1]*86400; - case 'h': - return matches[1]*3600; - case 'm': - return matches[1]*60; - case 's': - return matches[1]; + var intervals_in_seconds = { + y: 31536000, + M: 2592000, + w: 604800, + d: 86400, + h: 3600, + m: 60, + s: 1 + }; + + kbn.interval_to_ms = function(string) { + var matches = string.match(kbn.interval_regex); + if (!matches || !_.has(intervals_in_seconds, matches[2])) { + throw new Error('Invalid interval string, expexcting a number followed by one of "Mwdhmsy"'); + } else { + return intervals_in_seconds[matches[2]] * matches[1] * 1000; } }; + kbn.interval_to_seconds = function (string) { + return kbn.interval_to_ms(string)/1000; + }; + // This should go away, moment.js can do this kbn.time_ago = function(string) { - return new Date(new Date().getTime() - (kbn.interval_to_seconds(string)*1000)); + return new Date(new Date().getTime() - (kbn.interval_to_ms(string))); }; // LOL. hahahahaha. DIE. diff --git a/src/app/panels/histogram/interval.js b/src/app/panels/histogram/interval.js new file mode 100644 index 0000000000000..7ddcc52825bbc --- /dev/null +++ b/src/app/panels/histogram/interval.js @@ -0,0 +1,58 @@ +define([ + 'kbn' +], +function (kbn) { + 'use strict'; + + /** + * manages the interval logic + * @param {[type]} interval_string An interval string in the format '1m', '1y', etc + */ + function Interval(interval_string) { + this.string = interval_string; + this.ms = kbn.interval_to_ms(interval_string); + + var matches = interval_string.match(kbn.interval_regex); + this.count = parseInt(matches[1], 10); + this.type = matches[2]; + + // does the length of the interval change based on the current time? + if (this.type === 'y' || this.type === 'M') { + // we will just modify this time object rather that create a new one constantly + this.get = this.get_complex; + this.date = new Date(0); + } else { + this.get = this.get_simple; + } + } + + Interval.prototype = { + toString: function () { + return this.string; + }, + after: function(current_ms) { + return this.get(current_ms, this.count); + }, + before: function (current_ms) { + return this.get(current_ms, -this.count); + }, + get_complex: function (current, delta) { + this.date.setTime(current); + switch(this.type) { + case 'M': + this.date.setUTCMonth(this.date.getUTCMonth() + delta); + break; + case 'y': + this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); + break; + } + return this.date.getTime(); + }, + get_simple: function (current, delta) { + return current + (delta * this.ms); + } + }; + + return Interval; + +}); \ No newline at end of file diff --git a/src/app/panels/histogram/module.js b/src/app/panels/histogram/module.js index 01b5d8c0bf9a1..d29f5835a2301 100755 --- a/src/app/panels/histogram/module.js +++ b/src/app/panels/histogram/module.js @@ -339,7 +339,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) { } catch(e) {return;} // Set barwidth based on specified interval - var barwidth = kbn.interval_to_seconds(scope.panel.interval)*1000; + var barwidth = kbn.interval_to_ms(scope.panel.interval); var stack = scope.panel.stack ? true : null; @@ -401,9 +401,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) { // so that the stacking happens in the proper order var required_times = []; if (scope.data.length > 1) { - required_times = _.uniq(Array.prototype.concat.apply([], _.map(scope.data, function (query) { + required_times = Array.prototype.concat.apply([], _.map(scope.data, function (query) { return query.time_series.getOrderedTimes(); - })).sort(), true); + })); + required_times = _.uniq(required_times.sort(function (a, b) { + // decending numeric sort + return a-b; + }), true); } for (var i = 0; i < scope.data.length; i++) { diff --git a/src/app/panels/histogram/timeSeries.js b/src/app/panels/histogram/timeSeries.js index 15780551dd9e3..96054fa7d1597 100755 --- a/src/app/panels/histogram/timeSeries.js +++ b/src/app/panels/histogram/timeSeries.js @@ -1,5 +1,8 @@ -define(['underscore', 'kbn'], -function (_, kbn) { +define([ + 'underscore', + './interval' +], +function (_, Interval) { 'use strict'; var ts = {}; @@ -39,7 +42,7 @@ function (_, kbn) { }); // the expected differenece between readings. - this.interval_ms = base10Int(kbn.interval_to_seconds(opts.interval)) * 1000; + this.interval = new Interval(opts.interval); // will keep all values here, keyed by their time this._data = {}; @@ -75,7 +78,10 @@ function (_, kbn) { if (_.isArray(include)) { times = times.concat(include); } - return _.uniq(times.sort(), true); + return _.uniq(times.sort(function (a, b) { + // decending numeric sort + return a - b; + }), true); }; /** @@ -104,7 +110,7 @@ function (_, kbn) { this // context ); - // if the start and end of the pairs are inside either the start or end time, + // if the first or last pair is inside either the start or end time, // add those times to the series with null values so the graph will stretch to contain them. if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { pairs.unshift([this.start_time, null]); @@ -128,7 +134,7 @@ function (_, kbn) { // check for previous measurement if (i > 0) { prev = times[i - 1]; - expected_prev = time - this.interval_ms; + expected_prev = this.interval.before(time); if (prev < expected_prev) { result.push([expected_prev, 0]); } @@ -140,7 +146,7 @@ function (_, kbn) { // check for next measurement if (times.length > i) { next = times[i + 1]; - expected_next = time + this.interval_ms; + expected_next = this.interval.after(time); if (next > expected_next) { result.push([expected_next, 0]); } @@ -160,8 +166,8 @@ function (_, kbn) { result.push([ times[i], this._data[times[i]] || 0 ]); next = times[i + 1]; - expected_next = times[i] + this.interval_ms; - for(; times.length > i && next > expected_next; expected_next+= this.interval_ms) { + expected_next = this.interval.after(time); + for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { result.push([expected_next, 0]); } diff --git a/src/app/panels/trends/module.js b/src/app/panels/trends/module.js index e6250573bc9b1..bb0e0a2dc9574 100755 --- a/src/app/panels/trends/module.js +++ b/src/app/panels/trends/module.js @@ -80,8 +80,8 @@ function (angular, app, _, kbn) { $scope.time = filterSrv.timeRange('min'); $scope.old_time = { - from : new Date($scope.time.from.getTime() - kbn.interval_to_seconds($scope.panel.ago)*1000), - to : new Date($scope.time.to.getTime() - kbn.interval_to_seconds($scope.panel.ago)*1000) + from : new Date($scope.time.from.getTime() - kbn.interval_to_ms($scope.panel.ago)), + to : new Date($scope.time.to.getTime() - kbn.interval_to_ms($scope.panel.ago)) }; var _segment = _.isUndefined(segment) ? 0 : segment;