Skip to content

Commit

Permalink
Merge pull request #594 from tjwudi/diwu/feature/date-range-selector
Browse files Browse the repository at this point in the history
Feature: date range selector support for charts
  • Loading branch information
arikfr committed Nov 3, 2015
2 parents 0bc9fc1 + 410c567 commit 67aecc0
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 28 deletions.
3 changes: 2 additions & 1 deletion rd_ui/app/index.html
Expand Up @@ -160,7 +160,7 @@
<script src="/bower_components/bucky/bucky.js"></script>
<script src="/bower_components/pace/pace.js"></script>
<script src="/bower_components/mustache/mustache.js"></script>
<script src="/bower_components/canvg/rgbcolor.js"></script>
<script src="/bower_components/canvg/rgbcolor.js"></script>
<script src="/bower_components/canvg/StackBlur.js"></script>
<script src="/bower_components/canvg/canvg.js"></script>
<script src="/bower_components/leaflet/dist/leaflet.js"></script>
Expand Down Expand Up @@ -190,6 +190,7 @@
<script src="/scripts/visualizations/box.js"></script>
<script src="/scripts/visualizations/table.js"></script>
<script src="/scripts/visualizations/pivot.js"></script>
<script src="/scripts/visualizations/date_range_selector.js"></script>
<script src="/scripts/directives/directives.js"></script>
<script src="/scripts/directives/query_directives.js"></script>
<script src="/scripts/directives/data_source_directives.js"></script>
Expand Down
54 changes: 36 additions & 18 deletions rd_ui/app/scripts/services/resources.js
Expand Up @@ -186,9 +186,38 @@
}

return this.filteredData;
};

/**
* Helper function to add a point into a series, also checks whether the point is within dateRange
*/
QueryResult.prototype._addPointToSeriesIfInDateRange = function (point, seriesCollection, seriesName, dateRange) {
if (dateRange && moment.isMoment(point.x)) {
// if dateRange is provided and x Axis is of type datetime
if (point.x.isBefore(dateRange.min) || point.x.isAfter(dateRange.max)) {
// if the point's date isn't within dateRange, then we will not add this point to series
return;
}
}
this._addPointToSeries(point, seriesCollection, seriesName);
}

QueryResult.prototype.getChartData = function (mapping) {
/**
* Helper function to add a point into a series
*/
QueryResult.prototype._addPointToSeries = function (point, seriesCollection, seriesName) {
if (seriesCollection[seriesName] == undefined) {
seriesCollection[seriesName] = {
name: seriesName,
type: 'column',
data: []
};
}

seriesCollection[seriesName]['data'].push(point);
};

QueryResult.prototype.getChartData = function (mapping, dateRange) {
var series = {};

_.each(this.getData(), function (row) {
Expand Down Expand Up @@ -229,26 +258,15 @@
}
});

var addPointToSeries = function (seriesName, point) {
if (series[seriesName] == undefined) {
series[seriesName] = {
name: seriesName,
type: 'column',
data: []
}
}

series[seriesName]['data'].push(point);
}

if (seriesName === undefined) {
_.each(yValues, function (yValue, seriesName) {
addPointToSeries(seriesName, {'x': xValue, 'y': yValue});
});
} else {
addPointToSeries(seriesName, point);
this._addPointToSeriesIfInDateRange({'x': xValue, 'y': yValue}, series, seriesName, dateRange);
}.bind(this));
}
});
else {
this._addPointToSeriesIfInDateRange(point, series, seriesName, dateRange);
}
}.bind(this));

return _.values(series);
};
Expand Down
61 changes: 54 additions & 7 deletions rd_ui/app/scripts/visualizations/chart.js
Expand Up @@ -27,31 +27,62 @@
queryResult: '=',
options: '=?'
},
template: "<chart options='chartOptions' series='chartSeries' class='graph'></chart>",
templateUrl: '/views/visualizations/chart.html',
replace: false,
controller: ['$scope', function ($scope) {
$scope.chartSeries = [];
$scope.chartOptions = {};
$scope.dateRangeEnabled = $scope.options.xAxis && $scope.options.xAxis.type === 'datetime';
$scope.dateRange = { min: moment('1970-01-01'), max: moment() };

/**
* Update date range by finding date extremes
*
* ISSUE: chart.getExtreme() does not support getting Moment object out of box
* TODO: Find a faster way to do this
*/
var setDateRangeToExtreme = function (allSeries) {
if ($scope.dateRangeEnabled && allSeries && allSeries.length > 0) {
$scope.dateRange = {
min: moment.min.apply(undefined, _.map(allSeries, function (series) {
return moment.min(_.pluck(series.data, 'x'));
})),
max: moment.max.apply(undefined, _.map(allSeries, function (series) {
return moment.max(_.pluck(series.data, 'x'));
}))
};
}
};

var reloadData = function(data) {
var reloadData = function(data, options) {
options = options || {};
if (!data || ($scope.queryResult && $scope.queryResult.getData()) == null) {
$scope.chartSeries.splice(0, $scope.chartSeries.length);
} else {
$scope.chartSeries.splice(0, $scope.chartSeries.length);

_.each($scope.queryResult.getChartData($scope.options.columnMapping), function (s) {
var allSeries = $scope.queryResult.getChartData(
$scope.options.columnMapping,
$scope.dateRangeEnabled ? $scope.dateRange : null
);

_.each(allSeries, function (series) {
var additional = {'stacking': 'normal'};
if ('globalSeriesType' in $scope.options) {
additional['type'] = $scope.options.globalSeriesType;
}
if ($scope.options.seriesOptions && $scope.options.seriesOptions[s.name]) {
additional = $scope.options.seriesOptions[s.name];
if ($scope.options.seriesOptions && $scope.options.seriesOptions[series.name]) {
additional = $scope.options.seriesOptions[series.name];
if (!additional.name || additional.name == "") {
additional.name = s.name;
additional.name = series.name;
}
}
$scope.chartSeries.push(_.extend(s, additional));
$scope.chartSeries.push(_.extend(series, additional));
});

if (!options.preventSetExtreme) {
setDateRangeToExtreme(allSeries);
}
};
};

Expand All @@ -73,6 +104,22 @@
$scope.$watch('queryResult && queryResult.getData()', function (data) {
reloadData(data);
});

$scope.$watch('dateRange.min', function(minDateRange, oldMinDateRange) {
if (!minDateRange.isSame(oldMinDateRange)) {
reloadData(true, {
preventSetExtreme: true
});
}
});

$scope.$watch('dateRange.max', function (maxDateRange, oldMaxDateRange) {
if (!maxDateRange.isSame(oldMaxDateRange)) {
reloadData(true, {
preventSetExtreme: true
});
}
});
}]
};
});
Expand Down
43 changes: 43 additions & 0 deletions rd_ui/app/scripts/visualizations/date_range_selector.js
@@ -0,0 +1,43 @@
(function (window) {
var module = angular.module('redash.visualization');

module.directive('dateRangeSelector', [function () {
return {
restrict: 'E',
scope: {
dateRange: "="
},
templateUrl: '/views/visualizations/date_range_selector.html',
replace: true,
controller: ['$scope', function ($scope) {
$scope.dateRangeHuman = {
min: null,
max: null
};

$scope.$watch('dateRange', function (dateRange, oldDateRange, scope) {
scope.dateRangeHuman.min = dateRange.min.format('YYYY-MM-DD');
scope.dateRangeHuman.max = dateRange.max.format('YYYY-MM-DD');
});

$scope.$watch('dateRangeHuman', function (dateRangeHuman, oldDateRangeHuman, scope) {
var newDateRangeMin = moment(dateRangeHuman.min);
var newDateRangeMax = moment(dateRangeHuman.max);
if (!newDateRangeMin ||
!newDateRangeMax ||
!newDateRangeMin.isValid() ||
!newDateRangeMax.isValid() ||
newDateRangeMin.isAfter(newDateRangeMax)) {
// Prevent invalid date input
// No need to show up a notification to user here, it will be too noisy.
// Instead, simply preventing changes to the scope silently.
scope.dateRangeHuman = oldDateRangeHuman;
return;
}
scope.dateRange.min = newDateRangeMin;
scope.dateRange.max = newDateRangeMax;
}, true);
}]
}
}]);
})(window);
8 changes: 8 additions & 0 deletions rd_ui/app/views/visualizations/chart.html
@@ -0,0 +1,8 @@
<div>
<section class="clearfix">
<date-range-selector ng-if="dateRangeEnabled" date-range='dateRange' class='pull-right'></date-range-selector>
</section>
<section>
<chart options='chartOptions' series='chartSeries' class='graph'></chart>
</section>
</div>
8 changes: 8 additions & 0 deletions rd_ui/app/views/visualizations/date_range_selector.html
@@ -0,0 +1,8 @@
<div>
<span>
From <input type="date" ng-model="dateRangeHuman.min">
</span>
<span>
To <input type="date" ng-model="dateRangeHuman.max">
</span>
</div>
4 changes: 2 additions & 2 deletions rd_ui/bower.json
Expand Up @@ -10,8 +10,8 @@
"jquery": "1.9.1",
"bootstrap": "3.0.0",
"es5-shim": "2.0.8",
"angular-moment": "0.2.0",
"moment": "2.1.0",
"angular-moment": "0.10.3",
"moment": "~2.8.0",
"codemirror": "4.8.0",
"highcharts": "3.0.10",
"underscore": "1.5.1",
Expand Down

0 comments on commit 67aecc0

Please sign in to comment.