PageRenderTime 33ms CodeModel.GetById 2ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/com/google/maps/extras/markerclusterer/Cluster.as

http://gmaps-utility-library-flash.googlecode.com/
ActionScript | 304 lines | 138 code | 22 blank | 144 comment | 31 complexity | 415ebc226c6d3a98545f30ed191cbebd MD5 | raw file
  1/**
  2 * @name MarkerClusterer for Flash
  3 * @version 1.0
  4 * @author Xiaoxi Wu
  5 * @copyright (c) 2009 Xiaoxi Wu
  6 * @fileoverview
  7 * Ported from Javascript to Actionscript 3 by Sean Toru
  8 * Ported for use in Flex (removal of fl. libraries) by Ian Watkins
  9 * Reflectored for both Flash and Flex, 
 10 * and maintained by Juguang XIAO (juguang@gmail.com)
 11 * 
 12 * This actionscript library creates and manages per-zoom-level 
 13 * clusters for large amounts of markers (hundreds or thousands).
 14 * This library was inspired by the <a href="http://www.maptimize.com">
 15 * Maptimize</a> hosted clustering solution.
 16 * <br /><br/>
 17 * <b>How it works</b>:<br/>
 18 * The <code>MarkerClusterer</code> will group markers into clusters according to
 19 * their distance from a cluster's center. When a marker is added,
 20 * the marker cluster will find a position in all the clusters, and 
 21 * if it fails to find one, it will create a new cluster with the marker.
 22 * The number of markers in a cluster will be displayed
 23 * on the cluster marker. When the map viewport changes,
 24 * <code>MarkerClusterer</code> will destroy the clusters in the viewport 
 25 * and regroup them into new clusters.
 26 *
 27 */
 28
 29
 30/*
 31 * Licensed under the Apache License, Version 2.0 (the "License");
 32 * you may not use this file except in compliance with the License.
 33 * You may obtain a copy of the License at
 34 *
 35 *     http://www.apache.org/licenses/LICENSE-2.0
 36 *
 37 * Unless required by applicable law or agreed to in writing, software
 38 * distributed under the License is distributed on an "AS IS" BASIS,
 39 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 40 * See the License for the specific language governing permissions and
 41 * limitations under the License.
 42 */
 43
 44package com.google.maps.extras.markerclusterer
 45{
 46import com.google.maps.LatLng;
 47import com.google.maps.LatLngBounds;
 48import com.google.maps.interfaces.IMap;
 49import com.google.maps.interfaces.IPane;
 50import com.google.maps.overlays.Marker;
 51
 52import flash.geom.Point;
 53import flash.geom.Rectangle;
 54/**
 55 * class Cluster is a structure to manage markers which fall into a single cluster.
 56 * 
 57 */ 
 58internal class Cluster
 59{
 60	private var center_				: LatLng;
 61	private var markers_			: Array;
 62	private var markerClusterer_	: MarkerClusterer;
 63//	private var map_				: IMap;
 64	private var clusterMarker_		: ClusterMarker;
 65	private var zoom_				: Number;
 66	private var _pane:IPane ;
 67	
 68	/**
 69	 * class Cluster is a structure to manage markers which fall into this cluster.
 70	 * 
 71	 */ 
 72	public function Cluster (markerClusterer : MarkerClusterer, pane:IPane)
 73	{
 74		center_ 			= null;
 75		markers_ 			= new Array();
 76		markerClusterer_ 	= markerClusterer;
 77//		map_ 				= markerClusterer.map;
 78		clusterMarker_ 		= null;
 79		zoom_ 				= markerClusterer_.zoom; // map_.getZoom();
 80		this._pane = pane;
 81	}
 82	/**
 83	 * @return an array of UnitMarker instance.
 84	 */ 
 85	public function getMarkers () : Array
 86	{
 87		return markers_;
 88	}
 89	/**
 90	 * Check whether the cluster is in the rectangle in pixels
 91	 */
 92	public function isInRectangle(bounds:Rectangle= null):Boolean{
 93		if(bounds == null){
 94			bounds = this._pane.getViewportBounds();
 95		}
 96		var centerxy:Point = this._pane.fromLatLngToPaneCoords(center_);
 97		
 98		var gridSize:Number = markerClusterer_.gridSize;
 99		if (zoom_ != _pane.map.getZoom()) //  map_.getZoom())
100		{
101			var dl:Number 	= this.markerClusterer_.zoom - zoom_;
102			gridSize 	= Math.pow(2, dl) * gridSize;
103		}
104		if(centerxy.x + gridSize < bounds.left || centerxy.x - gridSize > bounds.right){
105			return false;
106		} 
107		if(centerxy.y + gridSize < bounds.top || centerxy.y - gridSize > bounds.bottom){
108			return false;
109		}
110		return true;
111	}
112	/**
113	 * Check whether this cluster is in bounds in LatLngBounds
114	 * 
115	 * This method is considered to be replaced with isInRectangle. 
116	 * So you may not see it in the later version.
117	 */
118/* 
119	public function isInBounds (bounds : LatLngBounds = undefined) : Boolean
120	{
121		if (center_ == null)			{
122			return false;
123		}
124	
125		if (!bounds)			{
126			bounds = map_.getLatLngBounds();
127		}
128	
129		var  sw 			: Point = map_.fromLatLngToViewport(bounds.getSouthWest());
130		var  ne 			: Point	= map_.fromLatLngToViewport(bounds.getNorthEast());
131		var  centerxy 		: Point	= map_.fromLatLngToViewport(center_);
132		var  inViewport 	:Boolean 	= true;
133		var  gridSize 		: Number	= markerClusterer_.gridSize;
134	
135		if (zoom_ != map_.getZoom())
136		{
137			var  dl	: Number = map_.getZoom() - zoom_;
138			gridSize 	= Math.pow(2, dl) * gridSize;
139		}
140		
141		if (ne.x != sw.x && (centerxy.x + gridSize < sw.x || centerxy.x - gridSize > ne.x))
142		{
143			inViewport = false;
144		}
145		
146		if (inViewport && (centerxy.y + gridSize < ne.y || centerxy.y - gridSize > sw.y))
147		{
148			inViewport = false;
149		}
150		
151		return inViewport;
152	}
153	 */
154	 /* used in MarkerClusterer addMarker */
155	public function getCenter () : LatLng
156	{
157		return center_;
158	}
159	
160	public function addMarker (marker : UnitMarker) : void
161	{
162		if (center_ == null)
163		{
164			center_ = marker.getLatLng();
165		}
166		
167		markers_.push(marker);
168	}
169	
170/* 	private function removeMarker (marker : Marker) : Boolean
171	{
172
173		for (var i:int = 0; i < markers_.length; ++i)
174		{
175			if (marker == markers_[i].marker)
176			{
177				if (markers_[i].isAdded)
178				{
179					this._pane.removeOverlay(markers_[i].marker);
180				//	map_.removeOverlay(markers_[i].marker);
181				}
182				markers_.splice(i, 1);
183				
184				return true;
185			}
186		}
187		return false;
188	} */
189	
190	public function getCurrentZoom () : Number
191	{
192		return zoom_;
193	}
194	/**
195	 * This function causes to redraw the cluster.
196	 * Currently, there are three (3) places to call this function:
197	 * - 2 places in MarkerClusterer.addMarker
198	 * - 1 place in MarkerClusterer.redraw
199	 * 
200	 * @param isForced - current not in used
201	 */
202	public function redraw (isForce : Boolean) : void
203	{
204
205		if (!isForce && ! this.isInRectangle()
206		//this.isInBounds()
207		) {
208			return;
209		}
210		
211		// Set cluster zoom level.
212		zoom_ = this.markerClusterer_.zoom; //  map_.getZoom();
213	
214		var mz 	: Number = markerClusterer_.maxZoom;
215		
216		if (isNaN(mz)) {
217			mz = this.markerClusterer_.maximumResolution; // map_.getCurrentMapType().getMaximumResolution(); 
218		}
219		var marker:UnitMarker;
220		if (zoom_ >= mz || this.getTotalMarkers() == 1)
221		{
222			// If current zoom level is beyond the max zoom level or the cluster
223 			// have only one marker, the marker(s) in cluster will be showed on map.
224			for each(marker in markers_)
225			{
226				if (marker.isAdded)
227				{
228					if(!marker.visible )  marker.visible = true;
229				}
230				else
231				{
232					this._pane.addOverlay(marker);
233				//	map_.addOverlay(markers_[i]);
234					marker.isAdded = true;
235				}
236			}
237			
238			if (clusterMarker_ != null)
239			{
240			// was:	clusterMarker_.hide();
241				clusterMarker_.visible = false;
242			}
243		}
244		else
245		{
246			// Else add a cluster marker on map to show the number of markers in
247 			// this cluster.
248
249			for each(marker in markers_)
250			{
251				if (marker.isAdded && marker.visible)
252				{
253					marker.visible = false;
254				}
255			}
256			
257			if (clusterMarker_ == null)
258			{
259				clusterMarker_ = new ClusterMarker(center_, this.getTotalMarkers(), 
260					markerClusterer_.getStyles(), markerClusterer_.gridSize);
261		//		clusterMarker_.initialise(map_);
262		//		map_.addOverlay(clusterMarker_);
263				this._pane.addOverlay(clusterMarker_);
264			}
265			else
266			{
267			/* was :	
268				if (clusterMarker_.isHidden())
269				{
270					clusterMarker_.show();
271				}
272			*/	
273				if(!clusterMarker_.visible) 
274					clusterMarker_.visible = true;
275				clusterMarker_.redraw(true);
276			}
277			
278		}
279	}
280	
281	public function clearMarkers () : void
282	{
283		if (clusterMarker_ != null){
284			this._pane.removeOverlay(clusterMarker_);
285			clusterMarker_ = null;
286		//	map_.removeOverlay(clusterMarker_);
287		}
288		
289		for (var i:int = 0; i < markers_.length; ++i) {
290			if (markers_[i].isAdded){
291				markers_[i].isAdded = false;
292			// was:	map_.removeOverlay(markers_[i]);
293				this._pane.removeOverlay(markers_[i]);
294			}
295		}
296		
297		markers_ = new Array();
298	}
299	
300 	internal function getTotalMarkers () : int{
301		return markers_.length;
302	}
303}
304}