From e2899b98bff45514fddb437557d61813f08b424c Mon Sep 17 00:00:00 2001 From: Joe Tarricone Date: Fri, 25 Aug 2017 16:24:17 -0400 Subject: [PATCH 01/12] Implement "sliding" navigation --- src/mmw/js/src/compare/models.js | 6 +- .../src/compare/templates/compareWindow2.html | 4 +- src/mmw/js/src/compare/views.js | 70 ++++++++++++++++++- 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/mmw/js/src/compare/models.js b/src/mmw/js/src/compare/models.js index 7165133a4..4db957d0f 100644 --- a/src/mmw/js/src/compare/models.js +++ b/src/mmw/js/src/compare/models.js @@ -6,7 +6,9 @@ var _ = require('lodash'), ControlsCollection = require('../modeling/models').ModelPackageControlsCollection; var CHART = 'chart', - TABLE = 'table'; + TABLE = 'table', + CHART_AXIS_WIDTH = 82, + COMPARE_COLUMN_WIDTH = 134; var ChartRowModel = Backbone.Model.extend({ defaults: { @@ -225,5 +227,7 @@ module.exports = { constants: { CHART: CHART, TABLE: TABLE, + CHART_AXIS_WIDTH: CHART_AXIS_WIDTH, + COMPARE_COLUMN_WIDTH: COMPARE_COLUMN_WIDTH, }, }; diff --git a/src/mmw/js/src/compare/templates/compareWindow2.html b/src/mmw/js/src/compare/templates/compareWindow2.html index 8ff3999df..cbe8f3775 100644 --- a/src/mmw/js/src/compare/templates/compareWindow2.html +++ b/src/mmw/js/src/compare/templates/compareWindow2.html @@ -22,10 +22,10 @@

Scenarios

- -
diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 74c27e31d..7114653fc 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -35,10 +35,14 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ ui: { closeButton: '.compare-close > button', + nextButton: '.compare-scenario-buttons > .btn-next-scenario', + prevButton: '.compare-scenario-buttons > .btn-prev-scenario', }, events: _.defaults({ 'click @ui.closeButton': 'hide', + 'click @ui.nextButton' : 'nextScenario', + 'click @ui.prevButton' : 'prevScenario', }, modalViews.ModalBaseView.prototype.events), modelEvents: { @@ -90,6 +94,69 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ onModalHidden: function() { App.rootView.compareRegion.empty(); }, + + nextScenario: function() { + var currMargin = + parseInt( + $('.compare-scenario-row-content-container' + + ' > .compare-scenario-row-content', this.$el) + .css('margin-left')), + parentWidth = + parseInt( + $('.compare-scenario-row-content-container', this.$el) + .css('width')), + componentWidth = + (this.model.get('scenarios').length * models.constants.COMPARE_COLUMN_WIDTH); + + if ((componentWidth - 14) > parentWidth) { + var newMargin = _.max( + [currMargin - models.constants.COMPARE_COLUMN_WIDTH, + -(componentWidth * (1 / (componentWidth / parentWidth)))]); + + $('.compare-scenarios' + + ' > .compare-scenario-row-content-container' + + ' > .compare-scenario-row-content', this.$el) + .css({ + 'margin-left': newMargin.toString() + 'px', + 'transition': 'all 0.3s ease-in-out', + }); + + $('.compare-chart-row' + + ' > .compare-scenario-row-content-container' + + ' > .compare-scenario-row-content', this.$el) + .css({ + 'margin-left': newMargin.toString() + 'px', + 'transition': 'all 0.3s ease-in-out', + }); + } + }, + + prevScenario: function() { + var currMargin = + parseInt( + $('.compare-scenario-row-content-container' + + ' > .compare-scenario-row-content', this.$el) + .css('margin-left')); + + var maxMargin = 0; + var newMargin = _.min([currMargin + models.constants.COMPARE_COLUMN_WIDTH, maxMargin]); + + $('.compare-scenarios' + + ' > .compare-scenario-row-content-container' + + ' > .compare-scenario-row-content', this.$el) + .css({ + 'margin-left': newMargin.toString() + 'px', + 'transition': 'all 0.3s ease-in-out', + }); + + $('.compare-chart-row' + + ' > .compare-scenario-row-content-container' + + ' > .compare-scenario-row-content', this.$el) + .css({ + 'margin-left': newMargin.toString() + 'px', + 'transition': 'all 0.3s ease-in-out', + }); + }, }); var TabPanelView = Marionette.ItemView.extend({ @@ -300,8 +367,9 @@ var ChartRowView = Marionette.ItemView.extend({ }), }]; + $(chartEl.parentNode).css({ 'width': ((_.size(this.model.get('values')) * models.constants.COMPARE_COLUMN_WIDTH + models.constants.CHART_AXIS_WIDTH) + 'px') }); chart.renderCompareMultibarChart( - chartEl, name, label, colors, stacked, yMax, data); + chartEl, name, label, colors, stacked, yMax, data, models.constants.COMPARE_COLUMN_WIDTH, models.constants.CHART_AXIS_WIDTH); }, }); From 7dc8e907f79904063e9983fb6e232f933d708ba2 Mon Sep 17 00:00:00 2001 From: Joe Tarricone Date: Fri, 25 Aug 2017 16:24:36 -0400 Subject: [PATCH 02/12] Parameterize chart widths --- src/mmw/js/src/core/chart.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mmw/js/src/core/chart.js b/src/mmw/js/src/core/chart.js index 261715d8f..d14b862a9 100644 --- a/src/mmw/js/src/core/chart.js +++ b/src/mmw/js/src/core/chart.js @@ -314,15 +314,13 @@ function renderLineChart(chartEl, data, options) { }); } -function renderCompareMultibarChart(chartEl, name, label, colors, stacked, yMax, data) { +function renderCompareMultibarChart(chartEl, name, label, colors, stacked, yMax, data, columnWidth, xAxisWidth) { var options = { margin: { top: 20, bottom: 20, left: 60, }, - minBarWidth: 120, - maxBarWidth: 150, }, yTickFormat = stacked ? '0.1f' : yFormat(), chart = nv.models.multiBarChart(), @@ -330,9 +328,10 @@ function renderCompareMultibarChart(chartEl, name, label, colors, stacked, yMax, $svg = $(svg); function setChartWidth() { - var scenariosWidth = (document.getElementById('compare-title-row').offsetWidth + 100); - chartEl.style.width = scenariosWidth + "px"; + var scenarioCount = _.size(_.head(data).values), + scenariosWidth = scenarioCount * columnWidth + xAxisWidth; + chartEl.style.width = scenariosWidth + "px"; chart.width(chartEl.offsetWidth); } From efec820fdb0cfb7e1194af345a65399460a10b49 Mon Sep 17 00:00:00 2001 From: Joe Tarricone Date: Fri, 25 Aug 2017 16:25:18 -0400 Subject: [PATCH 03/12] Update styles --- src/mmw/sass/pages/_compare.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mmw/sass/pages/_compare.scss b/src/mmw/sass/pages/_compare.scss index 4e0723080..ac7ef5e5a 100644 --- a/src/mmw/sass/pages/_compare.scss +++ b/src/mmw/sass/pages/_compare.scss @@ -493,7 +493,7 @@ $compare-chart-table-height: calc(100vh - #{$height-lg} - #{$compare-footer-heig .compare-scenario-row-content { flex: 1; display: flex; - flex-wrap: nowrap; + flex-flow: row nowrap; } .compare-scenario-samplechartplaceholder { From c2dc821973dcd031303111824375110099e47573 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 16:54:16 -0400 Subject: [PATCH 04/12] Improved chart scrolling Now the axis always remains in view, and overflowing charts vanish into nothingness. --- src/mmw/js/src/compare/views.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 7114653fc..70f5acb38 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -106,7 +106,8 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ $('.compare-scenario-row-content-container', this.$el) .css('width')), componentWidth = - (this.model.get('scenarios').length * models.constants.COMPARE_COLUMN_WIDTH); + (this.model.get('scenarios').length * models.constants.COMPARE_COLUMN_WIDTH), + hiddenCols = parseInt(-1 * currMargin / models.constants.COMPARE_COLUMN_WIDTH + 1); if ((componentWidth - 14) > parentWidth) { var newMargin = _.max( @@ -128,6 +129,16 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ 'margin-left': newMargin.toString() + 'px', 'transition': 'all 0.3s ease-in-out', }); + + this.$('.nvd3.nv-wrap.nv-axis').css({ + 'transform': 'translate(' + (-newMargin).toString() + 'px)', + 'transition': 'all 0.3s ease-in-out', + }); + + this.$('.nv-group > rect:nth-child(-1n + ' + hiddenCols.toString() + ')').css({ + 'opacity': 0, + 'transition': 'all 0.3s ease-in-out', + }); } }, @@ -141,6 +152,8 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ var maxMargin = 0; var newMargin = _.min([currMargin + models.constants.COMPARE_COLUMN_WIDTH, maxMargin]); + var shownCols = parseInt(-1 * currMargin / models.constants.COMPARE_COLUMN_WIDTH); + $('.compare-scenarios' + ' > .compare-scenario-row-content-container' + ' > .compare-scenario-row-content', this.$el) @@ -156,6 +169,16 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ 'margin-left': newMargin.toString() + 'px', 'transition': 'all 0.3s ease-in-out', }); + + this.$('.nvd3.nv-wrap.nv-axis').css({ + 'transform': 'translate(' + (-newMargin).toString() + 'px)', + 'transition': 'all 0.3s ease-in-out', + }); + + this.$('.nv-group > rect:nth-child(n + ' + shownCols.toString() + ')').css({ + 'opacity': 1, + 'transition': 'all 0.3s ease-in-out', + }); }, }); From 0da77c7e74ffb642277299a1b963a79a8e2910d9 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 17:56:11 -0400 Subject: [PATCH 05/12] Refactor styling, simplify JavaScript Styles that don't need to by dynamically applied are moved to static SCSS. JavaScript expressions are reduced to simpler forms. --- src/mmw/js/src/compare/views.js | 10 +--------- src/mmw/sass/pages/_compare.scss | 9 +++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 70f5acb38..6177ba918 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -112,14 +112,13 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ if ((componentWidth - 14) > parentWidth) { var newMargin = _.max( [currMargin - models.constants.COMPARE_COLUMN_WIDTH, - -(componentWidth * (1 / (componentWidth / parentWidth)))]); + -(parentWidth)]); $('.compare-scenarios' + ' > .compare-scenario-row-content-container' + ' > .compare-scenario-row-content', this.$el) .css({ 'margin-left': newMargin.toString() + 'px', - 'transition': 'all 0.3s ease-in-out', }); $('.compare-chart-row' + @@ -127,17 +126,14 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ ' > .compare-scenario-row-content', this.$el) .css({ 'margin-left': newMargin.toString() + 'px', - 'transition': 'all 0.3s ease-in-out', }); this.$('.nvd3.nv-wrap.nv-axis').css({ 'transform': 'translate(' + (-newMargin).toString() + 'px)', - 'transition': 'all 0.3s ease-in-out', }); this.$('.nv-group > rect:nth-child(-1n + ' + hiddenCols.toString() + ')').css({ 'opacity': 0, - 'transition': 'all 0.3s ease-in-out', }); } }, @@ -159,7 +155,6 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ ' > .compare-scenario-row-content', this.$el) .css({ 'margin-left': newMargin.toString() + 'px', - 'transition': 'all 0.3s ease-in-out', }); $('.compare-chart-row' + @@ -167,17 +162,14 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ ' > .compare-scenario-row-content', this.$el) .css({ 'margin-left': newMargin.toString() + 'px', - 'transition': 'all 0.3s ease-in-out', }); this.$('.nvd3.nv-wrap.nv-axis').css({ 'transform': 'translate(' + (-newMargin).toString() + 'px)', - 'transition': 'all 0.3s ease-in-out', }); this.$('.nv-group > rect:nth-child(n + ' + shownCols.toString() + ')').css({ 'opacity': 1, - 'transition': 'all 0.3s ease-in-out', }); }, }); diff --git a/src/mmw/sass/pages/_compare.scss b/src/mmw/sass/pages/_compare.scss index ac7ef5e5a..44f4a4c5a 100644 --- a/src/mmw/sass/pages/_compare.scss +++ b/src/mmw/sass/pages/_compare.scss @@ -443,6 +443,14 @@ $compare-chart-table-height: calc(100vh - #{$height-lg} - #{$compare-footer-heig .nv-x .tick line { display: none; } + + .nvd3.nv-wrap.nv-axis { + transition: transform 0.3s ease-in-out; + } + + rect { + transition: opacity 0.3s ease-in-out; + } } .compare-scenario-gradient { @@ -494,6 +502,7 @@ $compare-chart-table-height: calc(100vh - #{$height-lg} - #{$compare-footer-heig flex: 1; display: flex; flex-flow: row nowrap; + transition: margin 0.3s ease-in-out; } .compare-scenario-samplechartplaceholder { From 198e4a2737ad8e70bbeab15742fe9532a4bcd148 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 18:36:58 -0400 Subject: [PATCH 06/12] Use model for sliding scenarios Instead of dynamically calculating the width, we count the number of scenarios, and track the left most visible one. The next and previous buttons change that value, corresponding to which the scenario row updates itself. --- src/mmw/js/src/compare/models.js | 1 + src/mmw/js/src/compare/views.js | 35 ++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/mmw/js/src/compare/models.js b/src/mmw/js/src/compare/models.js index 4db957d0f..f519bb87d 100644 --- a/src/mmw/js/src/compare/models.js +++ b/src/mmw/js/src/compare/models.js @@ -206,6 +206,7 @@ var WindowModel = Backbone.Model.extend({ mode: CHART, // or TABLE scenarios: null, // ScenariosCollection tabs: null, // TabsCollection + visibleScenarioIndex: 0, // Index of the first visible scenario }, addOrReplaceInput: function(input) { diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 6177ba918..87f7b1ee8 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -69,6 +69,7 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ model: this.model, })); this.scenariosRegion.show(new ScenariosRowView({ + model: this.model, collection: this.model.get('scenarios'), })); @@ -107,20 +108,17 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ .css('width')), componentWidth = (this.model.get('scenarios').length * models.constants.COMPARE_COLUMN_WIDTH), + lastScenario = this.model.get('scenarios').length - 1, + visibleScenarioIndex = this.model.get('visibleScenarioIndex'), hiddenCols = parseInt(-1 * currMargin / models.constants.COMPARE_COLUMN_WIDTH + 1); + this.model.set({ visibleScenarioIndex: Math.min(++visibleScenarioIndex, lastScenario) }); + if ((componentWidth - 14) > parentWidth) { var newMargin = _.max( [currMargin - models.constants.COMPARE_COLUMN_WIDTH, -(parentWidth)]); - $('.compare-scenarios' + - ' > .compare-scenario-row-content-container' + - ' > .compare-scenario-row-content', this.$el) - .css({ - 'margin-left': newMargin.toString() + 'px', - }); - $('.compare-chart-row' + ' > .compare-scenario-row-content-container' + ' > .compare-scenario-row-content', this.$el) @@ -148,14 +146,11 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ var maxMargin = 0; var newMargin = _.min([currMargin + models.constants.COMPARE_COLUMN_WIDTH, maxMargin]); + var visibleScenarioIndex = this.model.get('visibleScenarioIndex'); + var shownCols = parseInt(-1 * currMargin / models.constants.COMPARE_COLUMN_WIDTH); - $('.compare-scenarios' + - ' > .compare-scenario-row-content-container' + - ' > .compare-scenario-row-content', this.$el) - .css({ - 'margin-left': newMargin.toString() + 'px', - }); + this.model.set({ visibleScenarioIndex: Math.max(--visibleScenarioIndex, 0) }); $('.compare-chart-row' + ' > .compare-scenario-row-content-container' + @@ -337,6 +332,20 @@ var ScenarioItemView = Marionette.ItemView.extend({ var ScenariosRowView = Marionette.CollectionView.extend({ className: 'compare-scenario-row-content', childView: ScenarioItemView, + + modelEvents: { + 'change:visibleScenarioIndex': 'slide', + }, + + slide: function() { + var i = this.model.get('visibleScenarioIndex'), + width = models.constants.COMPARE_COLUMN_WIDTH, + marginLeft = -i * width; + + this.$el.css({ + 'margin-left': marginLeft + 'px', + }); + } }); var ChartRowView = Marionette.ItemView.extend({ From d8dc07fd883bfbf30fb04030c14ee6c4a5953cf3 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 18:57:01 -0400 Subject: [PATCH 07/12] Use model for sliding and hiding charts --- src/mmw/js/src/compare/views.js | 102 ++++++++++++-------------------- 1 file changed, 39 insertions(+), 63 deletions(-) diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 87f7b1ee8..a1f8039aa 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -79,6 +79,7 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ showSectionsView: function() { if (this.model.get('mode') === models.constants.CHART) { this.sectionsRegion.show(new ChartView({ + model: this.model, collection: this.model.get('tabs') .findWhere({ active: true }) .get('charts'), @@ -97,74 +98,19 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ }, nextScenario: function() { - var currMargin = - parseInt( - $('.compare-scenario-row-content-container' + - ' > .compare-scenario-row-content', this.$el) - .css('margin-left')), - parentWidth = - parseInt( - $('.compare-scenario-row-content-container', this.$el) - .css('width')), - componentWidth = - (this.model.get('scenarios').length * models.constants.COMPARE_COLUMN_WIDTH), - lastScenario = this.model.get('scenarios').length - 1, - visibleScenarioIndex = this.model.get('visibleScenarioIndex'), - hiddenCols = parseInt(-1 * currMargin / models.constants.COMPARE_COLUMN_WIDTH + 1); - - this.model.set({ visibleScenarioIndex: Math.min(++visibleScenarioIndex, lastScenario) }); - - if ((componentWidth - 14) > parentWidth) { - var newMargin = _.max( - [currMargin - models.constants.COMPARE_COLUMN_WIDTH, - -(parentWidth)]); - - $('.compare-chart-row' + - ' > .compare-scenario-row-content-container' + - ' > .compare-scenario-row-content', this.$el) - .css({ - 'margin-left': newMargin.toString() + 'px', - }); - - this.$('.nvd3.nv-wrap.nv-axis').css({ - 'transform': 'translate(' + (-newMargin).toString() + 'px)', - }); - - this.$('.nv-group > rect:nth-child(-1n + ' + hiddenCols.toString() + ')').css({ - 'opacity': 0, - }); - } + var visibleScenarioIndex = this.model.get('visibleScenarioIndex'), + last = this.model.get('scenarios').length - 1; + + this.model.set({ + visibleScenarioIndex: Math.min(++visibleScenarioIndex, last) + }); }, prevScenario: function() { - var currMargin = - parseInt( - $('.compare-scenario-row-content-container' + - ' > .compare-scenario-row-content', this.$el) - .css('margin-left')); - - var maxMargin = 0; - var newMargin = _.min([currMargin + models.constants.COMPARE_COLUMN_WIDTH, maxMargin]); - var visibleScenarioIndex = this.model.get('visibleScenarioIndex'); - var shownCols = parseInt(-1 * currMargin / models.constants.COMPARE_COLUMN_WIDTH); - - this.model.set({ visibleScenarioIndex: Math.max(--visibleScenarioIndex, 0) }); - - $('.compare-chart-row' + - ' > .compare-scenario-row-content-container' + - ' > .compare-scenario-row-content', this.$el) - .css({ - 'margin-left': newMargin.toString() + 'px', - }); - - this.$('.nvd3.nv-wrap.nv-axis').css({ - 'transform': 'translate(' + (-newMargin).toString() + 'px)', - }); - - this.$('.nv-group > rect:nth-child(n + ' + shownCols.toString() + ')').css({ - 'opacity': 1, + this.model.set({ + visibleScenarioIndex: Math.max(--visibleScenarioIndex, 0) }); }, }); @@ -399,6 +345,36 @@ var ChartRowView = Marionette.ItemView.extend({ var ChartView = Marionette.CollectionView.extend({ childView: ChartRowView, + + modelEvents: { + 'change:visibleScenarioIndex': 'slide', + }, + + slide: function() { + var i = this.model.get('visibleScenarioIndex'), + width = models.constants.COMPARE_COLUMN_WIDTH, + marginLeft = -i * width; + + // Slide charts + this.$('.compare-scenario-row-content').css({ + 'margin-left': marginLeft + 'px', + }); + + // Slide axis + this.$('.nvd3.nv-wrap.nv-axis').css({ + 'transform': 'translate(' + (-marginLeft) + 'px)', + }); + + // Show charts from visibleScenarioIndex + this.$('.nv-group > rect:nth-child(n + ' + (i+1) + ')').css({ + 'opacity': 1, + }); + + // Hide charts up to visibleScenarioIndex + this.$('.nv-group > rect:nth-child(-n + ' + i + ')').css({ + 'opacity': 0, + }); + }, }); var TableRowView = Marionette.ItemView.extend({ From c1eba50a85722e30f299c21e3b867d9ed3ba8ab1 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 19:00:56 -0400 Subject: [PATCH 08/12] Preserve slide state between tabs When switching between Runoff and Water Quality, the chart's slide state should match that of the scenarios above, which does not change when switching between tabs. --- src/mmw/js/src/compare/views.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index a1f8039aa..10ab54f4c 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -350,6 +350,11 @@ var ChartView = Marionette.CollectionView.extend({ 'change:visibleScenarioIndex': 'slide', }, + onRender: function() { + // To initialize chart correctly when switching between tabs + this.slide(); + }, + slide: function() { var i = this.model.get('visibleScenarioIndex'), width = models.constants.COMPARE_COLUMN_WIDTH, From 2d3469811990f16ef08ebba396e10b890e2cf408 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 19:24:42 -0400 Subject: [PATCH 09/12] Slide chart after rendering For cases when chart updates with new values from the server --- src/mmw/js/src/compare/views.js | 16 +++++++++++++--- src/mmw/js/src/core/chart.js | 5 +++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 10ab54f4c..d2d198f2c 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -308,7 +308,8 @@ var ChartRowView = Marionette.ItemView.extend({ }, renderChart: function() { - var chartDiv = this.model.get('chartDiv'), + var self = this, + chartDiv = this.model.get('chartDiv'), chartEl = document.getElementById(chartDiv), name = this.model.get('name'), label = this.model.get('unitLabel') + @@ -335,11 +336,15 @@ var ChartRowView = Marionette.ItemView.extend({ y: value, }; }), - }]; + }], + onRenderComplete = function() { + self.triggerMethod('chart:rendered'); + }; $(chartEl.parentNode).css({ 'width': ((_.size(this.model.get('values')) * models.constants.COMPARE_COLUMN_WIDTH + models.constants.CHART_AXIS_WIDTH) + 'px') }); chart.renderCompareMultibarChart( - chartEl, name, label, colors, stacked, yMax, data, models.constants.COMPARE_COLUMN_WIDTH, models.constants.CHART_AXIS_WIDTH); + chartEl, name, label, colors, stacked, yMax, data, + models.constants.COMPARE_COLUMN_WIDTH, models.constants.CHART_AXIS_WIDTH, onRenderComplete); }, }); @@ -355,6 +360,11 @@ var ChartView = Marionette.CollectionView.extend({ this.slide(); }, + onChildviewChartRendered: function() { + // Update chart status after it is rendered + this.slide(); + }, + slide: function() { var i = this.model.get('visibleScenarioIndex'), width = models.constants.COMPARE_COLUMN_WIDTH, diff --git a/src/mmw/js/src/core/chart.js b/src/mmw/js/src/core/chart.js index d14b862a9..e59dff9e4 100644 --- a/src/mmw/js/src/core/chart.js +++ b/src/mmw/js/src/core/chart.js @@ -314,7 +314,7 @@ function renderLineChart(chartEl, data, options) { }); } -function renderCompareMultibarChart(chartEl, name, label, colors, stacked, yMax, data, columnWidth, xAxisWidth) { +function renderCompareMultibarChart(chartEl, name, label, colors, stacked, yMax, data, columnWidth, xAxisWidth, callback) { var options = { margin: { top: 20, @@ -322,6 +322,7 @@ function renderCompareMultibarChart(chartEl, name, label, colors, stacked, yMax, left: 60, }, }, + onRenderComplete = (callback) ? callback : _.noop, yTickFormat = stacked ? '0.1f' : yFormat(), chart = nv.models.multiBarChart(), svg = makeSvg(chartEl), @@ -383,7 +384,7 @@ function renderCompareMultibarChart(chartEl, name, label, colors, stacked, yMax, .call(chart); return chart; - }); + }, onRenderComplete); } module.exports = { From 6893f898241a63f39423c4f078215dab746ef401 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 19:37:15 -0400 Subject: [PATCH 10/12] Highlight buttons correctly --- .../src/compare/templates/compareWindow2.html | 2 +- src/mmw/js/src/compare/views.js | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/mmw/js/src/compare/templates/compareWindow2.html b/src/mmw/js/src/compare/templates/compareWindow2.html index cbe8f3775..3fae396e7 100644 --- a/src/mmw/js/src/compare/templates/compareWindow2.html +++ b/src/mmw/js/src/compare/templates/compareWindow2.html @@ -25,7 +25,7 @@

Scenarios

- diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index d2d198f2c..b5a6bfeba 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -47,6 +47,7 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ modelEvents: { 'change:mode': 'showSectionsView', + 'change:visibleScenarioIndex': 'highlightButtons', }, regions: { @@ -56,6 +57,25 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ sectionsRegion: '.compare-sections', }, + highlightButtons: function() { + var i = this.model.get('visibleScenarioIndex'), + total = this.model.get('scenarios').length, + prevButton = this.ui.prevButton, + nextButton = this.ui.nextButton; + + if (i < 1) { + prevButton.removeClass('active'); + } else { + prevButton.addClass('active'); + } + + if (i + 1 >= total) { + nextButton.removeClass('active'); + } else { + nextButton.addClass('active'); + } + }, + onShow: function() { var tabPanelsView = new TabPanelsView({ collection: this.model.get('tabs'), @@ -74,6 +94,7 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ })); showSectionsView(); + this.highlightButtons(); }, showSectionsView: function() { From c2b0a9ff51f4894dfbd5df031181905bc4580850 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 19:43:06 -0400 Subject: [PATCH 11/12] Make minimum visible scenarios configurable So we can set how many we want shown at least at any time. --- src/mmw/js/src/compare/models.js | 2 ++ src/mmw/js/src/compare/views.js | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mmw/js/src/compare/models.js b/src/mmw/js/src/compare/models.js index f519bb87d..e08f4c487 100644 --- a/src/mmw/js/src/compare/models.js +++ b/src/mmw/js/src/compare/models.js @@ -7,6 +7,7 @@ var _ = require('lodash'), var CHART = 'chart', TABLE = 'table', + MIN_VISIBLE_SCENARIOS = 3, CHART_AXIS_WIDTH = 82, COMPARE_COLUMN_WIDTH = 134; @@ -228,6 +229,7 @@ module.exports = { constants: { CHART: CHART, TABLE: TABLE, + MIN_VISIBLE_SCENARIOS: MIN_VISIBLE_SCENARIOS, CHART_AXIS_WIDTH: CHART_AXIS_WIDTH, COMPARE_COLUMN_WIDTH: COMPARE_COLUMN_WIDTH, }, diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index b5a6bfeba..50ebe4e67 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -60,6 +60,7 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ highlightButtons: function() { var i = this.model.get('visibleScenarioIndex'), total = this.model.get('scenarios').length, + minScenarios = models.constants.MIN_VISIBLE_SCENARIOS, prevButton = this.ui.prevButton, nextButton = this.ui.nextButton; @@ -69,7 +70,7 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ prevButton.addClass('active'); } - if (i + 1 >= total) { + if (i + minScenarios >= total) { nextButton.removeClass('active'); } else { nextButton.addClass('active'); @@ -120,7 +121,8 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ nextScenario: function() { var visibleScenarioIndex = this.model.get('visibleScenarioIndex'), - last = this.model.get('scenarios').length - 1; + last = Math.max(0, this.model.get('scenarios').length - + models.constants.MIN_VISIBLE_SCENARIOS); this.model.set({ visibleScenarioIndex: Math.min(++visibleScenarioIndex, last) From a77a473b9bc99dc8c4510d3a4a1d569092dd36b5 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 20:05:06 -0400 Subject: [PATCH 12/12] Slide table and preserve state --- src/mmw/js/src/compare/views.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 50ebe4e67..fe8aa7b34 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -108,6 +108,7 @@ var CompareWindow2 = modalViews.ModalBaseView.extend({ })); } else { this.sectionsRegion.show(new TableView({ + model: this.model, collection: this.model.get('tabs') .findWhere({ active: true }) .get('table'), @@ -425,6 +426,26 @@ var TableView = Marionette.CollectionView.extend({ collectionEvents: { 'change': 'render', }, + + modelEvents: { + 'change:visibleScenarioIndex': 'slide', + }, + + onRender: function() { + // To initialize table correctly when switching between tabs, + // and when receiving new values from server + this.slide(); + }, + + slide: function() { + var i = this.model.get('visibleScenarioIndex'), + width = models.constants.COMPARE_COLUMN_WIDTH, + marginLeft = -i * width; + + this.$('.compare-scenario-row-content').css({ + 'margin-left': marginLeft + 'px', + }); + } }); var CompareWindow = Marionette.LayoutView.extend({