]> dev.renevier.net Git - syp.git/blob - openlayers/lib/OpenLayers/Handler/MouseWheel.js
initial commit
[syp.git] / openlayers / lib / OpenLayers / Handler / MouseWheel.js
1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2  * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3  * full text of the license. */
4
5 /**
6  * @requires OpenLayers/Handler.js
7  */
8
9 /**
10  * Class: OpenLayers.Handler.MouseWheel
11  * Handler for wheel up/down events.
12  * 
13  * Inherits from:
14  *  - <OpenLayers.Handler>
15  */
16 OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
17     /** 
18      * Property: wheelListener 
19      * {function} 
20      */
21     wheelListener: null,
22
23     /** 
24      * Property: mousePosition
25      * {<OpenLayers.Pixel>} mousePosition is necessary because
26      * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
27      * value from the last mousemove.
28      */
29     mousePosition: null,
30
31     /**
32      * Constructor: OpenLayers.Handler.MouseWheel
33      *
34      * Parameters:
35      * control - {<OpenLayers.Control>} 
36      * callbacks - {Object} An object containing a single function to be
37      *                          called when the drag operation is finished.
38      *                          The callback should expect to recieve a single
39      *                          argument, the point geometry.
40      * options - {Object} 
41      */
42     initialize: function(control, callbacks, options) {
43         OpenLayers.Handler.prototype.initialize.apply(this, arguments);
44         this.wheelListener = OpenLayers.Function.bindAsEventListener(
45             this.onWheelEvent, this
46         );
47     },
48
49     /**
50      * Method: destroy
51      */    
52     destroy: function() {
53         OpenLayers.Handler.prototype.destroy.apply(this, arguments);
54         this.wheelListener = null;
55     },
56
57     /**
58      *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
59      */
60
61     /** 
62      * Method: onWheelEvent
63      * Catch the wheel event and handle it xbrowserly
64      * 
65      * Parameters:
66      * e - {Event} 
67      */
68     onWheelEvent: function(e){
69         
70         // make sure we have a map and check keyboard modifiers
71         if (!this.map || !this.checkModifiers(e)) {
72             return;
73         }
74         
75         // Ride up the element's DOM hierarchy to determine if it or any of 
76         //  its ancestors was: 
77         //   * specifically marked as scrollable
78         //   * one of our layer divs
79         //   * the map div
80         //
81         var overScrollableDiv = false;
82         var overLayerDiv = false;
83         var overMapDiv = false;
84         
85         var elem = OpenLayers.Event.element(e);
86         while((elem != null) && !overMapDiv && !overScrollableDiv) {
87
88             if (!overScrollableDiv) {
89                 try {
90                     if (elem.currentStyle) {
91                         overflow = elem.currentStyle["overflow"];
92                     } else {
93                         var style = 
94                             document.defaultView.getComputedStyle(elem, null);
95                         var overflow = style.getPropertyValue("overflow");
96                     }
97                     overScrollableDiv = ( overflow && 
98                         (overflow == "auto") || (overflow == "scroll") );
99                 } catch(err) {
100                     //sometimes when scrolling in a popup, this causes 
101                     // obscure browser error
102                 }
103             }
104
105             if (!overLayerDiv) {
106                 for(var i=0, len=this.map.layers.length; i<len; i++) {
107                     // Are we in the layer div? Note that we have two cases
108                     // here: one is to catch EventPane layers, which have a 
109                     // pane above the layer (layer.pane)
110                     if (elem == this.map.layers[i].div 
111                         || elem == this.map.layers[i].pane) { 
112                         overLayerDiv = true;
113                         break;
114                     }
115                 }
116             }
117             overMapDiv = (elem == this.map.div);
118
119             elem = elem.parentNode;
120         }
121         
122         // Logic below is the following:
123         //
124         // If we are over a scrollable div or not over the map div:
125         //  * do nothing (let the browser handle scrolling)
126         //
127         //    otherwise 
128         // 
129         //    If we are over the layer div: 
130         //     * zoom/in out
131         //     then
132         //     * kill event (so as not to also scroll the page after zooming)
133         //
134         //       otherwise
135         //
136         //       Kill the event (dont scroll the page if we wheel over the 
137         //        layerswitcher or the pan/zoom control)
138         //
139         if (!overScrollableDiv && overMapDiv) {
140             if (overLayerDiv) {
141                 this.wheelZoom(e);
142             }
143             OpenLayers.Event.stop(e);
144         }
145     },
146
147     /**
148      * Method: wheelZoom
149      * Given the wheel event, we carry out the appropriate zooming in or out,
150      *     based on the 'wheelDelta' or 'detail' property of the event.
151      * 
152      * Parameters:
153      * e - {Event}
154      */
155     wheelZoom: function(e) {
156         
157         var delta = 0;
158         if (!e) {
159             e = window.event;
160         }
161         if (e.wheelDelta) {
162             delta = e.wheelDelta/120; 
163             if (window.opera && window.opera.version() < 9.2) {
164                 delta = -delta;
165             }
166         } else if (e.detail) {
167             delta = -e.detail / 3;
168         }
169         if (delta) {
170             // add the mouse position to the event because mozilla has 
171             // a bug with clientX and clientY (see 
172             // https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
173             // getLonLatFromViewPortPx(e) returns wrong values
174             if (this.mousePosition) {
175                 e.xy = this.mousePosition;
176             } 
177             if (!e.xy) {
178                 // If the mouse hasn't moved over the map yet, then
179                 // we don't have a mouse position (in FF), so we just
180                 // act as if the mouse was at the center of the map.
181                 // Note that we can tell we are in the map -- and 
182                 // this.map is ensured to be true above.
183                 e.xy = this.map.getPixelFromLonLat(
184                     this.map.getCenter()
185                 );
186             }
187             if (delta < 0) {
188                this.callback("down", [e, delta]);
189             } else {
190                this.callback("up", [e, delta]);
191             }
192         }
193     },
194     
195     /**
196      * Method: mousemove
197      * Update the stored mousePosition on every move.
198      * 
199      * Parameters:
200      * evt - {Event} The browser event
201      *
202      * Returns: 
203      * {Boolean} Allow event propagation
204      */
205     mousemove: function (evt) {
206         this.mousePosition = evt.xy;
207     },
208
209     /**
210      * Method: activate 
211      */
212     activate: function (evt) {
213         if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
214             //register mousewheel events specifically on the window and document
215             var wheelListener = this.wheelListener;
216             OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
217             OpenLayers.Event.observe(window, "mousewheel", wheelListener);
218             OpenLayers.Event.observe(document, "mousewheel", wheelListener);
219             return true;
220         } else {
221             return false;
222         }
223     },
224
225     /**
226      * Method: deactivate 
227      */
228     deactivate: function (evt) {
229         if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
230             // unregister mousewheel events specifically on the window and document
231             var wheelListener = this.wheelListener;
232             OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
233             OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
234             OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
235             return true;
236         } else {
237             return false;
238         }
239     },
240
241     CLASS_NAME: "OpenLayers.Handler.MouseWheel"
242 });