diff options
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Handler/MouseWheel.js')
-rw-r--r-- | misc/openlayers/lib/OpenLayers/Handler/MouseWheel.js | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Handler/MouseWheel.js b/misc/openlayers/lib/OpenLayers/Handler/MouseWheel.js new file mode 100644 index 0000000..c69dff3 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Handler/MouseWheel.js @@ -0,0 +1,264 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository 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: 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: maxDelta + * {Integer} Maximum delta to collect before breaking from the current + * interval. In cumulative mode, this also limits the maximum delta + * returned from the handler. Default is Number.POSITIVE_INFINITY. + */ + maxDelta: Number.POSITIVE_INFINITY, + + /** + * 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 (CSS overflow property) + // * one of our layer divs or a div marked as scrollable + // ('olScrollable' CSS class) + // * the map div + // + var overScrollableDiv = false; + var allowScroll = false; + var overMapDiv = false; + + var elem = OpenLayers.Event.element(e); + while((elem != null) && !overMapDiv && !overScrollableDiv) { + + if (!overScrollableDiv) { + try { + var overflow; + if (elem.currentStyle) { + overflow = elem.currentStyle["overflow"]; + } else { + var style = + document.defaultView.getComputedStyle(elem, null); + overflow = style.getPropertyValue("overflow"); + } + overScrollableDiv = ( overflow && + (overflow == "auto") || (overflow == "scroll") ); + } catch(err) { + //sometimes when scrolling in a popup, this causes + // obscure browser error + } + } + + if (!allowScroll) { + allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); + if (!allowScroll) { + 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) + var layer = this.map.layers[i]; + if (elem == layer.div || elem == layer.pane) { + allowScroll = 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 or a 'olScrollable' 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 (allowScroll) { + var delta = 0; + + if (e.wheelDelta) { + delta = e.wheelDelta; + if (delta % 160 === 0) { + // opera have steps of 160 instead of 120 + delta = delta * 0.75; + } + delta = delta / 120; + } else if (e.detail) { + // detail in Firefox on OS X is 1/3 of Windows + // so force delta 1 / -1 + delta = - (e.detail / Math.abs(e.detail)); + } + this.delta += delta; + + window.clearTimeout(this._timeoutId); + if(this.interval && Math.abs(this.delta) < this.maxDelta) { + // store e because window.event might change during delay + var evt = OpenLayers.Util.extend({}, e); + this._timeoutId = window.setTimeout( + OpenLayers.Function.bind(function(){ + this.wheelZoom(evt); + }, 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) { + e.xy = this.map.events.getMousePosition(e); + if (delta < 0) { + this.callback("down", + [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); + } else { + this.callback("up", + [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); + } + } + }, + + /** + * 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" +}); |