More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Control / WMSGetFeatureInfo.js
blob:a/labs/openlayers/lib/OpenLayers/Control/WMSGetFeatureInfo.js -> blob:b/labs/openlayers/lib/OpenLayers/Control/WMSGetFeatureInfo.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/Hover.js
  * @requires OpenLayers/Request.js
  */
   
  /**
  * Class: OpenLayers.Control.WMSGetFeatureInfo
  * The WMSGetFeatureInfo control uses a WMS query to get information about a point on the map. The
  * information may be in a display-friendly format such as HTML, or a machine-friendly format such
  * as GML, depending on the server's capabilities and the client's configuration. This control
  * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and
  * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an
  * array of features if it successfully read the response.
  *
  * Inherits from:
  * - <OpenLayers.Control>
  */
  OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
   
  /**
  * APIProperty: hover
  * {Boolean} Send GetFeatureInfo requests when mouse stops moving.
  * Default is false.
  */
  hover: false,
   
  /**
  * APIProperty: drillDown
  * {Boolean} Drill down over all WMS layers in the map. When
  * using drillDown mode, hover is not possible, and an infoFormat that
  * returns parseable features is required. Default is false.
  */
  drillDown: false,
   
  /**
  * APIProperty: maxFeatures
  * {Integer} Maximum number of features to return from a WMS query. This
  * sets the feature_count parameter on WMS GetFeatureInfo
  * requests.
  */
  maxFeatures: 10,
   
  /** APIProperty: clickCallback
  * {String} The click callback to register in the
  * {<OpenLayers.Handler.Click>} object created when the hover
  * option is set to false. Default is "click".
  */
  clickCallback: "click",
   
  /**
  * Property: layers
  * {Array(<OpenLayers.Layer.WMS>)} The layers to query for feature info.
  * If omitted, all map WMS layers with a url that matches this <url> or
  * <layerUrls> will be considered.
  */
  layers: null,
   
  /**
  * Property: queryVisible
  * {Boolean} If true, filter out hidden layers when searching the map for
  * layers to query. Default is false.
  */
  queryVisible: false,
   
  /**
  * Property: url
  * {String} The URL of the WMS service to use. If not provided, the url
  * of the first eligible layer will be used.
  */
  url: null,
   
  /**
  * Property: layerUrls
  * {Array(String)} Optional list of urls for layers that should be queried.
  * This can be used when the layer url differs from the url used for
  * making GetFeatureInfo requests (in the case of a layer using cached
  * tiles).
  */
  layerUrls: null,
   
  /**
  * Property: infoFormat
  * {String} The mimetype to request from the server
  */
  infoFormat: 'text/html',
   
  /**
  * Property: vendorParams
  * {Object} Additional parameters that will be added to the request, for
  * WMS implementations that support them. This could e.g. look like
  * (start code)
  * {
  * radius: 5
  * }
  * (end)
  */
  vendorParams: {},
   
  /**
  * Property: format
  * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses.
  * Default is <OpenLayers.Format.WMSGetFeatureInfo>.
  */
  format: null,
   
  /**
  * Property: formatOptions
  * {Object} Optional properties to set on the format (if one is not provided
  * in the <format> property.
  */
  formatOptions: null,
   
  /**
  * APIProperty: handlerOptions
  * {Object} Additional options for the handlers used by this control, e.g.
  * (start code)
  * {
  * "click": {delay: 100},
  * "hover": {delay: 300}
  * }
  * (end)
  */
  handlerOptions: null,
   
  /**
  * Property: handler
  * {Object} Reference to the <OpenLayers.Handler> for this control
  */
  handler: null,
   
  /**
  * Property: hoverRequest
  * {<OpenLayers.Request>} contains the currently running hover request
  * (if any).
  */
  hoverRequest: null,
   
  /**
  * Constant: EVENT_TYPES
  *
  * Supported event types (in addition to those from <OpenLayers.Control>):
  * beforegetfeatureinfo - Triggered before the request is sent.
  * The event object has an *xy* property with the position of the
  * mouse click or hover event that triggers the request.
  * nogetfeatureinfo - no queryable layers were found.
  * getfeatureinfo - Triggered when a GetFeatureInfo response is received.
  * The event object has a *text* property with the body of the
  * response (String), a *features* property with an array of the
  * parsed features, an *xy* property with the position of the mouse
  * click or hover event that triggered the request, and a *request*
  * property with the request itself. If drillDown is set to true and
  * multiple requests were issued to collect feature info from all
  * layers, *text* and *request* will only contain the response body
  * and request object of the last request.
  */
  EVENT_TYPES: ["beforegetfeatureinfo", "nogetfeatureinfo", "getfeatureinfo"],
   
  /**
  * Constructor: <OpenLayers.Control.WMSGetFeatureInfo>
  *
  * Parameters:
  * options - {Object}
  */
  initialize: function(options) {
  // concatenate events specific to vector with those from the base
  this.EVENT_TYPES =
  OpenLayers.Control.WMSGetFeatureInfo.prototype.EVENT_TYPES.concat(
  OpenLayers.Control.prototype.EVENT_TYPES
  );
   
  options = options || {};
  options.handlerOptions = options.handlerOptions || {};
   
  OpenLayers.Control.prototype.initialize.apply(this, [options]);
   
  if(!this.format) {
  this.format = new OpenLayers.Format.WMSGetFeatureInfo(
  options.formatOptions
  );
  }
   
  if(this.drillDown === true) {
  this.hover = false;
  }
   
  if(this.hover) {
  this.handler = new OpenLayers.Handler.Hover(
  this, {
  'move': this.cancelHover,
  'pause': this.getInfoForHover
  },
  OpenLayers.Util.extend(this.handlerOptions.hover || {}, {
  'delay': 250
  }));
  } else {
  var callbacks = {};
  callbacks[this.clickCallback] = this.getInfoForClick;
  this.handler = new OpenLayers.Handler.Click(
  this, callbacks, this.handlerOptions.click || {});
  }
  },
   
  /**
  * Method: activate
  * Activates the control.
  *
  * Returns:
  * {Boolean} The control was effectively activated.
  */
  activate: function () {
  if (!this.active) {
  this.handler.activate();
  }
  return OpenLayers.Control.prototype.activate.apply(
  this, arguments
  );
  },
   
  /**
  * Method: deactivate
  * Deactivates the control.
  *
  * Returns:
  * {Boolean} The control was effectively deactivated.
  */
  deactivate: function () {
  return OpenLayers.Control.prototype.deactivate.apply(
  this, arguments
  );
  },
   
  /**
  * Method: getInfoForClick
  * Called on click
  *
  * Parameters:
  * evt - {<OpenLayers.Event>}
  */
  getInfoForClick: function(evt) {
  this.events.triggerEvent("beforegetfeatureinfo", {xy: evt.xy});
  // Set the cursor to "wait" to tell the user we're working on their
  // click.
  OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait");
  this.request(evt.xy, {});
  },
   
  /**
  * Method: getInfoForHover
  * Pause callback for the hover handler
  *
  * Parameters:
  * evt - {Object}
  */
  getInfoForHover: function(evt) {
  this.events.triggerEvent("beforegetfeatureinfo", {xy: evt.xy});
  this.request(evt.xy, {hover: true});
  },
   
  /**
  * Method: cancelHover
  * Cancel callback for the hover handler
  */
  cancelHover: function() {
  if (this.hoverRequest) {
  this.hoverRequest.abort();
  this.hoverRequest = null;
  }
  },
   
  /**
  * Method: findLayers
  * Internal method to get the layers, independent of whether we are
  * inspecting the map or using a client-provided array
  */
  findLayers: function() {
   
  var candidates = this.layers || this.map.layers;
  var layers = [];
  var layer, url;
  for(var i=0, len=candidates.length; i<len; ++i) {
  layer = candidates[i];
  if(layer instanceof OpenLayers.Layer.WMS &&
  (!this.queryVisible || layer.getVisibility())) {
  url = layer.url instanceof Array ? layer.url[0] : layer.url;
  // if the control was not configured with a url, set it
  // to the first layer url
  if(this.drillDown === false && !this.url) {
  this.url = url;
  }
  if(this.drillDown === true || this.urlMatches(url)) {
  layers.push(layer);
  }
  }
  }
  return layers;
  },
   
  /**
  * Method: urlMatches
  * Test to see if the provided url matches either the control <url> or one
  * of the <layerUrls>.
  *
  * Parameters:
  * url - {String} The url to test.
  *
  * Returns:
  * {Boolean} The provided url matches the control <url> or one of the
  * <layerUrls>.
  */
  urlMatches: function(url) {
  var matches = OpenLayers.Util.isEquivalentUrl(this.url, url);
  if(!matches && this.layerUrls) {
  for(var i=0, len=this.layerUrls.length; i<len; ++i) {
  if(OpenLayers.Util.isEquivalentUrl(this.layerUrls[i], url)) {
  matches = true;
  break;
  }
  }
  }
  return matches;
  },
   
  /**
  * Method: buildWMSOptions
  * Build an object with the relevant WMS options for the GetFeatureInfo request
  *
  * Parameters:
  * url - {String} The url to be used for sending the request
  * layers - {Array(<OpenLayers.Layer.WMS)} An array of layers
  * clickPosition - {<OpenLayers.Pixel>} The position on the map where the mouse
  * event occurred.
  * format - {String} The format from the corresponding GetMap request
  */
  buildWMSOptions: function(url, layers, clickPosition, format) {
  var layerNames = [], styleNames = [];
  for (var i = 0, len = layers.length; i < len; i++) {
  layerNames = layerNames.concat(layers[i].params.LAYERS);
  styleNames = styleNames.concat(this.getStyleNames(layers[i]));
  }
  var params = OpenLayers.Util.extend({
  service: "WMS",
  version: layers[0].params.VERSION,
  request: "GetFeatureInfo",
  layers: layerNames,
  query_layers: layerNames,
  styles: styleNames,
  bbox: this.map.getExtent().toBBOX(null,
  layers[0].reverseAxisOrder()),
  feature_count: this.maxFeatures,
  height: this.map.getSize().h,
  width: this.map.getSize().w,
  format: format,
  info_format: this.infoFormat
  }, (parseFloat(layers[0].params.VERSION) >= 1.3) ?
  {
  crs: this.map.getProjection(),
  i: clickPosition.x,
  j: clickPosition.y
  } :
  {
  srs: this.map.getProjection(),
  x: clickPosition.x,
  y: clickPosition.y
  }
  );
  OpenLayers.Util.applyDefaults(params, this.vendorParams);
  return {