1 /***************************************
  2  * Copyright 2011, 2012 GlobWeb contributors.
  3  *
  4  * This file is part of GlobWeb.
  5  *
  6  * GlobWeb is free software: you can redistribute it and/or modify
  7  * it under the terms of the GNU Lesser General Public License as published by
  8  * the Free Software Foundation, version 3 of the License, or
  9  * (at your option) any later version.
 10  *
 11  * GlobWeb is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 14  * GNU Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU General Public License
 17  * along with GlobWeb. If not, see <http://www.gnu.org/licenses/>.
 18  ***************************************/
 19 
 20 define( function() {
 21 
 22 /**************************************************************************************************************/
 23 
 24 /** @export
 25 	@constructor
 26 	GoogleMouseNavigationHandler constructor
 27  */
 28 var GoogleMouseNavigationHandler = function(options){
 29 	
 30 	/**************************************************************************************************************/
 31 	
 32 	/**
 33  	 * Private variables
 34 	 */
 35 	
 36 	var _navigation = null;
 37 	var _pressedButton = -1;
 38 	var _lastMouseX = -1;
 39 	var _lastMouseY = -1;
 40 	var _needsStartEvent = false;
 41 	var _needsEndEvent = false;
 42 	var _dx = 0;
 43 	var _dy = 0;
 44 	var _pressedGeo = null;
 45 	var _changeInertia = null;
 46 	var _slower = 0;
 47 
 48 	/**************************************************************************************************************/
 49 	
 50 	/**
 51  	 * Private methods
 52 	 */
 53 
 54 	/**
 55 		Event handler for mouse wheel
 56 	 */
 57 	var _handleMouseWheel = function(event)
 58 	{
 59 		_navigation.globe.publish("startNavigation");
 60 		
 61 		var factor;
 62 
 63 		// Check differences between firefox and the rest of the world
 64 		if ( event.wheelDelta === undefined)
 65 		{
 66 			factor = event.detail;
 67 		}
 68 		else
 69 		{
 70 			factor = -event.wheelDelta / 120.0;	
 71 		}
 72 		
 73 		if (!_navigation.inertia )
 74 		{
 75 			// Compute mouse position and corresponding lon lat before zoom
 76 			var pos = _navigation.globe.renderContext.getXYRelativeToCanvas(event);
 77 			var geo = _navigation.globe.getLonLatFromPixel( pos[0], pos[1] );
 78 		}
 79 		
 80 		_navigation.zoom(factor);
 81 		
 82 		// Stop all animations when an event is received
 83 		_navigation.stopAnimations();
 84 		
 85 		// Launch inertia if needed
 86 		if ( _navigation.inertia )
 87 		{
 88 			_navigation.inertia.launch("zoom", factor < 0 ? -1 : 1 );
 89 		}
 90 		else{
 91 			// Compute the new position of lon lat and pan the globe toward it
 92 			if(geo){
 93 				var pos2 = _navigation.globe.getPixelFromLonLat(geo[0], geo[1]);
 94 				
 95 				var dx = pos[0] - pos2[0];
 96 				var widthHeightFactor = Math.round(_navigation.globe.renderContext.canvas.width / _navigation.globe.renderContext.canvas.height);
 97 				widthHeightFactor = (widthHeightFactor < 1) ? 1 : widthHeightFactor;
 98 				dx *= widthHeightFactor;
 99 				var dy = pos[1] - pos2[1];
100 				_navigation.pan(dx, dy);
101 			}
102 		}
103 		
104 		// Stop mouse wheel to be propagated, because default is to scroll the page
105 		// This is need when using Firefox event listener on DOMMouseScroll
106 		if ( event.preventDefault )
107 		{
108 			event.preventDefault();
109 		}
110 		event.returnValue = false;
111 		
112 		_navigation.globe.publish("endNavigation");
113 		_navigation.globe.renderContext.requestFrame();
114 			
115 		// Return false to stop mouse wheel to be propagated when using onmousewheel
116 		return false;
117 	};
118 
119 	/**
120 	 * Event handler for mouse down
121 	 */
122 	var _handleMouseDown = function(event)
123 	{
124 		_pressedButton = event.button;
125 		
126 		// Stop all animations when an event is received
127 		_navigation.stopAnimations();
128 		
129 		_lastMouseX = event.clientX;
130 		_lastMouseY = event.clientY;
131 		_dx = 0;
132 		_dy = 0;
133 		
134 		// Middle click
135 		if (event.button == 1){
136 			// Cursor's style modification: Rotating icon
137 			_navigation.globe.renderContext.canvas.style.cursor = 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABeUlEQVR42u2XS07DMBCGbaCCQstzy4YDcAGWCAE3YI3omsN0XcSaGxSEWHIBDsCGLY9SykM80m/CFLkhIBycVpVi6ZetUez/S2x5JtYMudkCYJQBbGJ+pBoIgMybQKUoijrW2hnGr+jNFyILQM+8jHkLc0Nv6OeIPflC+AJ8M++1rBA+AD+a/wfCB2Bczdtp5gmIqkK8hwSQt69gcNu3gJ6BRGyB7kG/QlAAOe3rSD5zFeO6cwj3ibVRC52hTmgA2YJJVUUgML5wAFbVXN78RRV0C+TZMVUZLWJ86QCsELsxn3v/oQp6CN02hZYwvnIAloldo2efhQqAAqAAGKl7IL4JpQDpWyA9F8iVHfwmjHMBZnd/yIbzJodcEGdDtInJ0S/1wA7DE5NDNozrATSLtjE7SKmI9hg20b3JoR74qogUYgvThnMIa8SOHfPgFVEaxAbmh5jvMj71Nc8CkISYRmvoHD36mmcFcCFKOhbDgf0XuHOH9mcUrHUBoVXvIfh2krcAAAAASUVORK5CYII=), auto';
138 		}
139 		// Left and right click
140 		else{
141 			// Save the lon lat clicked
142 			var pressedPos = _navigation.globe.renderContext.getXYRelativeToCanvas(event);
143 			_pressedGeo = _navigation.globe.getLonLatFromPixel( pressedPos[0], pressedPos[1] );
144 			
145 			// Left click
146 			if(event.button == 0){
147 				// Cursor's style modification: Grabbing icon
148 				_navigation.globe.renderContext.canvas.style.cursor = 'url(data:image/png;base64,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), auto';
149 			
150 			}
151 			// Right click
152 			else{
153 				// Cursor's style modification: Zooming (same as Rotating) icon
154 				_navigation.globe.renderContext.canvas.style.cursor = 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABeUlEQVR42u2XS07DMBCGbaCCQstzy4YDcAGWCAE3YI3omsN0XcSaGxSEWHIBDsCGLY9SykM80m/CFLkhIBycVpVi6ZetUez/S2x5JtYMudkCYJQBbGJ+pBoIgMybQKUoijrW2hnGr+jNFyILQM+8jHkLc0Nv6OeIPflC+AJ8M++1rBA+AD+a/wfCB2Bczdtp5gmIqkK8hwSQt69gcNu3gJ6BRGyB7kG/QlAAOe3rSD5zFeO6cwj3ibVRC52hTmgA2YJJVUUgML5wAFbVXN78RRV0C+TZMVUZLWJ86QCsELsxn3v/oQp6CN02hZYwvnIAloldo2efhQqAAqAAGKl7IL4JpQDpWyA9F8iVHfwmjHMBZnd/yIbzJodcEGdDtInJ0S/1wA7DE5NDNozrATSLtjE7SKmI9hg20b3JoR74qogUYgvThnMIa8SOHfPgFVEaxAbmh5jvMj71Nc8CkISYRmvoHD36mmcFcCFKOhbDgf0XuHOH9mcUrHUBoVXvIfh2krcAAAAASUVORK5CYII=), auto';
155 			}
156 		}
157 		
158 		_needsStartEvent = true;
159 		
160 		// Return false to stop mouse down to be propagated when using onmousedown
161 		return false;
162 		
163 	};
164 
165 	/**
166 	 * Event handler for mouse up
167 	 */
168 	var _handleMouseUp = function(event)
169 	{
170 		// No button pressed anymore
171 		_pressedButton = -1;
172 
173 		if ( _navigation.inertia && (_dx != 0 || _dy != 0)  )
174 		{	
175 			// Left click
176 			if ( event.button == 0 )
177 			{
178 				//different behavior if the move has change from pan to rotate
179 				if(_changeInertia){
180 					_navigation.inertia.launch("rotate", _changeInertia, 0 );
181 				}
182 				else{
183 					_navigation.inertia.launch("pan", _dx, _dy );
184 				}
185 			
186 			}
187 			// Middle click
188 			else if ( event.button == 1 )
189 			{
190 				_navigation.inertia.launch("rotate", -_dx, -_dy );
191 			}
192 		}
193 
194 		// Cursor's style modification : Hand icon
195 		_navigation.globe.renderContext.canvas.style.cursor = 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/sl0p8zAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAAjElEQVR42pyRQRLAIAwCoePD8vT8jB7aONHRVuWagBuku2MmMxMAuDtnO2VmMDNJAgCQVOz0YSWbR4ZQnuWQC4cK2pLRSEoSJIHkp/nd0RFBnFMJUnkgiaAYGXrxmdeCfg2NmWxLXDWG2d15veUdhdRv7EO2A3YV+E3AKUVDsBKSXx+esEvC3dZ73QMAeuphLLn/cTIAAAAASUVORK5CYII=), auto';
196 		
197 		_pressedGeo = null;
198 		_slower = 0;
199 		
200 		if (_needsEndEvent ) {
201 			_navigation.globe.publish("endNavigation");
202 		}
203 
204 		_needsStartEvent = false;
205 		_needsEndEvent = false;
206 		
207 		// Stop mouse up event
208 		return false;
209 	};
210 
211 	/**
212 		Event handler for mouse move
213 	*/
214 	var _handleMouseMove = function(event)
215 	{
216 		// No button pressed
217 		if (_pressedButton < 0)
218 			return;
219 		
220 		_dx = (event.clientX - _lastMouseX);
221 		_dy = (event.clientY - _lastMouseY);
222 		
223 		if ( _dx == 0 && _dy == 0 )
224 			return;
225 		
226 		var ret = false;
227 		// Pan on Left click
228 		if ( _pressedButton == 0 )
229 		{
230 			if ( _needsStartEvent ) { 
231 				_navigation.globe.publish("startNavigation");
232 				_needsStartEvent  = false;
233 				_needsEndEvent = true;
234 			}
235 			
236 			// Compute the mouse position
237 			var pos = _navigation.globe.renderContext.getXYRelativeToCanvas(event);
238 			if(_pressedGeo){
239 				_changeInertia=null;
240 				var inside = _navigation.globe.getLonLatFromPixel(pos[0], pos[1]);
241 				if(inside){
242 					var pos2 = _navigation.globe.getPixelFromLonLat(_pressedGeo[0], _pressedGeo[1]);
243 					_dx = pos[0] - pos2[0];
244 					_dy = pos[1] - pos2[1];
245 					_navigation.pan( _dx, _dy );
246 				}
247 			}
248 			// If the mouse not on the globe
249 			if(!_pressedGeo || !inside){
250 				if(Math.abs(_dx) > Math.abs(_dy)){
251 					_changeInertia = (pos[1] > (_navigation.globe.renderContext.canvas.height/2)) ? -_dx : _dx;
252 				}
253 				else{
254 					_changeInertia = (pos[0] > (_navigation.globe.renderContext.canvas.width/2)) ? _dy : -_dy;
255 				}
256 				_navigation.rotate(_changeInertia,0);
257 				pos = _navigation.globe.renderContext.getXYRelativeToCanvas(event);
258 				_pressedGeo = _navigation.globe.getLonLatFromPixel(pos[0], pos[1]);
259 				if(_pressedGeo) _changeInertia=null;
260 			}
261 				
262 			_navigation.globe.renderContext.requestFrame();
263 			ret = true;
264 		}
265 		// Rotate on Middle click
266 		else if ( _pressedButton == 1 )
267 		{
268 			_navigation.rotate(-_dx,-_dy);
269 			_navigation.globe.renderContext.requestFrame();
270 			ret = true;
271 		}
272 		// Zoom on Right click
273 		else
274 		{
275 			// Mouse move is too fast for zooming, need to slow it down
276 			_slower++;
277 			if((_slower % 3 == 0) && ( _slower > 1 )){
278 			
279 				_navigation.globe.publish("startNavigation");
280 				
281 				_navigation.zoom(-_dy/10);
282 				
283 				if(_dy > 0 && _dy > _dx){
284 					// Compute the new position of lon lat and pan the globe toward it
285 					if(_pressedGeo){
286 						
287 						var pos = [_navigation.globe.renderContext.canvas.clientLeft+(_navigation.globe.renderContext.canvas.clientWidth / 2), _navigation.globe.renderContext.canvas.clientTop+(_navigation.globe.renderContext.canvas.clientHeight / 2)];
288 						var pos2 = _navigation.globe.getPixelFromLonLat(_pressedGeo[0], _pressedGeo[1]);
289 						
290 						var dx = pos[0] - pos2[0];
291 						dx = dx * 10 / 100;
292 						var dy = pos[1] - pos2[1];
293 						dy = dy * 10 / 100;
294 						
295 						_navigation.pan(dx, dy);
296 					}
297 				}
298 	
299 				// Stop all animations when an event is received
300 				_navigation.stopAnimations();
301 				
302 				_navigation.globe.publish("endNavigation");
303 				_navigation.globe.renderContext.requestFrame();
304 			}
305 			
306 			ret = true;
307 		}
308 		
309 		_lastMouseX = event.clientX;
310 		_lastMouseY = event.clientY;
311 		
312 		return ret;
313 	};
314 
315 	/**
316 		Event handler for mouse double click
317 	 */
318 	var _handleMouseDblClick = function(event)
319 	{
320 		if (event.button == 0)
321 		{
322 			var pos = _navigation.globe.renderContext.getXYRelativeToCanvas(event);
323 			var geo = _navigation.globe.getLonLatFromPixel( pos[0], pos[1] );
324 		
325 			if (geo)
326 			{
327 				_navigation.zoomTo(geo);
328 			}
329 		}
330 	};
331 	
332 	/**
333 		Event handler for mouse context menu
334 	 */
335 	var _handleContextMenu = function(event)
336 	{
337 		// Need this so browser's context menu won't show up when using right click zooming
338 		event.preventDefault();
339 		return false;
340 	};
341 	
342 
343 	/**************************************************************************************************************/
344 	
345 	 /**
346 	  * Public methods
347 	  */
348 			
349 	/** 
350 	 *	Setup the default event handlers for the _navigation
351 	 */
352 	this.install = function(nav)
353 	{
354 		_navigation = nav;
355 		
356 		var canvas = _navigation.globe.renderContext.canvas;
357 		
358 		// Cursor's style modification : Hand icon
359 		canvas.style.cursor = 'url(data:image/png;base64,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), auto';
360 
361 		
362 		// Setup the mouse event handlers
363 		canvas.addEventListener("mousedown", _handleMouseDown);
364 		document.addEventListener("mouseup", _handleMouseUp);
365 		canvas.addEventListener("mousemove", _handleMouseMove);
366 		canvas.addEventListener("contextmenu", _handleContextMenu);
367 		canvas.addEventListener("dblclick", _handleMouseDblClick);
368 			
369 		// For Firefox
370 		canvas.addEventListener("DOMMouseScroll", _handleMouseWheel);
371 		canvas.addEventListener("mousewheel", _handleMouseWheel);
372 	};
373 
374 	/** 
375 	 *	Remove the default event handlers for the _navigation
376 	 */
377 	this.uninstall = function()
378 	{
379 		// Setup the mouse event handlers
380 		var canvas = _navigation.globe.renderContext.canvas;
381 
382 		canvas.style.cursor = 'auto';
383 		
384 		canvas.removeEventListener("mousedown", _handleMouseDown);
385 		document.removeEventListener("mouseup", _handleMouseUp);
386 		canvas.removeEventListener("mousemove", _handleMouseMove);
387 		canvas.removeEventListener("contextmenu", _handleContextMenu);
388 		canvas.removeEventListener("dblclick", _handleMouseDblClick);
389 			
390 		// For Firefox
391 		canvas.removeEventListener("DOMMouseScroll", _handleMouseWheel);
392 		canvas.removeEventListener("mousewheel", _handleMouseWheel);
393 	};
394 };
395 
396 return GoogleMouseNavigationHandler;
397 
398 });
399 
400