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