Vizzuality/gfw-climate

View on GitHub
app/assets/javascripts/map/presenters/tabs/SubscriptionPresenter.js

Summary

Maintainability
F
4 days
Test Coverage
/**
 * The SubscriptionPresenter class for the AnalysisToolView.
 *
 * @return SubscriptionPresenter class.
 */
define(
  [
    'map/presenters/PresenterClass',
    'underscore',
    'backbone',
    'mps',
    'topojson',
    'helpers/geojsonUtilsHelper',
    'map/services/CountryService',
    'map/services/RegionService'
  ],
  function(
    PresenterClass,
    _,
    Backbone,
    mps,
    topojson,
    geojsonUtilsHelper,
    countryService,
    regionService
  ) {
    '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 SubscriptionPresenter = PresenterClass.extend({
      datasets: {
        loss: 'umd-loss-gain',
        forestgain: 'umd-loss-gain',
        forma: 'forma-alerts',
        imazon: 'imazon-alerts',
        fires: 'nasa-active-fires',
        modis: 'quicc-alerts',
        terrailoss: 'terrai-alerts',
        prodes: 'prodes-alerts'
      },

      init: function(view) {
        this.view = view;
        this.status = new StatusModel();
        this._super();
      },

      /**
       * Application subscriptions.
       */
      _subscriptions: [
        {
          'Subscribe/end': function(options) {
            this.deleteSubscription();
          }
        },
        {
          'Subscription/iso': function(iso) {
            this.openSubscriptionTab(true);
            this.view._onClickStart();
            this.view._stopDrawing();
            this.deleteSubscription();
            this.view.setStyle();
            this._subscribeIso(iso);
          }
        },
        {
          'Subscription/analyze-wdpaid': function(wdpaid) {
            this.openSubscriptionTab(true);
            this.view._onClickStart();
            this.view._stopDrawing();
            this.deleteSubscription();
            this.view.setStyle();
            this._subscribeWdpai(wdpaid.wdpaid);
          }
        },
        {
          'Subscription/analyze-concession': function(
            useid,
            layerSlug,
            wdpaid
          ) {
            if (wdpaid && wdpaid != '') {
              wdpaid = { wdpaid: wdpaid };
              mps.publish('Subscription/analyze-wdpaid', [wdpaid]);
              return;
            }
            this.openSubscriptionTab(true);
            this.view._onClickStart();
            this.view._stopDrawing();
            this.deleteSubscription();
            this.view.setStyle();
            this._subscribeConcession(useid, layerSlug);
          }
        },
        {
          'Tab/opened': function(id) {
            if (id === 'subscription-tab') {
              this.view.model.set('hidden', false);
            } else {
              this.view.model.set('hidden', true);
              if (this.view.model.get('is_drawing')) {
                this.view._stopDrawing();
                mps.publish('Subscribe/hide');
              } else {
                mps.publish('Subscribe/hide');
              }
            }
          }
        }
      ],

      openSubscriptionTab: function(open) {
        mps.publish('Tab/open', ['#subscription-tab-button']);
      },

      /**
       * Analyzes a geojson object.
       *
       * @param  {[type]} geojson [description]
       */
      _subscribeGeojson: function(geojson, options) {
        options = options || { draw: true };
        this.view.setStyle();
        // 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',
          'Subscription',
          'Layer: ' + resource.dataset + ', Polygon: true'
        );
        this._publishSubscribe(resource);
      },

      /**
       * Analyze country/region by iso.
       *
       * @param  {Object} iso {country: {string}, id: {integer}}
       */
      _subscribeIso: function(iso) {
        this.deleteSubscription();
        this.view.setStyle();
        this.view.setSelects(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',
          'Subscription',
          'Layer: ' + resource.dataset + ', Iso: ' + resource.iso.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);
              this.view.drawCountrypolygon(geojson, '#F00');

              // Show subscription dialog
              resource.geom = geojson;
              this._publishSubscribe(resource);
            }, this)
          );
        } else {
          regionService.execute(
            resource,
            _.bind(function(results) {
              var geojson = results.features[0];
              this._geojsonFitBounds(geojson);
              this.view.drawCountrypolygon(geojson, '#F00');

              // Show subscription dialog
              resource.geom = geojson;
              this._publishSubscribe(resource);
            }, this)
          );
        }
      },

      setSubscriptionIso: function(iso) {
        this._subscribeIso(iso);
      },

      _subscribeWdpai: function(wdpaid) {
        // Build resource
        var resource = this._buildResource({
          wdpaid: wdpaid,
          type: 'other'
        });

        ga(
          'send',
          'event',
          'Map',
          'Subscription',
          '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);
              resource.geom = geojson;
              this._publishSubscribe(resource);
            } else {
              this._publishSubscribe(resource, true);
            }
          }, this)
        );
      },

      /**
       * Analyze a concession.
       *
       * @param  {integer} useid Carto db id
       */
      _subscribeConcession: function(useid, layerSlug) {
        var resource = this._buildResource({
          useid: useid,
          use: layerSlug,
          type: 'other'
        });

        ga(
          'send',
          'event',
          'Map',
          'Subscription',
          '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);
              resource.geom = geojson;
              this._publishSubscribe(resource);
            } else {
              this._publishSubscribe(resource, true);
            }
          }, this)
        );
      },

      /**
       * 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);

        this.view.setEditable(overlay, false);
        this._subscribeGeojson(geojson, { 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 (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] : '2001-01-01';
          date[1] = date[1] != null ? date[1] : '2014-12-31';
          resource.period = '{0},{1}'.format(
            date[0].format(dateFormat),
            date[1].format(dateFormat)
          );

          // this is super ugly
          if (baselayer.slug === 'loss') {
            resource.thresh =
              '?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
       */
      _publishSubscribe: function(resource, failed) {
        this.status.set('resource', resource);
        var options = {
          analysisResource: this.status.get('resource')
        };

        mps.publish('Spinner/stop');
        mps.publish('Subscribe/show', [options]);
        this.view.$el.addClass('is-subscribing');
      },

      /**
       * Deletes the current analysis.
       */
      deleteSubscription: function() {
        // 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.view.$el.removeClass('is-subscribing');
      },

      resetIsos: function() {
        mps.publish('LocalMode/updateIso', [{ country: null, region: null }]);
      },

      /**
       * 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.geojson) {
          p.geojson = encodeURIComponent(resource.geojson);
        } else if (resource.wdpaid) {
          p.wdpaid = resource.wdpaid;
        }

        return p;
      },

      notificate: function(id) {
        mps.publish('Notification/open', [id]);
      }
    });

    return SubscriptionPresenter;
  }
);