More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Handler / MouseWheel.js
blob:a/labs/openlayers/lib/OpenLayers/Handler/MouseWheel.js -> blob:b/labs/openlayers/lib/OpenLayers/Handler/MouseWheel.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/Handler.js
  */
   
  /**
  * Class: OpenLayers.Handler.MouseWheel
  * Handler for wheel up/down events.
  *
  * Inherits from:
  * - <OpenLayers.Handler>
  */
  OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
  /**
  * Property: wheelListener
  * {function}
  */
  wheelListener: null,
   
  /**
  * Property: mousePosition
  * {<OpenLayers.Pixel>} mousePosition is necessary because
  * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
  * value from the last mousemove.
  */
  mousePosition: null,
   
  /**
  * Property: interval
  * {Integer} In order to increase server performance, an interval (in
  * milliseconds) can be set to reduce the number of up/down events
  * called. If set, a new up/down event will not be set until the
  * interval has passed.
  * Defaults to 0, meaning no interval.
  */
  interval: 0,
   
  /**
  * Property: delta
  * {Integer} When interval is set, delta collects the mousewheel z-deltas
  * of the events that occur within the interval.
  * See also the cumulative option
  */
  delta: 0,
   
  /**
  * Property: cumulative
  * {Boolean} When interval is set: true to collect all the mousewheel
  * z-deltas, false to only record the delta direction (positive or
  * negative)
  */
  cumulative: true,
   
  /**
  * Constructor: OpenLayers.Handler.MouseWheel
  *
  * Parameters:
  * control - {<OpenLayers.Control>}
  * callbacks - {Object} An object containing a single function to be
  * called when the drag operation is finished.
  * The callback should expect to recieve a single
  * argument, the point geometry.
  * options - {Object}
  */
  initialize: function(control, callbacks, options) {
  OpenLayers.Handler.prototype.initialize.apply(this, arguments);
  this.wheelListener = OpenLayers.Function.bindAsEventListener(
  this.onWheelEvent, this
  );
  },
   
  /**
  * Method: destroy
  */
  destroy: function() {
  OpenLayers.Handler.prototype.destroy.apply(this, arguments);
  this.wheelListener = null;
  },
   
  /**
  * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
  */
   
  /**
  * Method: onWheelEvent
  * Catch the wheel event and handle it xbrowserly
  *
  * Parameters:
  * e - {Event}
  */
  onWheelEvent: function(e){
   
  // make sure we have a map and check keyboard modifiers
  if (!this.map || !this.checkModifiers(e)) {
  return;
  }
   
  // Ride up the element's DOM hierarchy to determine if it or any of
  // its ancestors was:
  // * specifically marked as scrollable
  // * one of our layer divs
  // * the map div
  //
  var overScrollableDiv = false;
  var overLayerDiv = false;
  var overMapDiv = false;
   
  var elem = OpenLayers.Event.element(e);
  while((elem != null) && !overMapDiv && !overScrollableDiv) {
   
  if (!overScrollableDiv) {
  try {
  if (elem.currentStyle) {
  overflow = elem.currentStyle["overflow"];
  } else {
  var style =
  document.defaultView.getComputedStyle(elem, null);
  var overflow = style.getPropertyValue("overflow");
  }
  overScrollableDiv = ( overflow &&
  (overflow == "auto") || (overflow == "scroll") );
  } catch(err) {
  //sometimes when scrolling in a popup, this causes
  // obscure browser error
  }
  }
   
  if (!overLayerDiv) {
  for(var i=0, len=this.map.layers.length; i<len; i++) {
  // Are we in the layer div? Note that we have two cases
  // here: one is to catch EventPane layers, which have a
  // pane above the layer (layer.pane)
  if (elem == this.map.layers[i].div
  || elem == this.map.layers[i].pane) {
  overLayerDiv = true;
  break;
  }
  }
  }
  overMapDiv = (elem == this.map.div);
   
  elem = elem.parentNode;
  }
   
  // Logic below is the following:
  //
  // If we are over a scrollable div or not over the map div:
  // * do nothing (let the browser handle scrolling)
  //
  // otherwise
  //
  // If we are over the layer div:
  // * zoom/in out
  // then
  // * kill event (so as not to also scroll the page after zooming)
  //
  // otherwise
  //
  // Kill the event (dont scroll the page if we wheel over the
  // layerswitcher or the pan/zoom control)
  //
  if (!overScrollableDiv && overMapDiv) {
  if (overLayerDiv) {
  var delta = 0;
  if (!e) {
  e = window.event;
  }
  if (e.wheelDelta) {
  delta = e.wheelDelta/120;
  if (window.opera && window.opera.version() < 9.2) {
  delta = -delta;
  }
  } else if (e.detail) {
  delta = -e.detail / 3;
  }
  this.delta = this.delta + delta;
   
  if(this.interval) {
  window.clearTimeout(this._timeoutId);
  this._timeoutId = window.setTimeout(
  OpenLayers.Function.bind(function(){
  this.wheelZoom(e);
  }, this),
  this.interval
  );
  } else {
  this.wheelZoom(e);
  }
  }
  OpenLayers.Event.stop(e);
  }
  },
   
  /**
  * Method: wheelZoom
  * Given the wheel event, we carry out the appropriate zooming in or out,
  * based on the 'wheelDelta' or 'detail' property of the event.
  *
  * Parameters:
  * e - {Event}
  */
  wheelZoom: function(e) {
  var delta = this.delta;
  this.delta = 0;
   
  if (delta) {
  // add the mouse position to the event because mozilla has
  // a bug with clientX and clientY (see
  // https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
  // getLonLatFromViewPortPx(e) returns wrong values
  if (this.mousePosition) {
  e.xy = this.mousePosition;
  }
  if (!e.xy) {
  // If the mouse hasn't moved over the map yet, then
  // we don't have a mouse position (in FF), so we just
  // act as if the mouse was at the center of the map.
  // Note that we can tell we are in the map -- and
  // this.map is ensured to be true above.
  e.xy = this.map.getPixelFromLonLat(
  this.map.getCenter()
  );
  }
  if (delta < 0) {
  this.callback("down", [e, this.cumulative ? delta : -1]);
  } else {
  this.callback("up", [e, this.cumulative ? delta : 1]);
  }
  }
  },
   
  /**
  * Method: mousemove
  * Update the stored mousePosition on every move.
  *
  * Parameters:
  * evt - {Event} The browser event
  *
  * Returns:
  * {Boolean} Allow event propagation
  */
  mousemove: function (evt) {
  this.mousePosition = evt.xy;
  },
   
  /**
  * Method: activate
  */
  activate: function (evt) {
  if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
  //register mousewheel events specifically on the window and document
  var wheelListener = this.wheelListener;
  OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
  OpenLayers.Event.observe(window, "mousewheel", wheelListener);
  OpenLayers.Event.observe(document, "mousewheel", wheelListener);
  return true;
  } else {
  return false;
  }
  },
   
  /**
  * Method: deactivate
  */
  deactivate: function (evt) {
  if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
  // unregister mousewheel events specifically on the window and document
  var wheelListener = this.wheelListener;
  OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
  OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
  OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
  return true;
  } else {
  return false;
  }
  },
   
  CLASS_NAME: "OpenLayers.Handler.MouseWheel"
  });