app/assets/javascripts/map/presenters/tabs/AnalysisPresenter.js
/**
* The AnalysisToolPresenter class for the AnalysisToolView.
*
* @return AnalysisToolPresenter class.
*/
define(
[
'map/presenters/PresenterClass',
'underscore',
'backbone',
'mps',
'topojson',
'bluebird',
'helpers/geojsonUtilsHelper',
'map/services/CountryService',
'map/services/RegionService',
'map/services/GeostoreService'
],
function(
PresenterClass,
_,
Backbone,
mps,
topojson,
bluebird,
geojsonUtilsHelper,
countryService,
regionService,
GeostoreService
) {
'use strict';
var StatusModel = Backbone.Model.extend({
defaults: {
baselayer: null,
both: false,
resource: null, // analysis resource
date: null,
threshold: 30, // by default
iso: null,
overlay: null, // google.maps.Polygon (user drawn polygon)
multipolygon: null, // geojson (countries and regions multypolygon)
disableUpdating: false,
dont_analyze: false
}
});
var concessionsSql = {
logging:
'http://wri-01.cartodb.com/api/v2/sql/?q=SELECT ST_AsGeoJSON(the_geom) from gfw_logging where cartodb_id ={0}',
mining:
'http://wri-01.cartodb.com/api/v2/sql/?q=SELECT ST_AsGeoJSON(the_geom) from gfw_mining where cartodb_id ={0}',
oilpalm:
'http://wri-01.cartodb.com/api/v2/sql/?q=SELECT ST_AsGeoJSON(the_geom) from gfw_oil_palm where cartodb_id ={0}',
fiber:
'http://wri-01.cartodb.com/api/v2/sql/?q=SELECT ST_AsGeoJSON(the_geom) from gfw_wood_fiber where cartodb_id ={0}'
};
var AnalysisToolPresenter = PresenterClass.extend({
datasets: {
biomass_loss: 'biomass-loss'
},
usenames: ['mining', 'oilpalm', 'fiber', 'logging'],
init: function(view) {
this.view = view;
this.status = new StatusModel();
this._super();
mps.publish('Place/register', [this]);
},
/**
* Application subscriptions.
*/
_subscriptions: [
{
'Geostore/go': function(geostore) {
this.status.set('geostore', geostore.data.attributes.hash);
this._handlePlaceGo(geostore.data.attributes);
}
},
{
'Place/go': function(place) {
this._setBaselayer(place.layerSpec.getBaselayers());
this.status.set('date', [place.params.begin, place.params.end]);
this.status.set('threshold', place.params.threshold);
this.status.set('dont_analyze', place.params.dont_analyze);
this._handlePlaceGo(place.params);
}
},
{
'LayerNav/change': function(layerSpec) {
var baselayer = this.status.get('baselayer');
var both = this.status.get('both');
this._setBaselayer(layerSpec.getBaselayers());
if (this.status.get('baselayer') != baselayer) {
this._updateAnalysis();
this.openAnalysisTab();
} else {
if (this.status.get('both') != both) {
this._updateAnalysis();
this.openAnalysisTab();
}
}
}
},
{
'AnalysisTool/update-analysis': function() {
this._updateAnalysis();
}
},
{
'AnalysisResults/delete-analysis': function() {
this.deleteAnalysis();
}
},
{
'AnalysisTool/analyze-wdpaid': function(wdpaid) {
this.openAnalysisTab(true);
this.view._stopDrawing();
this.deleteAnalysis();
this._analyzeWdpai(wdpaid.wdpaid);
}
},
{
'AnalysisTool/analyze-concession': function(
useid,
layerSlug,
wdpaid
) {
if (wdpaid && wdpaid != '') {
wdpaid = { wdpaid: wdpaid };
mps.publish('AnalysisTool/analyze-wdpaid', [wdpaid]);
return;
}
this.openAnalysisTab(true);
this.view._stopDrawing();
this.deleteAnalysis();
this._analyzeConcession(useid, layerSlug);
}
},
{
'Timeline/date-change': function(layerSlug, date) {
this.status.set('date', date);
this.openAnalysisTab();
this._updateAnalysis();
}
},
{
'Timeline/start-playing': function() {
this.status.set('disableUpdating', true);
}
},
{
'Timeline/stop-playing': function() {
this.status.set('disableUpdating', false);
this._updateAnalysis();
}
},
{
'Threshold/changed': function(threshold) {
this.status.set('threshold', threshold);
this.openAnalysisTab();
this._updateAnalysis();
}
},
{
'Tab/opened': function(id) {
if (id === 'analysis-tab') {
this.view.model.set('hidden', false);
} else {
if (this.view.model.get('is_drawing')) {
this.view._stopDrawing();
this.deleteAnalysis();
this.view.model.set('hidden', true);
}
}
}
},
{
'Countries/changeIso': function(iso, analyze) {
this.status.set('dont_analyze', analyze);
if (!!iso.country) {
this.deleteAnalysis();
this._analyzeIso(iso);
} else {
mps.publish('LocalMode/updateIso', [
iso,
this.status.get('dont_analyze')
]);
this.deleteAnalysis();
}
}
},
{
'Analysis/toggle': function() {
this.view.toggleAnalysis(this.view.$el.hasClass('is-analysis'));
}
},
{
'Analysis/upload': function(geojson) {
ga('send', 'event', 'Map', 'Analysis', 'Upload Shapefile');
this._saveAndAnalyzeGeojson(geojson, { draw: true });
}
},
{
'Subscribe/end': function() {
this.view.setStyle();
}
},
{
'Dialogs/close': function() {
this.view.toggleAnalysis(true);
}
}
],
openAnalysisTab: function(open) {
var open = open || this.view.$el.hasClass('is-analysis');
if (open) {
mps.publish('Tab/open', ['#analysis-tab-button']);
}
},
/**
* Handles a Place/go.
*
* @param {Object} params Place params
*/
_handlePlaceGo: function(params) {
// this.deleteAnalysis();
//Open analysis tab
if (
(!this.status.get('dont_analyze') &&
(params.iso &&
params.iso.country &&
params.iso.country !== 'ALL')) ||
(params.analyze || params.geojson || params.wdpaid)
) {
mps.publish('Tab/open', ['#analysis-tab-button']);
}
//Select analysis type by params given
if (params.analyze && params.name === 'map') {
this.view.onClickAnalysis();
} else if (
params.iso &&
params.iso.country &&
params.iso.country !== 'ALL'
) {
if (params.geojson) {
this._analyzeIso(params.iso);
this._analyzeGeojson(params.geojson);
} else {
this._analyzeIso(params.iso);
}
} else if (params.geostore) {
this.status.set('geostore', params.geostore);
} else if (params.geojson) {
var geojson = this._getGeomFromGeoJSON(params.geojson);
if (geojson) {
this._analyzeGeojson(geojson);
}
} else if (params.wdpaid) {
this._analyzeWdpai(params.wdpaid);
}
},
_getGeomFromGeoJSON: function(geojson) {
var geom = {};
if (geojson && geojson.features && geojson.features[0]) {
geom = _.clone(geojson.features[0].geometry);
}
return geom;
},
/**
* Analyzes a geojson object.
*
* @param {[type]} geojson [description]
*/
_analyzeGeojson: function(geojson, options) {
options = options || { draw: true };
// Build resource
var resource = {
geojson: JSON.stringify(geojson),
type: 'geojson'
};
resource = this._buildResource(resource);
// Draw geojson if needed.
if (options.draw) {
this.view.drawPaths(geojsonUtilsHelper.geojsonToPath(geojson));
}
// Publish analysis
ga(
'send',
'event',
'Map',
'Analysis',
'Layer: ' + resource.dataset + ', Polygon: true'
);
this._publishAnalysis(resource);
},
_saveAndAnalyzeGeojson: function(geojson, options) {
mps.publish('Spinner/start');
GeostoreService.save(geojson)
.then(
function(geostoreId) {
this.status.set('geostore', geostoreId);
this._analyzeGeojson(geojson, options);
}.bind(this)
)
.catch(function(e) {
mps.publish('AnalysisService/results', [{ unavailable: true }]);
});
},
/**
* Analyze country/region by iso.
*
* @param {Object} iso {country: {string}, id: {integer}}
*/
_analyzeIso: function(iso) {
this.deleteAnalysis();
this.view.setSelects(iso, this.status.get('dont_analyze'));
mps.publish('LocalMode/updateIso', [
iso,
this.status.get('dont_analyze')
]);
// Build resource
var resource = {
iso: iso.country,
type: 'iso'
};
if (iso.region) {
resource.id1 = iso.region;
}
resource = this._buildResource(resource);
ga(
'send',
'event',
'Map',
'Analysis',
'Layer: ' + resource.dataset + ', Iso: ' + resource.iso.country
);
//Pan map to selected country.
if (!iso.region) {
// Get geojson/fit bounds/draw geojson/publish analysis.
countryService.execute(
resource.iso,
_.bind(function(results) {
var objects = _.findWhere(results.topojson.objects, {
type: 'MultiPolygon'
});
var geojson = topojson.feature(results.topojson, objects);
this._geojsonFitBounds(geojson);
mps.publish('Subscribe/geom', [geojson]);
// Always draw the country shape regardless of the tab
this.view.drawCountrypolygon(geojson, '#5B80A0');
if (!this.status.get('dont_analyze')) {
this.view._removeCartodblayer();
this._publishAnalysis(resource);
} else {
mps.publish('Spinner/stop');
}
}, this)
);
} else {
regionService.execute(
resource,
_.bind(function(results) {
var geojson = results.features[0];
this._geojsonFitBounds(geojson);
mps.publish('Subscribe/geom', [geojson]);
if (!this.status.get('dont_analyze')) {
this.view.drawCountrypolygon(geojson, '#5B80A0');
this.view._removeCartodblayer();
this._publishAnalysis(resource);
} else {
mps.publish('Spinner/stop');
}
}, this)
);
}
},
setAnalyzeIso: function(iso) {
this.status.set('dont_analyze', null);
mps.publish('Analysis/analyze-iso', [
iso,
this.status.get('dont_analyze')
]);
mps.publish('Countries/changeIso', [
iso,
this.status.get('dont_analyze')
]);
},
setSubscribeIso: function(iso) {
mps.publish('Subscription/iso', [iso]);
},
_analyzeWdpai: function(wdpaid) {
// Build resource
this.wdpaidBool = this.wdpaid == wdpaid ? false : true;
this.wdpaid = wdpaid;
if (this.wdpaidBool) {
var resource = this._buildResource({
wdpaid: wdpaid,
type: 'other',
geostore: null
});
ga(
'send',
'event',
'Map',
'Analysis',
'Layer: ' + resource.dataset + ', Wdpaid: ' + resource.wdpaid
);
// Get geojson/fit bounds/draw geojson/publish analysis
var url =
'http://wri-01.cartodb.com/api/v2/sql/?q=SELECT ST_AsGeoJSON(the_geom) from wdpa_protected_areas where wdpaid =' +
wdpaid;
$.getJSON(
url,
_.bind(function(data) {
if (data.rows.length > 0) {
var geojson = {
geometry: JSON.parse(data.rows[0].st_asgeojson),
properties: {},
type: 'Feature'
};
this._geojsonFitBounds(geojson);
this.view.drawMultipolygon(geojson);
this._publishAnalysis(resource);
this.wdpaid = null;
this.wdpaidBool = true;
} else {
this._publishAnalysis(resource, true);
}
}, this)
);
}
},
/**
* Analyze a concession.
*
* @param {integer} useid Carto db id
*/
_analyzeConcession: function(useid, layerSlug) {
var resource = this._buildResource({
useid: useid,
use: layerSlug,
type: 'other'
});
ga(
'send',
'event',
'Map',
'Analysis',
'Layer: ' +
resource.dataset +
', ConcessionLayer: ' +
resource.use +
', ConcessionId: ' +
resource.useid
);
var url = (function() {
if (!!concessionsSql[layerSlug])
return concessionsSql[layerSlug].format(useid);
else
return (
'http://wri-01.cartodb.com/api/v2/sql/?q=SELECT ST_AsGeoJSON(the_geom) from ' +
layerSlug +
' where cartodb_id =' +
useid
);
})();
$.getJSON(
url,
_.bind(function(data) {
if (data.rows.length > 0) {
var geojson = {
geometry: JSON.parse(data.rows[0].st_asgeojson),
properties: {},
type: 'Feature'
};
this._geojsonFitBounds(geojson);
this.view.drawMultipolygon(geojson);
if (!!layerSlug && this.usenames.indexOf(layerSlug) === -1) {
var provider = {
table: layerSlug,
filter: 'cartodb_id = ' + useid,
user: 'wri-01',
type: 'carto'
};
GeostoreService.use(provider).then(
function(useGeostoreId) {
if (useGeostoreId) {
resource.use = null;
resource.useid = null;
resource.type = 'world';
resource.geostore = useGeostoreId;
this._publishAnalysis(resource);
} else {
this._publishAnalysis(resource, true);
}
}.bind(this)
);
} else {
this._publishAnalysis(resource);
}
} else {
this._publishAnalysis(resource, true);
}
}, this)
);
},
/**
* Get the geojson from the current geom and check valid size
*/
isValidDraw: function() {
var overlay = this.status.get('overlay');
return overlay.getPath().getArray().length >= 3; // LinearRing of coordinates needs to have four or more positions
},
/**
* Get the geojson from the current and analyze
* that geojson without drawing again the geom.
*/
doneDrawing: function() {
var overlay = this.status.get('overlay');
var paths = overlay.getPath().getArray();
var geojson = geojsonUtilsHelper.pathToGeojson(paths);
var wrappedGeoJSON = geojsonUtilsHelper.wrapInCollection(geojson);
this.view.setEditable(overlay, false);
// this._analyzeGeojson(geojson, {draw: false});
this._saveAndAnalyzeGeojson(wrappedGeoJSON, { draw: false });
},
/**
* Build a resource, adding extra options
* from the current status.
*/
_buildResource: function(resource) {
mps.publish('Spinner/start');
var date, dateFormat;
var baselayer = this.status.get('baselayer');
// Return resource if there isn't a baselayer
// so we can build the resource later
// and display a 'unsupported layer' message.
if (!baselayer) {
return resource;
}
if (this.status.get('geostore')) {
resource.geostore = this.status.get('geostore');
}
if (baselayer.slug !== 'forestgain') {
// Append dataset string
resource.dataset = this.datasets[baselayer.slug];
// Append period
date = this.status.get('date');
dateFormat = 'YYYY-MM-DD';
// period format = 2012-12-23,2013-01-4
date[0] =
date[0] != null
? !!date[0]._isAMomentObject ? date[0] : date[0].substr(0, 10)
: '2001-01-01';
date[1] =
date[1] != null
? !!date[1]._isAMomentObject ? date[1] : date[1].substr(0, 10)
: '2014-12-31';
resource.period = '{0},{1}'.format(
date[0].format(dateFormat),
date[1].format(dateFormat)
);
resource.begin = date[0];
resource.end = date[1];
// this is super ugly
if (baselayer.slug === 'biomass_loss') {
resource.thresh =
this.status.get('threshold') === null
? 30
: this.status.get('threshold');
} else {
delete resource.thresh;
}
return resource;
} else {
// Append dataset string
resource.dataset = this.datasets[baselayer.slug];
// Append period
date = ['2001-01-01', '2013-12-31'];
// period format = 2012-12-23,2013-01-4
resource.period = '{0},{1}'.format(date[0], date[1]);
// this is super ugly
resource.thresh = '?thresh=' + this.status.get('threshold');
return resource;
}
},
/**
* Publish an analysis form a suplied resource.
*
* @param {Object} resource The analysis resource
*/
_publishAnalysis: function(resource, failed) {
this.status.set('resource', resource);
// this._setAnalysisBtnVisibility();
mps.publish('Place/update', [{ go: false }]);
//Open tab of analysis
this.view.openTab(resource.type);
if (!this.status.get('baselayer') || failed) {
mps.publish('AnalysisService/results', [{ unavailable: true }]);
} else {
mps.publish('AnalysisService/get', [resource]);
}
},
/**
* Updates current analysis if it's permitted.
*/
_updateAnalysis: function() {
var resource = this.status.get('resource');
if (resource && !this.status.get('disableUpdating')) {
resource = this._buildResource(resource);
// (resource.iso) ? this.view.putMaskOnTop() : null;
this._publishAnalysis(resource);
}
},
/**
* Deletes the current analysis.
*/
deleteAnalysis: function() {
mps.publish('AnalysisResults/Delete');
this.view._removeCartodblayer();
this.view.$el.removeClass('is-analysis');
// if(!this.status.get('dont_analyze')){
// console.log('cause');
// mps.publish('Analysis/toggle')
// }
// Delete overlay drawn or multipolygon.
this.view.deleteGeom({
overlay: this.status.get('overlay'),
multipolygon: this.status.get('multipolygon')
});
this.view.setSelects({ country: null, region: null });
// Reset status model
this.status.set({
resource: null,
overlay: null,
polygon: null,
multipolygon: null
});
this._setAnalysisBtnVisibility();
},
resetIsos: function() {
mps.publish('LocalMode/updateIso', [{ country: null, region: null }]);
},
/**
* Set the status.baselayer from layerSpec.
*
* @param {Object} baselayers Current active baselayers
*/
_setBaselayer: function(baselayers) {
var baselayer;
baselayer =
baselayers[
_.first(
_.intersection(_.pluck(baselayers, 'slug'), _.keys(this.datasets))
)
];
$('#analyzeBtn').toggleClass('dont-analyze', !!!baselayer);
this.status.set('baselayer', baselayer);
this._setAnalysisBtnVisibility();
},
_setAnalysisBtnVisibility: function() {
this.view.toggleBtn(!!!this.status.get('baselayer'));
},
toggleVisibilityAnalysis: function(to) {
mps.publish('Analysis/visibility', [to]);
},
/**
* Publish a 'Map/fit-bounds' with the bounds
* from the suplied geojson.
*
* @param {Object} geojson
*/
_geojsonFitBounds: function(geojson) {
var bounds = geojsonUtilsHelper.getBoundsFromGeojson(geojson);
if (bounds) {
mps.publish('Map/fit-bounds', [bounds]);
}
},
/**
* Publish a start drawing mps event.
*/
startDrawing: function() {
mps.publish('AnalysisTool/start-drawing', []);
},
/**
* Publish a stop drawing mps event.
*/
stopDrawing: function() {
mps.publish('AnalysisTool/stop-drawing', []);
},
/**
* Triggered when user finish drawing a polygon.
* @param {Object} e Event
*/
onOverlayComplete: function(e) {
e.overlay.type = e.type;
e.overlay.setEditable(true);
this.setOverlay(e.overlay);
},
setOverlay: function(overlay) {
this.status.set('overlay', overlay);
},
setMultipolygon: function(multipolygon, geojson) {
this.deleteMultiPoligon();
this.status.set('multipolygon', multipolygon);
mps.publish('AnalysisTool/iso-drawn', [geojson.geometry]);
},
deleteMultiPoligon: function() {
this.view.deleteGeom({
overlay: this.status.get('overlay'),
multipolygon: this.status.get('multipolygon')
});
},
/**
* Used by PlaceService to get the current iso/geom params.
*
* @return {object} iso/geom params
*/
getPlaceParams: function() {
var resource = this.status.get('resource');
if (!resource) {
return;
}
var p = {};
if (resource.iso) {
p.iso = {};
p.iso.country = resource.iso;
p.iso.region = resource.id1 ? resource.id1 : null;
} else if (resource.geostore) {
p.geostore = resource.geostore;
} else if (resource.geojson) {
p.geojson = encodeURIComponent(resource.geojson);
} else if (resource.wdpaid) {
p.wdpaid = resource.wdpaid;
}
return p;
},
toggleOverlay: function(to) {
mps.publish('Overlay/toggle', [to]);
},
notificate: function(id) {
mps.publish('Notification/open', [id]);
}
});
return AnalysisToolPresenter;
}
);