Milimetric has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/156722

Change subject: Add visualizer to coordinate selectors and graphs
......................................................................

Add visualizer to coordinate selectors and graphs

Change-Id: I730fc02cece2d56ce165590d4cde777b2cb248be
---
M bower.json
M src/app/config.js
M src/app/data-converters/wikimetrics-timeseries.js
M src/app/require.config.js
M src/app/startup.js
D src/components/selection-visualizer/selection-visualizer.js
R src/components/wikimetrics-visualizer/wikimetrics-visualizer.html
A src/components/wikimetrics-visualizer/wikimetrics-visualizer.js
M test/SpecRunner.browser.js
A test/components/wikimetrics-visualizer.js
10 files changed, 140 insertions(+), 32 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/analytics/dashiki 
refs/changes/22/156722/1

diff --git a/bower.json b/bower.json
index 2d77283..d13ff26 100644
--- a/bower.json
+++ b/bower.json
@@ -10,6 +10,7 @@
     "topojson": "~1.6.18",
     "jquery": "^2.1.1",
     "moment": "^2.7.0",
-    "URIjs": "~1.13.2"
+    "URIjs": "~1.13.2",
+    "knockout-projections": "~1.1.0-pre"
   }
 }
diff --git a/src/app/config.js b/src/app/config.js
index 2829edc..f56db4f 100644
--- a/src/app/config.js
+++ b/src/app/config.js
@@ -5,6 +5,12 @@
     'use strict';
 
     return {
-        wikimetricsDomain : 'metrics-staging.wmflabs.org'
+        wikimetricsDomain : 'metrics-staging.wmflabs.org',
+        wikimetricsDefaultSubmetrics: {
+            NewlyRegistered: 'newly_registered',
+            RollingActiveEditor: 'rolling_active_editor',
+            PagesCreated: 'pages_created',
+            NamespaceEdits: 'edits'
+        },
     };
 });
diff --git a/src/app/data-converters/wikimetrics-timeseries.js 
b/src/app/data-converters/wikimetrics-timeseries.js
index 126c2c3..9450263 100644
--- a/src/app/data-converters/wikimetrics-timeseries.js
+++ b/src/app/data-converters/wikimetrics-timeseries.js
@@ -2,7 +2,7 @@
  * This module returns a method that knows how to translate json data from
  *   wikimetrics to the canonical timeseries format understood by dashiki
  */
-define(['moment'], function(moment) {
+define(['moment', 'config'], function(moment, config) {
 
     /**
      * Parameters
@@ -18,17 +18,11 @@
      */
     return function (rawData){
         var aggregate = 'Sum',
-            submetrics = {
-                NewlyRegistered: 'newly_registered',
-                RollingActiveEditor: 'rolling_active_editor',
-                PagesCreated: 'pages_created',
-                NamespaceEdits: 'edits'
-            },
             normalized = [],
             keys = Object.keys(rawData),
             parameters = rawData.parameters,
             metricName = parameters.Metric,
-            submetric = submetrics[metricName],
+            submetric = config.wikimetricsDefaultSubmetrics[metricName],
             i;
 
         keys.splice(keys.indexOf('parameters'), 1);
diff --git a/src/app/require.config.js b/src/app/require.config.js
index c03253c..cf621b6 100644
--- a/src/app/require.config.js
+++ b/src/app/require.config.js
@@ -5,13 +5,14 @@
 var require = {
     baseUrl: '.',
     paths: {
-        'jquery'    : 'bower_modules/jquery/dist/jquery',
-        'knockout'  : 'bower_modules/knockout/dist/knockout',
-        'text'      : 'bower_modules/requirejs-text/text',
-        'd3'        : 'bower_modules/d3/d3',
-        'vega'      : 'bower_modules/vega/vega',
-        'topojson'  : 'bower_modules/topojson/topojson',
-        'moment'    : 'bower_modules/moment/moment',
+        'jquery'                : 'bower_modules/jquery/dist/jquery',
+        'knockout'              : 'bower_modules/knockout/dist/knockout',
+        'knockout-projections'  : 
'bower_modules/knockout-projections/dist/knockout-projections',
+        'text'                  : 'bower_modules/requirejs-text/text',
+        'd3'                    : 'bower_modules/d3/d3',
+        'vega'                  : 'bower_modules/vega/vega',
+        'topojson'              : 'bower_modules/topojson/topojson',
+        'moment'                : 'bower_modules/moment/moment',
         // NOTE: if you want functions like uri.expand, you must include both
         // URI and URITemplate like define(['uri/URI', 'uri/URITemplate'] ...
         // because URITemplate modifies URI when it's parsed
diff --git a/src/app/startup.js b/src/app/startup.js
index 6a85bd7..5667d1e 100644
--- a/src/app/startup.js
+++ b/src/app/startup.js
@@ -4,10 +4,10 @@
 
     // register components here like
     ko.components.register('wikimetrics-layout', { require: 
'components/wikimetrics-layout/wikimetrics-layout' });
+    ko.components.register('wikimetrics-visualizer', { require: 
'components/wikimetrics-visualizer/wikimetrics-visualizer' });
     ko.components.register('project-selector', { require: 
'components/project-selector/project-selector' });
     ko.components.register('metric-selector', { require: 
'components/metric-selector/metric-selector' });
     ko.components.register('time-selector', { require: 
'components/time-selector/time-selector' });
-    ko.components.register('selection-visualizer', { require: 
'components/selection-visualizer/selection-visualizer' });
     ko.components.register('vega-timeseries', { require: 
'components/visualizers/vega-timeseries/vega-timeseries' });
 
     // Start the application
diff --git a/src/components/selection-visualizer/selection-visualizer.js 
b/src/components/selection-visualizer/selection-visualizer.js
deleted file mode 100644
index 3faa952..0000000
--- a/src/components/selection-visualizer/selection-visualizer.js
+++ /dev/null
@@ -1,14 +0,0 @@
-define(['knockout', 'text!./selection-visualizer.html'], function(ko, 
templateMarkup) {
-
-    'use strict';
-
-    function SelectionVisualizer() {
-        var self = this;
-        self.loading = ko.observable();
-    }
-
-    return {
-        viewModel: SelectionVisualizer,
-        template: templateMarkup
-    };
-});
diff --git a/src/components/selection-visualizer/selection-visualizer.html 
b/src/components/wikimetrics-visualizer/wikimetrics-visualizer.html
similarity index 100%
rename from src/components/selection-visualizer/selection-visualizer.html
rename to src/components/wikimetrics-visualizer/wikimetrics-visualizer.html
diff --git a/src/components/wikimetrics-visualizer/wikimetrics-visualizer.js 
b/src/components/wikimetrics-visualizer/wikimetrics-visualizer.js
new file mode 100644
index 0000000..69984df
--- /dev/null
+++ b/src/components/wikimetrics-visualizer/wikimetrics-visualizer.js
@@ -0,0 +1,53 @@
+define(function(require) {
+    'use strict';
+
+    var ko              = require('knockout'),
+        $               = require('jquery'),
+        d3              = require('d3'),
+        templateMarkup  = require('text!./wikimetrics-visualizer.html'),
+        api             = require('app/apis/wikimetrics'),
+        converter       = 
require('app/data-converters/wikimetrics-timeseries');
+
+    require('knockout-projections');
+
+    function Dataset(metric, project) {
+        this.metric = metric;
+        this.project = project;
+        // this is an array but we don't need to react to single value changes
+        // NOTE: this could become an array to enable real-time refreshing
+        this.data = ko.observable([]);
+
+        this.load = ko.computed(function(){
+            var self = this,
+                m = self.metric(),
+                p = self.project;
+
+            // a change has triggered this to refresh, so first empty it out
+            self.data([]);
+            api.get(m, p).pipe(converter).done(function(converted) {
+                self.data(converted);
+            });
+        }, this);
+    }
+
+    function WikimetricsVisualizer(params) {
+        var self = this;
+        $.extend(self, params);
+        self.api = api;
+        self.converter = converter;
+
+        self.datasets = self.projects.map(function(project) {
+            return new Dataset(self.metric, project);
+        });
+        self.mergedData = ko.computed(function() {
+            return d3.merge(self.datasets.map(function(set) {
+                return set.data();
+            })());
+        }, self);
+    }
+
+    return {
+        viewModel: WikimetricsVisualizer,
+        template: templateMarkup
+    };
+});
diff --git a/test/SpecRunner.browser.js b/test/SpecRunner.browser.js
index 3faf2ee..c0e3a6c 100644
--- a/test/SpecRunner.browser.js
+++ b/test/SpecRunner.browser.js
@@ -2,6 +2,7 @@
     // Reference your test modules here
     var testModules = [
         'components/wikimetrics-layout',
+        'components/wikimetrics-visualizer',
         'components/vega-timeseries',
         'app/data-converters',
         'app/apis',
diff --git a/test/components/wikimetrics-visualizer.js 
b/test/components/wikimetrics-visualizer.js
new file mode 100644
index 0000000..08810d0
--- /dev/null
+++ b/test/components/wikimetrics-visualizer.js
@@ -0,0 +1,66 @@
+define(function (require){
+    var component   = 
require('components/wikimetrics-visualizer/wikimetrics-visualizer'),
+        $           = require('jquery'),
+        ko          = require('knockout');
+
+    var WikimetricsVisualizer = component.viewModel;
+
+    describe('WikimetricsVisualizer view model', function() {
+
+        it('should transform selected projects and metrics into merged data', 
function() {
+            var cohort = 'cohort',
+                v1 = 12,
+                v2 = 1,
+                metric = 'RollingActiveEditor',
+                selectedMetric = ko.observable(),
+                selectedProjects = ko.observableArray();
+
+            var visualizer = new WikimetricsVisualizer({
+                metric: selectedMetric,
+                projects: selectedProjects,
+            });
+
+            // make a mock promise and resolve it before making api.get return 
it
+            var deferred = $.Deferred();
+            var response = {
+                'result': {
+                    'Sum': {
+                        'rolling_active_editor': {
+                            '2014-08-19 00:00:00': v2,
+                            '2014-08-18 00:00:00': v1
+                        }
+                    }
+                },
+                'parameters': {
+                    'Cohort': cohort,
+                    'Metric': metric
+                }
+            };
+            deferred.resolveWith(this, [response]);
+            sinon.stub(visualizer.api, 'get').returns(deferred.promise());
+
+            selectedMetric(metric);
+            selectedProjects.push(cohort);
+
+            expect(visualizer.mergedData().length).toEqual(2);
+            expect(visualizer.mergedData()[0].date).toEqual(new 
Date('2014-08-18 00:00:00'));
+            expect(visualizer.mergedData()[0].label).toEqual(cohort);
+            expect(visualizer.mergedData()[0].value).toEqual(v1);
+            expect(visualizer.mergedData()[1].date).toEqual(new 
Date('2014-08-19 00:00:00'));
+            expect(visualizer.mergedData()[1].label).toEqual(cohort);
+            expect(visualizer.mergedData()[1].value).toEqual(v2);
+
+            // change projects observable and make sure the merged data 
reflects it
+            var anotherCohort = 'another-cohort';
+            response.parameters.Cohort = anotherCohort;
+            selectedProjects.push(anotherCohort);
+
+            expect(visualizer.mergedData()[2].date).toEqual(new 
Date('2014-08-18 00:00:00'));
+            expect(visualizer.mergedData()[2].label).toEqual(anotherCohort);
+            expect(visualizer.mergedData()[2].value).toEqual(v1);
+            expect(visualizer.mergedData()[3].date).toEqual(new 
Date('2014-08-19 00:00:00'));
+            expect(visualizer.mergedData()[3].label).toEqual(anotherCohort);
+            expect(visualizer.mergedData()[3].value).toEqual(v2);
+        });
+    });
+});

-- 
To view, visit https://gerrit.wikimedia.org/r/156722
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I730fc02cece2d56ce165590d4cde777b2cb248be
Gerrit-PatchSet: 1
Gerrit-Project: analytics/dashiki
Gerrit-Branch: master
Gerrit-Owner: Milimetric <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to