More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Control / GetFeature.js
blob:a/labs/openlayers/lib/OpenLayers/Control/GetFeature.js -> blob:b/labs/openlayers/lib/OpenLayers/Control/GetFeature.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/Control.js
  * @requires OpenLayers/Handler/Click.js
  * @requires OpenLayers/Handler/Box.js
  * @requires OpenLayers/Handler/Hover.js
  * @requires OpenLayers/Filter/Spatial.js
  */
   
  /**
  * Class: OpenLayers.Control.GetFeature
  * Gets vector features for locations underneath the mouse cursor. Can be
  * configured to act on click, hover or dragged boxes. Uses an
  * <OpenLayers.Protocol> that supports spatial filters to retrieve
  * features from a server and fires events that notify applications of the
  * selected features.
  *
  * Inherits from:
  * - <OpenLayers.Control>
  */
  OpenLayers.Control.GetFeature = OpenLayers.Class(OpenLayers.Control, {
   
  /**
  * APIProperty: protocol
  * {<OpenLayers.Protocol>} Required. The protocol used for fetching
  * features.
  */
  protocol: null,
   
  /**
  * APIProperty: multipleKey
  * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets
  * the <multiple> property to true. Default is null.
  */
  multipleKey: null,
   
  /**
  * APIProperty: toggleKey
  * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets
  * the <toggle> property to true. Default is null.
  */
  toggleKey: null,
   
  /**
  * Property: modifiers
  * {Object} The event modifiers to use, according to the current event
  * being handled by this control's handlers
  */
  modifiers: null,
   
  /**
  * APIProperty: multiple
  * {Boolean} Allow selection of multiple geometries. Default is false.
  */
  multiple: false,
   
  /**
  * APIProperty: click
  * {Boolean} Use a click handler for selecting/unselecting features. If
  * both <click> and <box> are set to true, the click handler takes
  * precedence over the box handler if a box with zero extent was
  * selected. Default is true.
  */
  click: true,
   
  /**
  * APIProperty: single
  * {Boolean} Tells whether select by click should select a single
  * feature. If set to false, all matching features are selected.
  * If set to true, only the best matching feature is selected.
  * This option has an effect only of the <click> option is set
  * to true. Default is true.
  */
  single: true,
   
  /**
  * APIProperty: clickout
  * {Boolean} Unselect features when clicking outside any feature.
  * Applies only if <click> is true. Default is true.
  */
  clickout: true,
   
  /**
  * APIProperty: toggle
  * {Boolean} Unselect a selected feature on click. Applies only if
  * <click> is true. Default is false.
  */
  toggle: false,
   
  /**
  * APIProperty: clickTolerance
  * {Integer} Tolerance for the filter query in pixels. This has the
  * same effect as the tolerance parameter on WMS GetFeatureInfo
  * requests. Will be ignored for box selections. Applies only if
  * <click> or <hover> is true. Default is 5. Note that this not
  * only affects requests on click, but also on hover.
  */
  clickTolerance: 5,
   
  /**
  * APIProperty: hover
  * {Boolean} Send feature requests on mouse moves. Default is false.
  */
  hover: false,
   
  /**
  * APIProperty: box
  * {Boolean} Allow feature selection by drawing a box. If set to
  * true set <click> to false to disable the click handler and
  * rely on the box handler only, even for "zero extent" boxes.
  * See the description of the <click> option for additional
  * information. Default is false.
  */
  box: false,
   
  /**
  * APIProperty: maxFeatures
  * {Integer} Maximum number of features to return from a query in single mode
  * if supported by the <protocol>. This set of features is then used to
  * determine the best match client-side. Default is 10.
  */
  maxFeatures: 10,
   
  /**
  * Property: features
  * {Object} Hash of {<OpenLayers.Feature.Vector>}, keyed by fid, holding
  * the currently selected features
  */
  features: null,
   
  /**
  * Proeprty: hoverFeature
  * {<OpenLayers.Feature.Vector>} The feature currently selected by the
  * hover handler
  */
  hoverFeature: null,
   
  /**
  * APIProperty: handlerOptions
  * {Object} Additional options for the handlers used by this control. This
  * is a hash with the keys "click", "box" and "hover".
  */
  handlerOptions: null,
   
  /**
  * Property: handlers
  * {Object} Object with references to multiple <OpenLayers.Handler>
  * instances.
  */
  handlers: null,
   
  /**
  * Property: hoverResponse
  * {<OpenLayers.Protocol.Response>} The response object associated with
  * the currently running hover request (if any).
  */
  hoverResponse: null,
   
  /**
  * Property: filterType
  * {<String>} The type of filter to use when sending off a request.
  * Possible values:
  * OpenLayers.Filter.Spatial.<BBOX|INTERSECTS|WITHIN|CONTAINS>
  * Defaults to: OpenLayers.Filter.Spatial.BBOX
  */
  filterType: OpenLayers.Filter.Spatial.BBOX,
   
  /**
  * Constant: EVENT_TYPES
  *
  * Supported event types:
  * beforefeatureselected - Triggered when <click> is true before a
  * feature is selected. The event object has a feature property with
  * the feature about to select
  * featureselected - Triggered when <click> is true and a feature is
  * selected. The event object has a feature property with the
  * selected feature
  * beforefeaturesselected - Triggered when <click> is true before a
  * set of features is selected. The event object is an array of
  * feature properties with the features about to be selected.
  * Return false after receiving this event to discontinue processing
  * of all featureselected events and the featuresselected event.
  * featuresselected - Triggered when <click> is true and a set of
  * features is selected. The event object is an array of feature
  * properties of the selected features
  * featureunselected - Triggered when <click> is true and a feature is
  * unselected. The event object has a feature property with the
  * unselected feature
  * clickout - Triggered when when <click> is true and no feature was
  * selected.
  * hoverfeature - Triggered when <hover> is true and the mouse has
  * stopped over a feature
  * outfeature - Triggered when <hover> is true and the mouse moves
  * moved away from a hover-selected feature
  */
  EVENT_TYPES: ["featureselected", "featuresselected", "featureunselected",
  "clickout", "beforefeatureselected", "beforefeaturesselected",
  "hoverfeature", "outfeature"],
   
  /**
  * Constructor: OpenLayers.Control.GetFeature
  * Create a new control for fetching remote features.
  *
  * Parameters:
  * options - {Object} A configuration object which at least has to contain
  * a <protocol> property
  */
  initialize: function(options) {
  // concatenate events specific to vector with those from the base
  this.EVENT_TYPES =
  OpenLayers.Control.GetFeature.prototype.EVENT_TYPES.concat(
  OpenLayers.Control.prototype.EVENT_TYPES
  );
   
  options.handlerOptions = options.handlerOptions || {};
   
  OpenLayers.Control.prototype.initialize.apply(this, [options]);
   
  this.features = {};
   
  this.handlers = {};
   
  if(this.click) {
  this.handlers.click = new OpenLayers.Handler.Click(this,
  {click: this.selectClick}, this.handlerOptions.click || {});
  }
   
  if(this.box) {
  this.handlers.box = new OpenLayers.Handler.Box(
  this, {done: this.selectBox},
  OpenLayers.Util.extend(this.handlerOptions.box, {
  boxDivClassName: "olHandlerBoxSelectFeature"
  })
  );
  }
   
  if(this.hover) {
  this.handlers.hover = new OpenLayers.Handler.Hover(
  this, {'move': this.cancelHover, 'pause': this.selectHover},
  OpenLayers.Util.extend(this.handlerOptions.hover, {
  'delay': 250
  })
  );
  }
  },
   
  /**
  * Method: activate
  * Activates the control.
  *
  * Returns:
  * {Boolean} The control was effectively activated.
  */
  activate: function () {
  if (!this.active) {
  for(var i in this.handlers) {
  this.handlers[i].activate();
  }
  }
  return OpenLayers.Control.prototype.activate.apply(
  this, arguments
  );
  },
   
  /**
  * Method: deactivate
  * Deactivates the control.
  *
  * Returns:
  * {Boolean} The control was effectively deactivated.
  */
  deactivate: function () {
  if (this.active) {
  for(var i in this.handlers) {
  this.handlers[i].deactivate();
  }
  }
  return OpenLayers.Control.prototype.deactivate.apply(
  this, arguments
  );
  },
   
  /**
  * Method: selectClick
  * Called on click
  *
  * Parameters:
  * evt - {<OpenLayers.Event>}
  */
  selectClick: function(evt) {
  var bounds = this.pixelToBounds(evt.xy);
   
  this.setModifiers(evt);
  this.request(bounds, {single: this.single});
  },
   
  /**
  * Method: selectBox
  * Callback from the handlers.box set up when <box> selection is on
  *
  * Parameters:
  * position - {<OpenLayers.Bounds>}
  */
  selectBox: function(position) {
  var bounds;
  if (position instanceof OpenLayers.Bounds) {
  var minXY = this.map.getLonLatFromPixel(
  new OpenLayers.Pixel(position.left, position.bottom)
  );
  var maxXY = this.map.getLonLatFromPixel(
  new OpenLayers.Pixel(position.right, position.top)
  );
  bounds = new OpenLayers.Bounds(
  minXY.lon, minXY.lat, maxXY.lon, maxXY.lat
  );
   
  } else {
  if(this.click) {
  // box without extent - let the click handler take care of it
  return;
  }
  bounds = this.pixelToBounds(position);
  }
  this.setModifiers(this.handlers.box.dragHandler.evt);
  this.request(bounds);
  },
   
  /**
  * Method selectHover
  * Callback from the handlers.hover set up when <hover> selection is on
  *
  * Parameters:
  * evt {Object} - event object with an xy property
  */
  selectHover: function(evt) {
  var bounds = this.pixelToBounds(evt.xy);
  this.request(bounds, {single: true, hover: true});
  },
   
  /**
  * Method: cancelHover
  * Callback from the handlers.hover set up when <hover> selection is on
  */
  cancelHover: function() {
  if (this.hoverResponse) {
  this.protocol.abort(this.hoverResponse);
  this.hoverResponse = null;
   
  OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait");
  }
  },
   
  /**
  * Method: request
  * Sends a GetFeature request to the WFS
  *
  * Parameters:
  * bounds - {<OpenLayers.Bounds>} bounds for the request's BBOX filter
  * options - {Object} additional options for this method.
  *
  * Supported options include:
  * single - {Boolean} A single feature should be returned.
  * Note that this will be ignored if the protocol does not
  * return the geometries of the features.
  * hover - {Boolean} Do the request for the hover handler.
  */
  request: function(bounds, options) {
  options = options || {};
  var filter = new OpenLayers.Filter.Spatial({
  type: this.filterType,