Milimetric has submitted this change and it was merged.
Change subject: Add filters above timeseries graphs in the compare layout
......................................................................
Add filters above timeseries graphs in the compare layout
Bug: T104261
Change-Id: If4aab0e2537c7a08b38cf925546d747c601b78b3
---
M src/app/data-converters/timeseries-data.js
M src/app/startup.js
M src/components/a-b-compare/compare-timeseries.html
A src/components/filter-timeseries/filter-timeseries.html
A src/components/filter-timeseries/filter-timeseries.js
A src/css/066_checkbox.min.css
A src/css/067_list.min.css
M src/layouts/compare/index.html
M src/layouts/compare/index.js
M test/app/timeseries-data.js
10 files changed, 187 insertions(+), 4 deletions(-)
Approvals:
Milimetric: Verified; Looks good to me, approved
diff --git a/src/app/data-converters/timeseries-data.js
b/src/app/data-converters/timeseries-data.js
index 3347eb8..9e13fe5 100644
--- a/src/app/data-converters/timeseries-data.js
+++ b/src/app/data-converters/timeseries-data.js
@@ -168,6 +168,55 @@
};
/**
+ * Filter data by columns
+ * @param {Array} header - column names
+ * @param {Array} patternLabels - label names
+ * @return TimeseriesData
+ */
+ TimeseriesData.prototype.pickColumns = function (header, patternLabels) {
+ var self = this,
+ result = {
+ header: [],
+ colorLabels: [],
+ patternLabels: [],
+ rowsByDate: {}
+ };
+
+ _.forEach(self.rowsByDate, function (row, date) {
+ result.rowsByDate[date] = [];
+ _.forEach(self.rowsByDate[date], function() {
+ result.rowsByDate[date].push([]);
+ });
+ });
+
+ _.forEach(header, function (h, k) {
+ var i = self.header.indexOf(h);
+
+ // make sure the patternLabels also match
+ while (self.patternLabels[i] !== patternLabels[k]) {
+ i = self.header.indexOf(h, i + 1);
+ }
+
+ result.header.push(self.header[i]);
+ result.colorLabels.push(self.colorLabels[i]);
+ result.patternLabels.push(self.patternLabels[i]);
+ _.forEach(result.rowsByDate, function (row, date) {
+ _.forEach(result.rowsByDate[date], function(row2, j) {
+
result.rowsByDate[date][j].push(self.rowsByDate[date][j][i]);
+ });
+ });
+ });
+
+ return new TimeseriesData(
+ result.header,
+ result.rowsByDate,
+ result.colorLabels,
+ result.patternLabels,
+ this.duplicateDates
+ );
+ };
+
+ /**
* Materializes the lodash chainable rowsByDate property and sorts it by
date
*/
TimeseriesData.prototype.rowData = function (options) {
diff --git a/src/app/startup.js b/src/app/startup.js
index 99dd92d..6da70f7 100644
--- a/src/app/startup.js
+++ b/src/app/startup.js
@@ -39,6 +39,7 @@
ko.components.register('compare-sunburst', { require:
'components/a-b-compare/compare-sunburst' });
ko.components.register('compare-timeseries', { require:
'components/a-b-compare/compare-timeseries' });
ko.components.register('compare-stacked-bars', { require:
'components/a-b-compare/compare-stacked-bars' });
+ ko.components.register('filter-timeseries', { require:
'components/filter-timeseries/filter-timeseries' });
// *********** END Funnel Layout Components ************ //
diff --git a/src/components/a-b-compare/compare-timeseries.html
b/src/components/a-b-compare/compare-timeseries.html
index c586dbb..26b5b6b 100644
--- a/src/components/a-b-compare/compare-timeseries.html
+++ b/src/components/a-b-compare/compare-timeseries.html
@@ -1,3 +1 @@
-<!-- slow as can be and still a bit glitchy nvd3-timeseries params="height:
500, series: series, colors: colors"/-->
-<!-- much faster but glitchy: rickshaw-timeseries params="height: 500, series:
series, colors: colors"/-->
-<dygraphs-timeseries params="height: 500, data: data, colors: colors,
annotations: annotations"/>
+<filter-timeseries params="data: data, colors: colors, annotations:
annotations"></filter-timeseries>
diff --git a/src/components/filter-timeseries/filter-timeseries.html
b/src/components/filter-timeseries/filter-timeseries.html
new file mode 100644
index 0000000..4686ca3
--- /dev/null
+++ b/src/components/filter-timeseries/filter-timeseries.html
@@ -0,0 +1,19 @@
+<div class="ui basic segment">
+ <div data-bind="foreach: categorizedHeader" class="ui horizontal divided
list">
+ <div class="item">
+ <h4 data-bind="text: name"></h4>
+ <div data-bind="foreach: columns" class="ui list">
+ <div class="inline field item">
+ <div class="ui toggle checkbox">
+ <input type="checkbox" data-bind="attr: {id:
$data.uniqueId}, checked: selected"/>
+ <label data-bind="attr: {for: $data.uniqueId}">
+ <span data-bind="text: title"></span>
+ </label>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<dygraphs-timeseries params="height: 500, data: filteredData, colors: colors,
annotations: annotations" />
diff --git a/src/components/filter-timeseries/filter-timeseries.js
b/src/components/filter-timeseries/filter-timeseries.js
new file mode 100644
index 0000000..0ec4411
--- /dev/null
+++ b/src/components/filter-timeseries/filter-timeseries.js
@@ -0,0 +1,66 @@
+define(function (require) {
+ 'use strict';
+
+ var ko = require('knockout'),
+ _ = require('lodash'),
+ templateMarkup = require('text!./filter-timeseries.html');
+
+ function FilterTimeseries (params) {
+ this.data = params.data;
+
+ // turn the header into a list of items that can be selected /
deselected
+ // make it a computed so if the parent changes the data, this updates
+ this.filteredHeader = ko.computed(function () {
+ var data = ko.unwrap(this.data);
+
+ if (!data) {
+ return [];
+ }
+
+ return data.header.map(function (h, i){
+ return {
+ index: i,
+ title: h,
+ patternLabel: data.patternLabels[i],
+ name: data.patternLabels[i] + ' - ' + h,
+ uniqueId: data.patternLabels[i] + ' - ' + h +
(Math.floor(Math.random() * 100000)),
+ selected: ko.observable(true)
+ };
+ });
+ }, this);
+
+ // split up by category so we can control the display better
+ this.categorizedHeader = ko.computed(function () {
+ var header = ko.unwrap(this.filteredHeader);
+
+ return _(header).transform(function (categorized, column) {
+ categorized[column.patternLabel] =
categorized[column.patternLabel] || [];
+ categorized[column.patternLabel].push(column);
+ }, {}).transform(function (categories, columns, category) {
+ categories.push({
+ name: category,
+ columns: columns,
+ });
+ }, []).value();
+ }, this);
+
+ this.filteredData = ko.computed(function () {
+ var newHeader = _.filter(this.filteredHeader(), function (header) {
+ return header.selected();
+ });
+
+ return ko.unwrap(this.data).pickColumns(
+ _.pluck(newHeader, 'title'),
+ _.pluck(newHeader, 'patternLabel')
+ );
+ }, this);
+
+ this.colors = params.colors;
+ this.annotations = params.annotations;
+ }
+
+ return {
+ viewModel: FilterTimeseries,
+ template: templateMarkup
+ };
+});
diff --git a/src/css/066_checkbox.min.css b/src/css/066_checkbox.min.css
new file mode 120000
index 0000000..6fccd97
--- /dev/null
+++ b/src/css/066_checkbox.min.css
@@ -0,0 +1 @@
+../bower_modules/semantic/build/minified/modules/checkbox.min.css
\ No newline at end of file
diff --git a/src/css/067_list.min.css b/src/css/067_list.min.css
new file mode 120000
index 0000000..e53d4a2
--- /dev/null
+++ b/src/css/067_list.min.css
@@ -0,0 +1 @@
+../bower_modules/semantic/build/minified/views/list.min.css
\ No newline at end of file
diff --git a/src/layouts/compare/index.html b/src/layouts/compare/index.html
index 2dc7480..d81ca97 100644
--- a/src/layouts/compare/index.html
+++ b/src/layouts/compare/index.html
@@ -35,6 +35,8 @@
<link href="/src/css/063_button.min.css" rel="stylesheet">
<link href="/src/css/064_dropdown.min.css" rel="stylesheet">
<link href="/src/css/065_divider.min.css" rel="stylesheet">
+ <link href="/src/css/066_checkbox.min.css" rel="stylesheet">
+ <link href="/src/css/067_list.min.css" rel="stylesheet">
<!-- end semantic ui -->
<link href="/src/css/068_nvd3.css" rel="stylesheet">
diff --git a/src/layouts/compare/index.js b/src/layouts/compare/index.js
index b78c1fc..7f7ce48 100644
--- a/src/layouts/compare/index.js
+++ b/src/layouts/compare/index.js
@@ -19,7 +19,10 @@
// above, and group them into bundles here.
'sunburst': ['components/visualizers/sunburst/sunburst'],
'stacked-bars':
['components/visualizers/stacked-bars/stacked-bars'],
- 'dygraphs-timeseries':
['components/visualizers/dygraphs-timeseries/dygraphs-timeseries'],
+ 'filter-timeseries': [
+ 'components/filter-timeseries',
+
'components/visualizers/dygraphs-timeseries/dygraphs-timeseries'
+ ],
}
}
};
diff --git a/test/app/timeseries-data.js b/test/app/timeseries-data.js
index f1493db..cc5f210 100644
--- a/test/app/timeseries-data.js
+++ b/test/app/timeseries-data.js
@@ -175,5 +175,48 @@
t1.merge(t2);
}).toThrow('Can not be merged: has multiple rows per date.');
});
+
+ it('should filter by column', function () {
+ var header = [
+ 'bounce-rate',
+ 'not-attempted-rate',
+ 'success-rate',
+ 'failure-rate',
+ 'bounce-rate',
+ 'not-attempted-rate',
+ 'success-rate',
+ 'failure-rate'
+ ],
+ rowsByDate = {
+ '2015-04-01': [[1, 2, 3, 4, 5, 6, 7, 8]],
+ '2015-04-02': [[9, 10, 11, 12, 13, 14, 15, 16]],
+ '2015-04-03': [[17, 18, 19, 20, 21, 22, 23, 24]],
+ '2015-04-04': [[25, 26, 27, 28, 29, 30, 31, 32]]
+ },
+ colorLabels = [
+ 'bounce-rate',
+ 'not-attempted-rate',
+ 'success-rate',
+ 'failure-rate',
+ 'bounce-rate',
+ 'not-attempted-rate',
+ 'success-rate',
+ 'failure-rate'
+ ],
+ patternLabels = ['VE', 'VE', 'VE', 'VE', 'WT', 'WT', 'WT',
'WT'],
+ ts = new TimeseriesData(header, rowsByDate, colorLabels,
patternLabels),
+ filteredTs = ts.pickColumns(
+ ['success-rate', 'failure-rate'], ['VE', 'WT']);
+
+ expect(filteredTs.header).toEqual(['success-rate',
'failure-rate']);
+ expect(filteredTs.rowsByDate).toEqual({
+ '2015-04-01': [[3, 8]],
+ '2015-04-02': [[11, 16]],
+ '2015-04-03': [[19, 24]],
+ '2015-04-04': [[27, 32]]
+ });
+ expect(filteredTs.colorLabels).toEqual(['success-rate',
'failure-rate']);
+ expect(filteredTs.patternLabels).toEqual(['VE', 'WT']);
+ });
});
});
--
To view, visit https://gerrit.wikimedia.org/r/231424
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: If4aab0e2537c7a08b38cf925546d747c601b78b3
Gerrit-PatchSet: 9
Gerrit-Project: analytics/dashiki
Gerrit-Branch: master
Gerrit-Owner: Milimetric <[email protected]>
Gerrit-Reviewer: Bmansurov <[email protected]>
Gerrit-Reviewer: Milimetric <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits