From fc288fb89105eb109e63e66267cde17dc8e4c019 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Fri, 4 Aug 2017 11:58:05 -0400 Subject: [PATCH 1/5] Remove PrecipitationSynchronizer Since the new Compare View will feature a single precipitation slider, not one for each scenario, we no longer need the synchro- nization code to match them all. --- src/mmw/js/src/compare/controllers.js | 9 +--- src/mmw/js/src/compare/views.js | 5 +- src/mmw/js/src/modeling/controls.js | 77 --------------------------- 3 files changed, 2 insertions(+), 89 deletions(-) diff --git a/src/mmw/js/src/compare/controllers.js b/src/mmw/js/src/compare/controllers.js index cecf93b01..19fbf00e2 100644 --- a/src/mmw/js/src/compare/controllers.js +++ b/src/mmw/js/src/compare/controllers.js @@ -5,15 +5,9 @@ var _ = require('lodash'), router = require('../router').router, views = require('./views'), modelingModels = require('../modeling/models.js'), - modelingControls = require('../modeling/controls'), - coreUtils = require('../core/utils'), - synchronizer = modelingControls.PrecipitationSynchronizer; + coreUtils = require('../core/utils'); var CompareController = { - comparePrepare: function() { - synchronizer.on(); - }, - compare: function(projectId) { var first = null, aoi_census = null; @@ -53,7 +47,6 @@ var CompareController = { }, compareCleanUp: function() { - synchronizer.off(); App.user.off('change:guest', saveAfterLogin); App.origProject.off('change:id', updateUrl); diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 54ce4ebf8..ac6469821 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -9,7 +9,6 @@ var _ = require('lodash'), models = require('./models'), modelingModels = require('../modeling/models'), modelingViews = require('../modeling/views'), - modelingControls = require('../modeling/controls'), modConfigUtils = require('../modeling/modificationConfigUtils'), compareWindowTmpl = require('./templates/compareWindow.html'), compareWindow2Tmpl = require('./templates/compareWindow2.html'), @@ -20,8 +19,7 @@ var _ = require('lodash'), compareScenariosTmpl = require('./templates/compareScenarios.html'), compareScenarioTmpl = require('./templates/compareScenario.html'), compareModelingTmpl = require('./templates/compareModeling.html'), - compareModificationsTmpl = require('./templates/compareModifications.html'), - synchronizer = modelingControls.PrecipitationSynchronizer; + compareModificationsTmpl = require('./templates/compareModifications.html'); var CompareWindow2 = Marionette.LayoutView.extend({ template: compareWindow2Tmpl, @@ -225,7 +223,6 @@ var CompareWindow = Marionette.LayoutView.extend({ model: this.model, collection: this.model.get('scenarios') })); - synchronizer.sync(); } }); diff --git a/src/mmw/js/src/modeling/controls.js b/src/mmw/js/src/modeling/controls.js index c5a6817fa..a77dfc431 100644 --- a/src/mmw/js/src/modeling/controls.js +++ b/src/mmw/js/src/modeling/controls.js @@ -444,72 +444,6 @@ var GwlfeConservationPracticeView = ModificationsView.extend({ } }); -var PrecipitationSynchronizer = (function() { - var isEnabled = false, - precipViews = []; - - // Add a view to the list of views to be kept syncrhonized - function add(precipView) { - if (isEnabled) { - precipViews.push(precipView); - } - } - - // Remove a view from the list - function remove(precipView) { - if (isEnabled) { - precipViews = _.without(precipViews, precipView); - } - } - - // Turn synchronization on - function on() { - precipViews = []; - isEnabled = true; - } - - // Turn synchronization off - function off() { - isEnabled = false; - precipViews = []; - } - - // Synchronize the group to the given slider - function syncTo(precipView) { - if (isEnabled) { - var value = precipView.ui.slider.val(); - - isEnabled = false; - - precipViews.forEach(function(otherPrecipView) { - var otherValue = otherPrecipView.ui.slider.val(); - if (otherValue !== value) { - otherPrecipView.ui.slider.val(value); - otherPrecipView.onSliderChanged(); - } - }); - - isEnabled = true; - } - } - - // Synchronize the group to the first slider - function sync() { - if (precipViews.length > 0) { - syncTo(precipViews[0]); - } - } - - return { - add: add, - remove: remove, - on: on, - off: off, - sync: sync, - syncTo: syncTo - }; -})(); - var PrecipitationView = ControlView.extend({ template: precipitationTmpl, @@ -554,19 +488,9 @@ var PrecipitationView = ControlView.extend({ this.ui.slider.attr('value', value); this.ui.displayValue.text(this.getDisplayValue(value)); - PrecipitationSynchronizer.syncTo(this); - this.addOrReplaceInput(modification); }, - onAttach: function() { - PrecipitationSynchronizer.add(this); - }, - - onBeforeDestroy: function() { - PrecipitationSynchronizer.remove(this); - }, - onRender: function() { var model = this.controlModel, value = model && model.get('value') || 0; @@ -600,5 +524,4 @@ module.exports = { GwlfeConservationPracticeView: GwlfeConservationPracticeView, PrecipitationView: PrecipitationView, getControlView: getControlView, - PrecipitationSynchronizer: PrecipitationSynchronizer }; From 7f842118d066e18e5da147aca79e829112b8eb08 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Fri, 4 Aug 2017 16:14:50 -0400 Subject: [PATCH 2/5] Add precipitation slider to compare view This reuses the same view used for scenarios, although it will likely need some additional styling to make it look consistent. --- src/mmw/js/src/compare/models.js | 5 +++- .../src/compare/templates/compareInputs.html | 2 +- src/mmw/js/src/compare/views.js | 29 +++++++++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/mmw/js/src/compare/models.js b/src/mmw/js/src/compare/models.js index c8d675cc9..5a5b7fe8a 100644 --- a/src/mmw/js/src/compare/models.js +++ b/src/mmw/js/src/compare/models.js @@ -1,6 +1,7 @@ "use strict"; -var Backbone = require('../../shim/backbone'); +var Backbone = require('../../shim/backbone'), + ControlsCollection = require('../modeling/models').ModelPackageControlsCollection; var CHART = 'chart', TABLE = 'table'; @@ -39,6 +40,7 @@ var TabsCollection = Backbone.Collection.extend({ var WindowModel = Backbone.Model.extend({ defaults: { + controls: null, // ModelPackageControlsCollection mode: TABLE, // or CHART tabs: null, // TabsCollection }, @@ -47,6 +49,7 @@ var WindowModel = Backbone.Model.extend({ Backbone.Model.prototype.initialize.apply(this, arguments); this.set({ + controls: new ControlsCollection(attrs.controls), tabs: new TabsCollection(attrs.tabs), }); } diff --git a/src/mmw/js/src/compare/templates/compareInputs.html b/src/mmw/js/src/compare/templates/compareInputs.html index b5f802695..5d80f11a2 100644 --- a/src/mmw/js/src/compare/templates/compareInputs.html +++ b/src/mmw/js/src/compare/templates/compareInputs.html @@ -1,4 +1,4 @@ -
Precipitation -----|----
+
diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index ac6469821..5072fa360 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -9,6 +9,7 @@ var _ = require('lodash'), models = require('./models'), modelingModels = require('../modeling/models'), modelingViews = require('../modeling/views'), + PrecipitationView = require('../modeling/controls').PrecipitationView, modConfigUtils = require('../modeling/modificationConfigUtils'), compareWindowTmpl = require('./templates/compareWindow.html'), compareWindow2Tmpl = require('./templates/compareWindow2.html'), @@ -110,7 +111,7 @@ var TabPanelsView = Marionette.CollectionView.extend({ childView: TabPanelView, }); -var InputsView = Marionette.ItemView.extend({ +var InputsView = Marionette.LayoutView.extend({ template: compareInputsTmpl, ui: { @@ -123,6 +124,26 @@ var InputsView = Marionette.ItemView.extend({ 'click @ui.tableButton': 'setTableView', }, + regions: { + precipitationRegion: '.compare-precipitation', + }, + + onShow: function() { + var setPrecipitationValue = _.bind(this.setPrecipitationValue, this), + precipitationModel = this.model.get('controls') + .findWhere({ name: 'precipitation' }); + + this.precipitationRegion.show(new PrecipitationView({ + model: precipitationModel, + addOrReplaceInput: setPrecipitationValue, + })); + }, + + setPrecipitationValue: function(input) { + // TODO Make this set the precipitation value for all scenarios + console.log(input); + }, + setChartView: function() { this.model.set({ mode: models.constants.CHART }); }, @@ -502,9 +523,11 @@ function getGwlfeTabs(scenarios) { function showCompare() { var model_package = App.currentProject.get('model_package'), scenarios = App.currentProject.get('scenarios'), - tabs = model_package === modelingModels.TR55_PACKAGE ? - getTr55Tabs(scenarios) : getGwlfeTabs(scenarios), + isTr55 = model_package === modelingModels.TR55_PACKAGE, + tabs = isTr55 ? getTr55Tabs(scenarios) : getGwlfeTabs(scenarios), + controls = isTr55 ? [{ name: 'precipitation' }] : [], compareModel = new models.WindowModel({ + controls: controls, tabs: tabs, }); From 7c873ed8269a9c0132809ca31a017fa02f929f30 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Fri, 4 Aug 2017 16:52:14 -0400 Subject: [PATCH 3/5] Copy scenarios for Compare Window Just as in the previous compare view, we need to make a copy of scenarios so they can be adjusted (with inputs such as the pre- cipitation slider) without affecting the true scenarios on the page below. --- src/mmw/js/src/compare/models.js | 1 + src/mmw/js/src/compare/views.js | 59 ++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/mmw/js/src/compare/models.js b/src/mmw/js/src/compare/models.js index 5a5b7fe8a..c3c320776 100644 --- a/src/mmw/js/src/compare/models.js +++ b/src/mmw/js/src/compare/models.js @@ -42,6 +42,7 @@ var WindowModel = Backbone.Model.extend({ defaults: { controls: null, // ModelPackageControlsCollection mode: TABLE, // or CHART + scenarios: null, // ScenariosCollection tabs: null, // TabsCollection }, diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 5072fa360..2472c3010 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -54,7 +54,7 @@ var CompareWindow2 = Marionette.LayoutView.extend({ model: this.model, })); this.scenariosRegion.show(new ScenariosRowView({ - collection: App.currentProject.get('scenarios'), + collection: this.model.get('scenarios'), })); this.showSectionsView(); @@ -520,10 +520,63 @@ function getGwlfeTabs(scenarios) { ]; } +function copyScenario(scenario, aoi_census) { + var newScenario = new modelingModels.ScenarioModel({}), + fetchResults = _.bind(newScenario.fetchResults, newScenario), + debouncedFetchResults = _.debounce(fetchResults, 500); + + newScenario.set({ + name: scenario.get('name'), + is_current_conditions: scenario.get('is_current_conditions'), + aoi_census: aoi_census, + modifications: scenario.get('modifications'), + modification_hash: scenario.get('modification_hash'), + modification_censuses: scenario.get('modification_censuses'), + results: new modelingModels.ResultCollection(scenario.get('results').toJSON()), + inputs: new modelingModels.ModificationsCollection(scenario.get('inputs').toJSON()), + inputmod_hash: scenario.get('inputmod_hash'), + allow_save: false, + active: scenario.get('active'), + }); + + newScenario.get('inputs').on('add', debouncedFetchResults); + + return newScenario; +} + + +// Makes a sandboxed copy of project scenarios which can be safely +// edited and experimented in the Compare Window, and discarded on close. +function getCompareScenarios(isTr55) { + var trueScenarios = App.currentProject.get('scenarios'), + tempScenarios = new modelingModels.ScenariosCollection(), + ccScenario = trueScenarios.findWhere({ is_current_conditions: true }), + aoi_census = ccScenario.get('aoi_census'); + + if (isTr55) { + // Add 100% Forest Cover scenario + var forestScenario = copyScenario(ccScenario, aoi_census); + + forestScenario.set({ + name: '100% Forest Cover', + is_current_conditions: false, + is_pre_columbian: true, + }); + + tempScenarios.add(forestScenario); + } + + trueScenarios.forEach(function(scenario) { + tempScenarios.add(copyScenario(scenario, aoi_census)); + }); + + return tempScenarios; +} + function showCompare() { var model_package = App.currentProject.get('model_package'), - scenarios = App.currentProject.get('scenarios'), isTr55 = model_package === modelingModels.TR55_PACKAGE, + scenarios = getCompareScenarios(isTr55), tabs = isTr55 ? getTr55Tabs(scenarios) : getGwlfeTabs(scenarios), controls = isTr55 ? [{ name: 'precipitation' }] : [], compareModel = new models.WindowModel({ @@ -531,6 +584,8 @@ function showCompare() { tabs: tabs, }); + compareModel.set({ scenarios: scenarios }); + App.rootView.compareRegion.show(new CompareWindow2({ model: compareModel, })); From b8904e5f6d9e71e0d6f5b3e84acc5771944500ed Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Fri, 4 Aug 2017 17:30:08 -0400 Subject: [PATCH 4/5] Wire up precipitation slider to update scenarios It is also initialized to be the same value as the active scenario when the window is opened. --- src/mmw/js/src/compare/models.js | 6 ++++++ src/mmw/js/src/compare/views.js | 22 +++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/mmw/js/src/compare/models.js b/src/mmw/js/src/compare/models.js index c3c320776..33ff1b47c 100644 --- a/src/mmw/js/src/compare/models.js +++ b/src/mmw/js/src/compare/models.js @@ -53,6 +53,12 @@ var WindowModel = Backbone.Model.extend({ controls: new ControlsCollection(attrs.controls), tabs: new TabsCollection(attrs.tabs), }); + }, + + addOrReplaceInput: function(input) { + this.get('scenarios').each(function(scenario) { + scenario.addOrReplaceInput(input); + }); } }); diff --git a/src/mmw/js/src/compare/views.js b/src/mmw/js/src/compare/views.js index 2472c3010..a21159630 100644 --- a/src/mmw/js/src/compare/views.js +++ b/src/mmw/js/src/compare/views.js @@ -129,21 +129,21 @@ var InputsView = Marionette.LayoutView.extend({ }, onShow: function() { - var setPrecipitationValue = _.bind(this.setPrecipitationValue, this), + var addOrReplaceInput = _.bind(this.model.addOrReplaceInput, this.model), + controlModel = this.model.get('scenarios') + .findWhere({ active: true }) + .get('inputs') + .findWhere({ name: 'precipitation' }), precipitationModel = this.model.get('controls') .findWhere({ name: 'precipitation' }); this.precipitationRegion.show(new PrecipitationView({ model: precipitationModel, - addOrReplaceInput: setPrecipitationValue, + controlModel: controlModel, + addOrReplaceInput: addOrReplaceInput, })); }, - setPrecipitationValue: function(input) { - // TODO Make this set the precipitation value for all scenarios - console.log(input); - }, - setChartView: function() { this.model.set({ mode: models.constants.CHART }); }, @@ -586,6 +586,14 @@ function showCompare() { compareModel.set({ scenarios: scenarios }); + if (isTr55) { + // Set compare model to have same precipitation as active scenario + compareModel.addOrReplaceInput( + scenarios.findWhere({ active: true }) + .get('inputs') + .findWhere({ name: 'precipitation' })); + } + App.rootView.compareRegion.show(new CompareWindow2({ model: compareModel, })); From 5c18350668ddc59f81b9881bb42df1e1737a1b5d Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Fri, 4 Aug 2017 17:39:50 -0400 Subject: [PATCH 5/5] Style precipitation slider Reduce font size to match the styling in the modeling view --- src/mmw/sass/pages/_compare.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mmw/sass/pages/_compare.scss b/src/mmw/sass/pages/_compare.scss index a47c96c6b..dde808274 100644 --- a/src/mmw/sass/pages/_compare.scss +++ b/src/mmw/sass/pages/_compare.scss @@ -537,6 +537,9 @@ $compare-chart-table-height: calc(100vh - #{$height-lg} - #{$compare-footer-heig &.compare-precipitation { margin-right: 20px; + label { + font-size: 12px; + } } } }