PageRenderTime 25ms CodeModel.GetById 7ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 1ms

/src/com/google/maps/extras/dragzoomcontrol/DragZoomControl.as

http://gmaps-utility-library-flash.googlecode.com/
ActionScript | 425 lines | 234 code | 47 blank | 144 comment | 4 complexity | 5b669ba0c56838831045b4b67cba702f MD5 | raw file
  1/* 
  2 * DragZoomControl v1.0
  3 * Author: Brian Richardson
  4 * Email: irieb@mac.com
  5 * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
  6 * 
  7 * Magifying glass image pulled from the following source:
  8 * http://commons.wikimedia.org/wiki/File:Gnome-zoom-in.svg
  9 * Used in this component under their GNU General Public License
 10 *
 11 * Enables drag zoom functionality 
 12 *
 13 * The control is enabled when a user clicks the magnifying 
 14 * glass image.
 15 *
 16 * When the control is enable the control listens for a mouse click
 17 * then mouse move to render the selection area
 18 *
 19 * On mouseUp the map will center the selection and zoom to the
 20 * highest possible level on the selected bounds.
 21 *
 22 * A second magnifying glass will appear to enable the user to
 23 * back out to the last map position
 24 */
 25package com.google.maps.extras.dragzoomcontrol
 26{
 27	import com.google.maps.LatLng;
 28	import com.google.maps.LatLngBounds;
 29	import com.google.maps.MapMouseEvent;
 30	import com.google.maps.controls.ControlBase;
 31	import com.google.maps.controls.ControlPosition;
 32	import com.google.maps.interfaces.IMap;
 33	import com.google.maps.overlays.Polyline;
 34	
 35	import flash.display.BitmapData;
 36	import flash.display.DisplayObject;
 37	import flash.display.Shape;
 38	import flash.display.Sprite;
 39	import flash.events.MouseEvent;
 40	import flash.filters.BevelFilter;
 41	import flash.filters.BitmapFilterQuality;
 42	import flash.filters.BitmapFilterType;
 43	import flash.geom.Matrix;
 44	import flash.geom.Point;
 45	import flash.text.TextField;
 46	import flash.text.TextFieldAutoSize;
 47	import flash.text.TextFormat;
 48	
 49	/**
 50	 *  Dispatched when a Zoom is committed
 51	 * 
 52	 *  @eventType mx.events.FlexEvent.DATA_CHANGE
 53	 */
 54	[Event(name="zoomCommit", type="com.google.maps.extras.dragzoomcontrol.events.DragZoomEvent")]
 55	public class DragZoomControl extends ControlBase {
 56				
 57		//static constants
 58		private static const ACTIVE_ALPHA:Number = 1;
 59		private static const INACTIVE_ALPHA:Number = .7;
 60		
 61		//Default configurable properties values
 62		public static const DEFAULT_SELECTION_BG_COLOR:Number = 0xFFFFFF;
 63		public static const DEFAULT_SELECTION_ALPHA:Number = 0.5;
 64		public static const DEFAUT_LINE_COLOR:Number = 0x000000;	
 65		public static const DEFAUT_DRAG_ZOOM_MSG:String = "click and drag mouse to zoom into area";								
 66		public static const DEFAULT_MARGIN_TOP:int = 7;
 67		public static const DEFAULT_MARGIN_LEFT:int = 7;
 68		
 69		//zoom-in image
 70		[Embed(source="/assets/images/zoom-in.png")]
 71		private var zoomInImg_:Class;
 72		
 73		//zoom-out image
 74		[Embed(source="/assets/images/zoom-out.png")]
 75		private var zoomOutImg_:Class;	
 76		
 77		//configurable properties
 78		private var selectionBGColor_:Number;
 79		private var selectionAlpha_:Number;
 80		private var selectionLineColor_:Number;	
 81		private var dragZoomMsg_:String;	
 82		private var marginTop_:int;
 83		private var margingLeft_:int;			
 84		
 85		//private
 86		private var map_:IMap;
 87		private var drawArea_:Sprite;
 88		private var zoomArea_:Shape;
 89		private var startXPos_:int;
 90		private var startYPos_:int;
 91		private var zoomState_:Boolean = false;
 92		
 93		private var nwPoint_:Point;
 94		private var swPoint_:Point;
 95		private var nePoint_:Point;
 96		private var sePoint_:Point;
 97		
 98		private var zoomInBtn_:Sprite;
 99		private var zoomOutBtn_:Sprite;
100		private var msg_:Sprite;
101		
102		private var mapBitmapData_:BitmapData;
103		private var mapDisplayObject_:DisplayObject;		
104
105		/**
106		 * Creates the DragZoom control
107		 *
108		 * @constructor
109		 * @param {int} The top margin of the control in points. 
110		 *   @see #DEFAULT_MARGIN_TOP
111		 * @param {int} The left margin of the control in points. 
112		 *   @see #DEFAULT_MARGIN_LEFT
113		 * @param {Number} The background color message text. 
114		 *   @see #DEFAULT_SELECTION_BG_COLOR
115		 * @param {Number} The line color of the selection area. 
116		 *   @see #DEFAUT_LINE_COLOR
117		 * @param {Number} The alpha value of the selection area. 
118		 *   @see #DEFAULT_SELECTION_ALPHA
119		 * @param {String} The message displayed on screen when the control is enabled. 
120		 *   @see #DEFAUT_DRAG_ZOOM_MSG
121		 */
122		public function DragZoomControl(
123				optMarginTop:int = DEFAULT_MARGIN_TOP,
124				optMarginLeft:int = DEFAULT_MARGIN_LEFT,
125				optSelectionBGColor:Number = DEFAULT_SELECTION_BG_COLOR,
126				optSelectionLineColor:Number = DEFAUT_LINE_COLOR,
127				optSelectionAlpha:Number = DEFAULT_SELECTION_ALPHA,
128				optDragZoomMsg:String = DEFAUT_DRAG_ZOOM_MSG) {	
129								
130			super(new ControlPosition(ControlPosition.ANCHOR_TOP_LEFT, optMarginTop, optMarginLeft));
131			selectionBGColor_ = optSelectionBGColor;
132			selectionAlpha_ = optSelectionAlpha;
133			selectionLineColor_ = optSelectionLineColor;	
134			dragZoomMsg_ = optDragZoomMsg;	
135			marginTop_ = optMarginTop;
136			margingLeft_ = optMarginLeft;	 
137			
138			//default selection effect - possibly make this configurable
139			var bf:BevelFilter = new BevelFilter(1,
140			   45,
141			   0xFFFFFF,
142			   0.8,
143			   0x000000,
144			   0.8,
145			   5,
146			   5,
147			   5,
148			   BitmapFilterQuality.HIGH,
149			   BitmapFilterType.INNER,
150			   true);
151			   
152			drawArea_ =  new Sprite();
153			drawArea_.filters = [bf];
154			addChild(drawArea_);
155		}		
156
157		/**
158		 * Initialize the control
159		 *
160		 * @param {IMap} The instance of the Map the control is being 
161		 *   added to
162		 * @private
163		 */		
164		public override function initControlWithMap(pMap:IMap):void {
165			super.initControlWithMap(map);
166			map_ = pMap;
167			addControlButton();		
168		}
169		
170		//*****************
171		//private functions
172		//*****************
173		
174		/**
175		 * @private
176		 * Sets the state of the control to listen
177		 * for Map events in order to render the selection area
178		 * 
179		 * Map dragging is disabled as it would interfere with
180		 * the drag control of the selection area
181		 *
182		 * @param {MouseEvent} event The mouse event that triggered the call
183		 */			
184		private function enableDragZoom(event:MouseEvent):void {
185			msg_.visible = true;
186			map_.disableDragging();	
187			map_.addEventListener(MapMouseEvent.MOUSE_DOWN, startZoom);
188			map_.addEventListener(MapMouseEvent.MOUSE_UP, commitZoom);
189			map_.addEventListener(MapMouseEvent.MOUSE_MOVE, updateZoom);
190			
191			mapDisplayObject_ = map_ as DisplayObject;				
192			mapBitmapData_= new BitmapData(mapDisplayObject_.width, mapDisplayObject_.height);	
193			//this wil have to wait - sandbox security exception thrown
194			//we can do all kinds of cool effects once this is supported
195			//_mapBitmapData.draw(_mapDisplayObject);					
196		}
197		
198		/**
199		 * @private
200		 * Returns the Map to the last saved position
201		 *
202		 * @param {MouseEvent} event The mouse event
203		 */			
204		private function returnToSavedPosition(event:MouseEvent):void {
205			zoomOutBtn_.visible = false;
206			map_.returnToSavedPosition();			
207		}
208
209		/**
210		 * @private
211		 * Removes Map event listener and enables map dragging
212		 */			
213		private function disableZoom():void {			
214			map_.removeEventListener(MapMouseEvent.MOUSE_DOWN, startZoom);
215			map_.removeEventListener(MapMouseEvent.MOUSE_UP, commitZoom);
216			map_.removeEventListener(MapMouseEvent.MOUSE_MOVE, updateZoom);
217			map_.enableDragging();
218		}		
219
220		/**
221		 * @private
222		 * Updates the selection area.
223		 * Cooridinates are calculated using the latitude/longitude
224		 * provided by the MapMouseEvent
225		 *
226		 * @param {MapMouseEvent} event The mouse event
227		 */			
228		private function updateZoom(event:MapMouseEvent):void {
229			if (zoomState_) {
230				var latLgn:LatLng = event.latLng;
231				var point:Point = map_.fromLatLngToViewport(latLgn);
232							
233				var zoomWidth:int = (point.x - startXPos_);
234				var zoomHeight:int = (point.y - startYPos_);
235				
236				resetDrawArea();
237
238				zoomArea_ = new Shape();
239				
240				var recX:int = (point.x - zoomWidth)-marginTop_;
241				var recY:int = (point.y - zoomHeight)-margingLeft_;
242				
243				var myMatrix:Matrix = new Matrix();
244				myMatrix.tx = -(margingLeft_);
245				myMatrix.ty = -(marginTop_);
246				
247				zoomArea_.graphics.beginBitmapFill(mapBitmapData_,myMatrix); 
248				zoomArea_.graphics.lineStyle(1, selectionLineColor_);
249				zoomArea_.graphics.drawRect(recX, recY, zoomWidth, zoomHeight);
250				zoomArea_.graphics.endFill();
251				drawArea_.addChild(zoomArea_);	
252				
253				recX = point.x - zoomWidth;
254				recY = point.y - zoomHeight; 
255				
256				nwPoint_ = new Point(recX, recY);
257				swPoint_ = new Point(recX, (recY + zoomArea_.height));
258				sePoint_ = new Point((recX + zoomArea_.width), (recY + zoomArea_.height));
259				nePoint_ = new Point((recX + zoomArea_.width), recY);
260			}		
261		}
262		
263		/**
264		 * @private
265		 * Commits the Zoom based on the selection area
266		 *
267		 * @param {MapMouseEvent} event The mouse event
268		 */			
269		private function commitZoom(event:MapMouseEvent):void {	
270			disableZoom();	
271			map_.savePosition();	
272			zoomState_ = false;
273			resetDrawArea();
274						
275			var latLngBounds:LatLngBounds = calculatePolyline();
276			positionMap(latLngBounds);			
277			
278			zoomOutBtn_.visible = true;
279			msg_.visible = false;
280			mapBitmapData_ = null;
281			mapDisplayObject_ = null;
282			
283			var evt:DragZoomEvent = new DragZoomEvent(DragZoomEvent.ZOOM_COMMIT);
284			evt.bounds = latLngBounds;			
285			dispatchEvent(evt);	
286		}
287		
288		/**
289		 * @private
290		 * Position the Map
291		 *
292		 * @param {LatLngBounds} pLatLngBounds Latitude/Longtitude bounds
293		 * used to postion the map
294		 */			
295		private function positionMap(pLatLngBounds:LatLngBounds):void {
296			map_.setCenter(pLatLngBounds.getCenter());
297			map_.setZoom(map_.getBoundsZoomLevel(pLatLngBounds));			
298		}	
299		
300		/**
301		 * @private
302		 * Sets the x/y point of the initial mouse click
303		 * on the Map
304		 *
305		 * @param {MapMouseEvent} event The mouse event
306		 */			
307		private function startZoom(event:MapMouseEvent):void {
308			zoomState_ = true;			
309			var point:Point = map_.fromLatLngToViewport(event.latLng);
310			startXPos_ = point.x;
311			startYPos_ = point.y;		
312		}
313		
314		/**
315		 * Removes the selection graphic
316		 *
317		 */			
318		private function resetDrawArea():void {
319			if (zoomArea_) {				
320				drawArea_.removeChild(zoomArea_);
321				zoomArea_ = null;
322			}					
323		}
324		
325		/**
326		 * @private
327		 * Creates a Polyline based on the graphic selection
328		 * 
329		 * The Polyline is then used to create latitude/longtitude bounds
330		 * that are used to center the Map and set the highest possible
331		 * Zoom level for the selection
332		 *
333		 */			
334		private function calculatePolyline():LatLngBounds {	  						
335			var lines:Array = 
336				[map_.fromViewportToLatLng(nwPoint_),
337				map_.fromViewportToLatLng(swPoint_),
338				map_.fromViewportToLatLng(sePoint_),
339				map_.fromViewportToLatLng(nePoint_),
340				map_.fromViewportToLatLng(nwPoint_)];			
341			var polyLine:Polyline = new Polyline(lines);
342			return polyLine.getLatLngBounds();
343		}	
344		
345		/**
346		 * @private
347		 * Used to create the rollover effect
348		 *
349		 * @param {MouseEvent} event The mouse event
350		 */			
351		private function mouseOver(event:MouseEvent):void {
352			if (event.target is Sprite) {
353				var s:Sprite = Sprite(event.target);
354				s.alpha = ACTIVE_ALPHA;				
355			}
356			return;		
357		}
358		
359		/**
360		 * @private
361		 * Used to create the rollout effect
362		 *
363		 * @param {MouseEvent} event The mouse event
364		 */		
365		private function mouseOut(event:MouseEvent):void {
366			if (event.target is Sprite) {
367				var s:Sprite = Sprite(event.target);
368				s.alpha = INACTIVE_ALPHA;				
369			}
370			return;		
371		}		
372		
373		/**
374		 * @private
375		 * Creates the control buttons (zoom in/zoom out)
376		 *
377		 */			
378		private function addControlButton():void {			
379			zoomInBtn_ = new Sprite();
380			zoomInBtn_.x = 0;
381			zoomInBtn_.y = 0;	   			    		    		    	
382			zoomInBtn_.addChild(DisplayObject(new zoomInImg_()));
383			zoomInBtn_.addEventListener(MouseEvent.CLICK, enableDragZoom);
384			zoomInBtn_.addEventListener(MouseEvent.MOUSE_OVER, mouseOver);
385			zoomInBtn_.addEventListener(MouseEvent.MOUSE_OUT, mouseOut);
386			zoomInBtn_.alpha = INACTIVE_ALPHA;
387						
388			zoomOutBtn_ = new Sprite();
389			zoomOutBtn_.x = zoomInBtn_.width;
390			zoomOutBtn_.y = 0;									    		    
391			zoomOutBtn_.addChild(DisplayObject(new zoomOutImg_()));
392			zoomOutBtn_.addEventListener(MouseEvent.CLICK, returnToSavedPosition);
393			zoomOutBtn_.addEventListener(MouseEvent.MOUSE_OVER, mouseOver);
394			zoomOutBtn_.addEventListener(MouseEvent.MOUSE_OUT, mouseOut);		    
395			zoomOutBtn_.alpha = INACTIVE_ALPHA;
396			zoomOutBtn_.visible = false;
397			
398			var center:Point = map_.fromLatLngToViewport(map_.getCenter());
399			msg_ = new Sprite();
400			msg_.x = center.x;
401			msg_.y = 10;			    		    		
402			var label:TextField = new TextField();
403			label.text = dragZoomMsg_;
404			label.selectable = false;
405			label.autoSize = TextFieldAutoSize.CENTER;
406			var format:TextFormat = new TextFormat("Verdana");
407			label.setTextFormat(format);	
408			
409			var background:Shape = new Shape();
410			background.graphics.beginFill(selectionBGColor_, selectionAlpha_);
411			background.graphics.lineStyle(1, selectionLineColor_);
412			background.graphics.drawRoundRect(label.x, label.y, label.width, label.height, 4);
413			background.graphics.endFill();
414			
415			msg_.addChild(background);	
416			msg_.addChild(label);
417			msg_.visible = false;				   	    	    
418			
419			addChild(msg_);
420			addChild(zoomInBtn_);
421			addChild(zoomOutBtn_);			
422		}		
423		
424	}
425}