Commits

mkorpela committed e9b1744

New mouse wheel handler that zooms so that mouse position is kept fixed

  • Participants
  • Parent commits 9ae542b

Comments (0)

Files changed (2)

File openscales-core/src/main/flex/org/openscales/core/Map.as

 {
 	import com.gskinner.motion.GTween;
 	
-	import flash.display.Bitmap;
-	import flash.display.BitmapData;
-	import flash.display.DisplayObject;
-	import flash.display.Sprite;
-	import flash.geom.Rectangle;
-	import flash.utils.getQualifiedClassName;
+    import flash.display.Bitmap;
+    import flash.display.BitmapData;
+    import flash.display.DisplayObject;
+    import flash.display.Sprite;
+    import flash.geom.Rectangle;
+    import flash.utils.getQualifiedClassName;
 	
 	import org.openscales.core.basetypes.Bounds;
 	import org.openscales.core.basetypes.DraggableSprite;
 		}
 		public function set zoom(newZoom:Number):void 
 		{
-			 if (this.isValidZoomLevel(newZoom)) {
-			 	
-			 	//Dispatch a MapEvent with the old and new zoom
-				var mapEvent:MapEvent = new MapEvent(MapEvent.ZOOM_START,this);
-				mapEvent.oldZoom = this.zoom;
-				mapEvent.newZoom = newZoom;
-				this.dispatchEvent(mapEvent);
-			 	
-				if (this.tweenZoomEnabled)
-				{
-					this.zoomTransition(newZoom);
-				} else {
-					setCenter(null, newZoom);
-				}
-
-			} 
+			 this.setZoom(newZoom, this.center); 
 		}
-
+		
+		public function setZoom(newZoom:Number, newCenter:LonLat):void {
+			
+			if (this.isValidZoomLevel(newZoom)) {
+				
+				//Dispatch a MapEvent with the old and new zoom
+                var mapEvent:MapEvent = new MapEvent(MapEvent.ZOOM_START,this);
+                mapEvent.oldZoom = this.zoom;
+                mapEvent.newZoom = newZoom;
+                this.dispatchEvent(mapEvent);
+                
+                if (this.tweenZoomEnabled)
+                {
+                    this.zoomTransition(newZoom, newCenter);
+                } else {
+                    this.setCenter(newCenter, newZoom);
+                }
+				
+			}
+		}
+		
 		/**
 		 * Copy the layerContainer in a bitmap and display this (this function is use for zoom)
 		 */
-		private function zoomTransition(newZoom:Number = -1):void {
+		private function zoomTransition(newZoom:Number, newCenter:LonLat):void {
 			if (!_zooming && newZoom >= 0) {
 				
 				// Disable more zooming until this zooming is complete 
 				this._zooming = true;
 
-				// We calculate de scale multiplicator according to the actual and new resolution
-				var resMult:Number = this.resolution / this.baseLayer.resolutions[newZoom];
+				// We calculate the scale multiplicator according to the actual and new resolution
+				const resMult:Number = this.resolution / this.baseLayer.resolutions[newZoom];
 				// We intsanciate a bitmapdata with map's size
-				var bitmapData:BitmapData = new BitmapData(this.width,this.height);
+				const bitmapData:BitmapData = new BitmapData(this.width,this.height);
 				
 
 				// We draw the old transition before drawing the better-fitting tiles on top and removing the old transition. 
 				this.layerContainer.visible = false;
 
 				//We calculate the bitmapTransition position
-				var x:Number = this.bitmapTransition.x-((resMult-1)*this.bitmapTransition.width)/2;
-				var y:Number = this.bitmapTransition.y-((resMult-1)*this.bitmapTransition.height)/2;
-
+				const pix:Pixel = this.getMapPxFromLonLat(newCenter);
+				const bt:DraggableSprite = this.bitmapTransition;
+                const oldCenterPix:Pixel = new Pixel(bt.x+bt.width/2, bt.y+bt.height/2);
+                const centerOffset:Pixel = new Pixel(oldCenterPix.x-pix.x, oldCenterPix.y-pix.y);
+                const alpha:Number = Math.pow(2, newZoom-this.zoom);
+                const x:Number = bt.x-((resMult-1)*(bt.width))/2+alpha*centerOffset.x;
+                const y:Number = bt.y-((resMult-1)*(bt.height))/2+alpha*centerOffset.y
+				
 				//The tween effect to scale and re-position the bitmapTransition
-				var tween:GTween = new GTween(this.bitmapTransition,0.3,
+				const tween:GTween = new GTween(this.bitmapTransition,0.3,
 					{
 						scaleX: resMult,
 						scaleY: resMult,
 			// The zoom tween callback method defined here to avoid a class attribute for newZoom
 			function clbZoomTween(tween:GTween):void {
 				_zooming = false;
-				setCenter(null, newZoom);
+				setCenter(newCenter, newZoom);
 				layerContainer.visible = true;
 
 			} 

File openscales-core/src/main/flex/org/openscales/core/handler/mouse/WheelHandler.as

 package org.openscales.core.handler.mouse {
 
-	import flash.events.MouseEvent;
+    import flash.events.Event;
+    import flash.events.MouseEvent;
+    import flash.events.TimerEvent;
+    import flash.utils.Timer;
 
 	import org.openscales.core.Map;
-	import org.openscales.core.basetypes.LonLat;
 	import org.openscales.core.basetypes.Pixel;
-	import org.openscales.core.basetypes.Size;
 	import org.openscales.core.handler.Handler;
 
 	/**
 	 */
 	public class WheelHandler extends Handler {
 
+        private var timer:Timer;
+        private var delta:Number;
+
 		public function WheelHandler(target:Map = null, active:Boolean = true){
 			super(target,active);
+			timer = new Timer(50,1);
+            timer.addEventListener(TimerEvent.TIMER, doZoom);
 		}
 
 		override protected function registerListeners():void{
 		}
 
 		private function onMouseWheel(event:MouseEvent):void{
-
-			if(event.delta > 0) {
-				this.map.zoom++;
-			} else {
-				this.map.zoom--;
-			}
-
+            this.delta = event.delta;
+            this.timer.reset();
+            this.timer.start();
 		}
+		
+		private function doZoom(event:Event):void {
+            const px:Pixel = new Pixel(this.map.mouseX, this.map.mouseY);
+            const centerPx:Pixel = new Pixel(this.map.width/2, this.map.height/2);
+            var newCenterPx:Pixel;
+            var zoom:Number = this.map.zoom;
+            if(this.delta > 0) { 
+                 newCenterPx = new Pixel((px.x+centerPx.x)/2, (px.y+centerPx.y)/2);
+                 zoom++;
+            } else {
+                 newCenterPx = new Pixel(2*centerPx.x-px.x, 2*centerPx.y-px.y);
+                 zoom--;
+            }
+            this.map.setZoom(zoom, this.map.getLonLatFromMapPx(newCenterPx));
+        }
 
 	}
 }