conveyal/modeify

View on GitHub
client/components/conveyal/transitive.js/master/lib/point/index.js

Summary

Maintainability
D
1 day
Test Coverage
var augment = require('augment');
var each = require('each');

var PointLabel = require('../labeler/pointlabel');

var debug = require('debug')('transitive:point');

var Point = augment(Object, function() {

  this.constructor = function(data) {
    for (var key in data) {
      this[key] = data[key];
    }

    this.paths = [];
    this.renderData = [];

    this.label = new PointLabel(this);
    this.renderLabel = true;

    this.focused = true;
    this.sortableType = 'POINT';

    this.placeOffsets = {
      x: 0,
      y: 0
    };

    this.zIndex = 10000;
  };

  /**
   * Get unique ID for point -- must be defined by subclass
   */

  this.getId = function() {};

  this.getElementId = function() {
    return this.getType().toLowerCase() + '-' + this.getId();
  };

  /**
   * Get Point type -- must be defined by subclass
   */

  this.getType = function() {};

  /**
   * Get Point name
   */

  this.getName = function() {
    return this.getType() + ' point (ID=' + this.getId() + ')';
  };

  /**
   * Get latitude
   */

  this.getLat = function() {
    return 0;
  };

  /**
   * Get longitude
   */

  this.getLon = function() {
    return 0;
  };

  this.containsSegmentEndPoint = function() {
    return false;
  };

  this.containsBoardPoint = function() {
    return false;
  };

  this.containsAlightPoint = function() {
    return false;
  };

  this.containsTransferPoint = function() {
    return false;
  };

  this.getPatterns = function() {
    return [];
  };

  /**
   * Draw the point
   *
   * @param {Display} display
   */

  this.render = function(display) {
    this.label.svgGroup = null;
  };

  /**
   * Refresh a previously drawn point
   *
   * @param {Display} display
   */

  this.refresh = function(display) {};

  this.addRenderData = function() {};

  this.clearRenderData = function() {};

  this.containsFromPoint = function() {
    return false;
  };

  this.containsToPoint = function() {
    return false;
  };

  this.initSvg = function(display) {
    // set up the main svg group for this stop
    this.svgGroup = display.svg.append('g')
      .attr('id', 'transitive-' + this.getType().toLowerCase() + '-' + this
        .getId())
    //.attr('class', 'transitive-sortable')
    .datum(this);

    this.markerSvg = this.svgGroup.append('g');
    this.labelSvg = this.svgGroup.append('g');
  };

  //** Shared geom utility functions **//

  this.constructMergedMarker = function(display) {

    var dataArray = this.getRenderDataArray();
    var xValues = [],
      yValues = [];
    dataArray.forEach(function(data) {
      var x = data.x; //display.xScale(data.x) + data.offsetX;
      var y = data.y; //display.yScale(data.y) - data.offsetY;
      xValues.push(x);
      yValues.push(y);
    });
    var minX = Math.min.apply(Math, xValues),
      minY = Math.min.apply(Math, yValues);
    var maxX = Math.max.apply(Math, xValues),
      maxY = Math.max.apply(Math, yValues);

    // retrieve marker type and radius from the styler
    var markerType = display.styler.compute(display.styler.stops_merged[
      'marker-type'], display, {
      owner: this
    });
    var stylerRadius = display.styler.compute(display.styler.stops_merged.r,
      display, {
        owner: this
      });

    var width, height, r;

    // if this is a circle marker w/ a styler-defined fixed radius, use that
    if (markerType === 'circle' && stylerRadius) {
      width = height = stylerRadius * 2;
      r = stylerRadius;
    }

    // otherwise, this is a dynamically-sized marker
    else {

      var dx = maxX - minX,
        dy = maxY - minY;

      var markerPadding = display.styler.compute(display.styler.stops_merged[
        'marker-padding'], display, {
        owner: this
      }) || 0;

      var patternRadius = display.styler.compute(display.styler[
        this.patternStylerKey].r, display, {
        owner: this
      });
      r = parseFloat(patternRadius) + markerPadding;

      if (markerType === 'circle') {
        width = height = Math.max(dx, dy) + 2 * r;
        r = width / 2;
      } else {
        width = dx + 2 * r;
        height = dy + 2 * r;
        if (markerType === 'rectangle') r = 0;
      }
    }

    return {
      x: (minX + maxX) / 2 - width / 2,
      y: (minY + maxY) / 2 - height / 2,
      width: width,
      height: height,
      rx: r,
      ry: r
    };

  };

  this.initMarkerData = function(display) {

    if (this.getType() !== 'STOP' && this.getType() !== 'MULTI') return;

    this.mergedMarkerData = this.constructMergedMarker(display);

    this.placeOffsets = {
      x: 0,
      y: 0
    };
    if (this.adjacentPlace) {
      var placeBBox = this.adjacentPlace.getMarkerBBox();

      var placeR = display.styler.compute(display.styler.places.r, display, {
        owner: this.adjacentPlace
      });

      var placeX = display.xScale(this.adjacentPlace.worldX);
      var placeY = display.yScale(this.adjacentPlace.worldY);

      var thisR = this.mergedMarkerData.width / 2;
      var thisX = this.mergedMarkerData.x + thisR,
        thisY = this.mergedMarkerData.y + thisR;

      var dx = thisX - placeX,
        dy = thisY - placeY;
      var dist = Math.sqrt(dx * dx + dy * dy);

      if (placeR + thisR > dist) {
        var f = (placeR + thisR) / dist;
        this.placeOffsets = {
          x: (dx * f) - dx,
          y: (dy * f) - dy
        };

        this.mergedMarkerData.x += this.placeOffsets.x;
        this.mergedMarkerData.y += this.placeOffsets.y;

        each(this.graphVertex.incidentEdges(), function(edge) {
          each(edge.renderSegments, function(segment) {
            segment.refreshRenderData(display);
          });
        });
      }
    }
  };

  this.refreshLabel = function(display) {
    if (!this.renderLabel) return;
    this.label.refresh(display);
  };

  this.getMarkerBBox = function() {
    return this.markerSvg.node().getBBox();
  };

  this.setFocused = function(focused) {
    this.focused = focused;
  };

  this.isFocused = function() {
    return (this.focused === true);
  };

  this.runFocusTransition = function(display, callback) {};

  this.setAllPatternsFocused = function() {};

  this.getZIndex = function() {
    return this.zIndex;
  };

  this.getAverageCoord = function() {
    var dataArray = this.getRenderDataArray();

    var xTotal = 0,
      yTotal = 0;
    each(dataArray, function(data) {
      xTotal += data.x;
      yTotal += data.y;
    });

    return {
      x: xTotal / dataArray.length,
      y: yTotal / dataArray.length
    };
  };

  this.hasRenderData = function() {
    var dataArray = this.getRenderDataArray();
    return (dataArray && dataArray.length > 0);
  };

  this.makeDraggable = function(transitive) {};

  this.toString = function() {
    return this.getType() + ' point: ' + this.getId() + ' (' + this.getName() +
      ')';
  };

});

/**
 * Expose `Point`
 */

module.exports = Point;