API Docs for: 0.0.1
Show:

File: lib/graphs/structure.js

/*
* niViz -- snow profiles visualization
* Copyright (C) 2015 WSL/SLF - Fluelastrasse 11 - 7260 Davos Dorf - Switzerland.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

(function (niviz, moment) {
  'use strict';

  // --- Module Dependencies ---
  var Graph     = niviz.Graph;
  var Common    = niviz.Common;
  var Cartesian = niviz.Cartesian;
  var BarGraph  = niviz.BarGraph;
  var t         = niviz.Translate.gettext;
  var hsgrid    = niviz.Grid.hsgrid;
  var extend    = niviz.util.extend;

  /** @module niviz */

  /**
   * Visualization of a singular snow profile SLF style with an additional
   * visualization of the structure profile according to Monti et Schweizer
   * "Snow profile visualisations to highlight structural instability
   * conditions" (2013). A miniature version exists which may be used in
   * combination with a timeline graph.
   *
   * @class StructureProfile
   * @constructor
   * @extends SLFProfile
   *
   * @param {Station} station A niViz station object
   * @param {Object} canvas A svg element that will be used as SnapSVG paper
   * @param {Object} properties
   */
  function StructureProfile (station, canvas, properties) {
    StructureProfile.uber.call(this, station, canvas, properties);
    extend(this.properties, properties);

    this.draw(station.current || station.profiles[station.profiles.length - 1]);

    var self = this;
    station.emitter.on('profile', function (object) {
      self.draw(object);
    });
  }

  Graph.implement(StructureProfile, 'StructureProfile', 'profile', 'SLFProfile');

  /**
   * Deregister events
   * @method destroy
   */
  StructureProfile.prototype.destroy = function () {
    this.station.emitter.off('profile');
  };

  /**
   * Overwrite current properties with the ones passed as parameter.
   *
   * @method setProperties
   * @param {Object} properties
   */
  StructureProfile.prototype.setProperties = function (properties) {
    extend(this.properties, properties);
    this.draw(this.profile);
  };

  /**
   * Configure all properties and axes dependent on canvas size and whether
   * the graph shall be used in miniature or normal mode.
   *
   * @method configure
   * @private
   */
  StructureProfile.prototype.configure = function () {
    var p = this.properties,  hsmin, hsmax, pchange = false;

    if (this.hsgrid) {
      hsmin = this.hsgrid.min;
      hsmax = this.hsgrid.max;
    }

    p.height = this.canvas.height();
    p.width  = this.canvas.width();

    if (p.miniature) {
      this.miniconfig();
      this.left = 0;
    } else {
      this.hsgrid = hsgrid(this.station, p.table.max, p.table.min, false);
      this.left = p.width - 400;
    }

    this.cart  = 100;
    this.right = p.width - 4 * p.fontsize;

    this.cartesian.addx('flags', 0, 7, this.right - this.cart, this.left + 2 * p.fontsize);

    if (hsmin !== this.hsgrid.min || hsmax !== this.hsgrid.max) pchange = true;

    if (!this.bargraph || pchange) {
      this.setbarcfg();

      if (!this.bargraph) this.bargraph = new BarGraph(this.paper, this.barcfg);
      else this.bargraph.reconfigure(this.barcfg);
    }
  };

  /**
   * Configure bargraph properties.
   * @method setbarcfg
   * @private
   */
  StructureProfile.prototype.setbarcfg = function () {
    var p = this.properties;

    this.barcfg = {
      font: p.font,
      fontsize: p.fontsize,
      grid_color: p.grid_color,
      cartesian: this.cartesian,
      valuefunc: valuefunc,
      primary: {
        lbl: t('Structure index'), pos: 'bottom',
        min: 0, max: 7, inc: 1, axis: 'flags'
      },
      showdate: p.miniature,
      hs : this.hsgrid,
      bars: {x: 'flags', y: 'hs'},
      top: p.table ? p.table.top : this.top,
      left: this.left,
      right: this.right,
      height: p.table ? p.height - p.table.top - p.table.bottom : this.height,
      cart: this.cart,
      canvas: this.canvas,
      callbacks: [{
        f: this.arrow,
        param: ['flags', 'arrow']
      }]
    };
  };

  /**
   * Configure parameters for miniature mode.
   * @method miniconfig
   * @private
   */
  StructureProfile.prototype.miniconfig = function () {
    var p = this.properties;

    p.grid_color = '#000';//'#707070';
    p.fontsize = 14;
    p.font = {
      fontSize: p.fontsize + 'px',
      textAnchor: 'middle',
      fontFamily: 'LatoWeb, Helvetica, Arial'
    };

    this.top = 3 * p.fontsize;
    this.bottom = p.height - 3 * p.fontsize;
    this.height = p.height - 6 * p.fontsize;

    if (!this.cartesian) {
      this.cartesian = new Cartesian();
      this.hsgrid = hsgrid(this.station, null, null, Common.defaults.autoscale);
      this.cartesian.addy('hs', this.hsgrid.min, this.hsgrid.max, this.bottom, this.top);
    }

    if (!this.paper) this.paper = Snap(this.canvasnode);
  };

  /**
   * Callback for BarGraph. Draw the red arrows to highlight instable structures.
   *
   * @method arrow
   * @private
   * @param {String} feature
   * @param {String} type
   */
  StructureProfile.prototype.arrow = function (feature, type) {
    feature = this.profile[feature];
    if (this.elements[type]) this.elements[type].remove();

    if (!feature) return;

    var ii = 0, paper = this.paper, set = paper.g(), origin = this.coord(0, 0);
    for ( ; ii < feature.layers.length; ++ii) {
      if (feature.layers[ii].value.sum < 5) continue;
      if (!this.bars[ii]) continue;

      var y = this.bars[ii].center, x = origin.x + 3;
      set.add(paper.line(this.properties.xright, y, x, y));
      set.add(paper.polygon(x, y, x + 10, y - 5, x + 10, y + 5, x, y));
    }

    set.attr({
      'fill' : '#D00',
      'stroke': '#D00',
      'arrow-end': 'block-wide-long',
      'stroke-width': 3
    });

    this.elements[type] = set;
  };

  var valuefunc = function (value) {
    return 7 - value.value.sum;
  };

  /**
   * Draw the StructureProfile by drawing the bargraph.
   *
   * @method draw
   * @param {Profile} profile The niViz profile to render
   */
  StructureProfile.prototype.draw = function (profile) {
    var p = this.properties;
    if (profile) this.profile = profile;

    if (!p.miniature) { // draw the full SLFProfile AND the StructureProfile
      StructureProfile.uber.prototype.draw.call(this, profile);
      this.canvas.width(this.canvas.width() + 400);
      p.width = this.canvas.width();
      this.paper.attr({ width: p.width + 'px', height: p.height + 'px' });
    }

    this.configure();
    this.bargraph.draw(profile);
  };

  // --- Helpers ---

  // --- Module Exports ---
  niviz.StructureProfile = StructureProfile;

}(niviz, moment));