More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Layer / Text.js
blob:a/labs/openlayers/lib/OpenLayers/Layer/Text.js -> blob:b/labs/openlayers/lib/OpenLayers/Layer/Text.js
  /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the Clear BSD license.
  * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
   
   
  /**
  * @requires OpenLayers/Layer/Markers.js
  * @requires OpenLayers/Format/Text.js
  * @requires OpenLayers/Request/XMLHttpRequest.js
  */
   
  /**
  * Class: OpenLayers.Layer.Text
  * This layer creates markers given data in a text file. The <location>
  * property of the layer (specified as a property of the options argument
  * in the <OpenLayers.Layer.Text> constructor) points to a tab delimited
  * file with data used to create markers.
  *
  * The first row of the data file should be a header line with the column names
  * of the data. Each column should be delimited by a tab space. The
  * possible columns are:
  * - *point* lat,lon of the point where a marker is to be placed
  * - *lat* Latitude of the point where a marker is to be placed
  * - *lon* Longitude of the point where a marker is to be placed
  * - *icon* or *image* URL of marker icon to use.
  * - *iconSize* Size of Icon to use.
  * - *iconOffset* Where the top-left corner of the icon is to be placed
  * relative to the latitude and longitude of the point.
  * - *title* The text of the 'title' is placed inside an 'h2' marker
  * inside a popup, which opens when the marker is clicked.
  * - *description* The text of the 'description' is placed below the h2
  * in the popup. this can be plain text or HTML.
  *
  * Example text file:
  * (code)
  * lat lon title description iconSize iconOffset icon
  * 10 20 title description 21,25 -10,-25 http://www.openlayers.org/dev/img/marker.png
  * (end)
  *
  * Inherits from:
  * - <OpenLayers.Layer.Markers>
  */
  OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, {
   
  /**
  * APIProperty: location
  * {String} URL of text file. Must be specified in the "options" argument
  * of the constructor. Can not be changed once passed in.
  */
  location:null,
   
  /**
  * Property: features
  * {Array(<OpenLayers.Feature>)}
  */
  features: null,
   
  /**
  * APIProperty: formatOptions
  * {Object} Hash of options which should be passed to the format when it is
  * created. Must be passed in the constructor.
  */
  formatOptions: null,
   
  /**
  * Property: selectedFeature
  * {<OpenLayers.Feature>}
  */
  selectedFeature: null,
   
  /**
  * Constructor: OpenLayers.Layer.Text
  * Create a text layer.
  *
  * Parameters:
  * name - {String}
  * options - {Object} Object with properties to be set on the layer.
  * Must include <location> property.
  */
  initialize: function(name, options) {
  OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments);
  this.features = new Array();
  },
   
  /**
  * APIMethod: destroy
  */
  destroy: function() {
  // Warning: Layer.Markers.destroy() must be called prior to calling
  // clearFeatures() here, otherwise we leak memory. Indeed, if
  // Layer.Markers.destroy() is called after clearFeatures(), it won't be
  // able to remove the marker image elements from the layer's div since
  // the markers will have been destroyed by clearFeatures().
  OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments);
  this.clearFeatures();
  this.features = null;
  },
   
  /**
  * Method: loadText
  * Start the load of the Text data. Don't do this when we first add the layer,
  * since we may not be visible at any point, and it would therefore be a waste.
  */
  loadText: function() {
  if (!this.loaded) {
  if (this.location != null) {
   
  var onFail = function(e) {
  this.events.triggerEvent("loadend");
  };
   
  this.events.triggerEvent("loadstart");
  OpenLayers.Request.GET({
  url: this.location,
  success: this.parseData,
  failure: onFail,
  scope: this
  });
  this.loaded = true;
  }
  }
  },
   
  /**
  * Method: moveTo
  * If layer is visible and Text has not been loaded, load Text.
  *
  * Parameters:
  * bounds - {Object}
  * zoomChanged - {Object}
  * minor - {Object}
  */
  moveTo:function(bounds, zoomChanged, minor) {
  OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments);
  if(this.visibility && !this.loaded){
  this.loadText();
  }
  },
   
  /**
  * Method: parseData
  *
  * Parameters:
  * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>}
  */
  parseData: function(ajaxRequest) {
  var text = ajaxRequest.responseText;
   
  var options = {};
   
  OpenLayers.Util.extend(options, this.formatOptions);
   
  if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
  options.externalProjection = this.projection;
  options.internalProjection = this.map.getProjectionObject();
  }
   
  var parser = new OpenLayers.Format.Text(options);
  var features = parser.read(text);
  for (var i=0, len=features.length; i<len; i++) {
  var data = {};
  var feature = features[i];
  var location;
  var iconSize, iconOffset;
   
  location = new OpenLayers.LonLat(feature.geometry.x,
  feature.geometry.y);
   
  if (feature.style.graphicWidth
  && feature.style.graphicHeight) {
  iconSize = new OpenLayers.Size(
  feature.style.graphicWidth,
  feature.style.graphicHeight);
  }
   
  // FIXME: At the moment, we only use this if we have an
  // externalGraphic, because icon has no setOffset API Method.
  /**
  * FIXME FIRST!!
  * The Text format does all sorts of parseFloating
  * The result of a parseFloat for a bogus string is NaN. That
  * means the three possible values here are undefined, NaN, or a
  * number. The previous check was an identity check for null. This
  * means it was failing for all undefined or NaN. A slightly better
  * check is for undefined. An even better check is to see if the
  * value is a number (see #1441).
  */
  if (feature.style.graphicXOffset !== undefined
  && feature.style.graphicYOffset !== undefined) {
  iconOffset = new OpenLayers.Pixel(
  feature.style.graphicXOffset,
  feature.style.graphicYOffset);
  }
   
  if (feature.style.externalGraphic != null) {
  data.icon = new OpenLayers.Icon(feature.style.externalGraphic,
  iconSize,
  iconOffset);
  } else {
  data.icon = OpenLayers.Marker.defaultIcon();
   
  //allows for the case where the image url is not
  // specified but the size is. use a default icon
  // but change the size
  if (iconSize != null) {
  data.icon.setSize(iconSize);
  }
  }
   
  if ((feature.attributes.title != null)
  && (feature.attributes.description != null)) {
  data['popupContentHTML'] =
  '<h2>'+feature.attributes.title+'</h2>' +
  '<p>'+feature.attributes.description+'</p>';
  }
   
  data['overflow'] = feature.attributes.overflow || "auto";
   
  var markerFeature = new OpenLayers.Feature(this, location, data);
  this.features.push(markerFeature);
  var marker = markerFeature.createMarker();
  if ((feature.attributes.title != null)
  && (feature.attributes.description != null)) {
  marker.events.register('click', markerFeature, this.markerClick);
  }
  this.addMarker(marker);
  }
  this.events.triggerEvent("loadend");
  },
   
  /**
  * Property: markerClick
  *
  * Parameters:
  * evt - {Event}
  */
  markerClick: function(evt) {
  var sameMarkerClicked = (this == this.layer.selectedFeature);
  this.layer.selectedFeature = (!sameMarkerClicked) ? this : null;
  for(var i=0, len=this.layer.map.popups.length; i<len; i++) {
  this.layer.map.removePopup(this.layer.map.popups[i]);
  }
  if (!sameMarkerClicked) {
  this.layer.map.addPopup(this.createPopup());
  }
  OpenLayers.Event.stop(evt);
  },
   
  /**
  * Method: clearFeatures
  */
  clearFeatures: function() {
  if (this.features != null) {
  while(this.features.length > 0) {
  var feature = this.features[0];
  OpenLayers.Util.removeItem(this.features, feature);
  feature.destroy();
  }
  }
  },
   
  CLASS_NAME: "OpenLayers.Layer.Text"
  });