|
/* 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" |
|
}); |
|
|