PageRenderTime 87ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/com/modestmaps/Map.as

https://github.com/pombredanne/Elastic-Lists
ActionScript | 777 lines | 420 code | 109 blank | 248 comment | 66 complexity | ae41e900a87f3fdfd268e78cab52a89f MD5 | raw file
  1. /**
  2. * vim:et sts=4 sw=4 cindent:
  3. * @ignore
  4. *
  5. * @author migurski
  6. * @author darren
  7. * @author tom
  8. *
  9. * com.modestmaps.Map is the base class and interface for Modest Maps.
  10. *
  11. * @description Map is the base class and interface for Modest Maps.
  12. * Correctly attaching an instance of this Sprite subclass
  13. * should result in a pannable map. Controls and event
  14. * handlers must be added separately.
  15. *
  16. * @usage <code>
  17. * import com.modestmaps.Map;
  18. * import com.modestmaps.geo.Location;
  19. * import com.modestmaps.mapproviders.BlueMarbleMapProvider;
  20. * ...
  21. * var map:Map = new Map(640, 480, true, new BlueMarbleMapProvider());
  22. * addChild(map);
  23. * </code>
  24. *
  25. */
  26. package com.modestmaps
  27. {
  28. import com.modestmaps.core.*;
  29. import com.modestmaps.events.*;
  30. import com.modestmaps.geo.*;
  31. import com.modestmaps.mapproviders.IMapProvider;
  32. import com.modestmaps.mapproviders.microsoft.MicrosoftProvider;
  33. import com.modestmaps.overlays.MarkerClip;
  34. import flash.display.DisplayObject;
  35. import flash.display.Sprite;
  36. import flash.events.Event;
  37. import flash.events.MouseEvent;
  38. import flash.geom.Matrix;
  39. import flash.geom.Point;
  40. import flash.geom.Rectangle;
  41. import flash.utils.getTimer;
  42. [Event(name="startZooming", type="com.modestmaps.events.MapEvent")]
  43. [Event(name="stopZooming", type="com.modestmaps.events.MapEvent")]
  44. [Event(name="zoomedBy", type="com.modestmaps.events.MapEvent")]
  45. [Event(name="startPanning", type="com.modestmaps.events.MapEvent")]
  46. [Event(name="stopPanning", type="com.modestmaps.events.MapEvent")]
  47. [Event(name="panned", type="com.modestmaps.events.MapEvent")]
  48. [Event(name="resized", type="com.modestmaps.events.MapEvent")]
  49. [Event(name="mapProviderChanged",type="com.modestmaps.events.MapEvent")]
  50. [Event(name="beginExtentChange", type="com.modestmaps.events.MapEvent")]
  51. [Event(name="extentChanged", type="com.modestmaps.events.MapEvent")]
  52. [Event(name="beginTileLoading", type="com.modestmaps.events.MapEvent")]
  53. [Event(name="allTilesLoaded", type="com.modestmaps.events.MapEvent")]
  54. [Event(name="rendered", type="com.modestmaps.events.MapEvent")]
  55. [Event(name="markerRollOver", type="com.modestmaps.events.MarkerEvent")]
  56. [Event(name="markerRollOut", type="com.modestmaps.events.MarkerEvent")]
  57. [Event(name="markerClick", type="com.modestmaps.events.MarkerEvent")]
  58. public class Map extends Sprite
  59. {
  60. protected var mapWidth:Number;
  61. protected var mapHeight:Number;
  62. protected var __draggable:Boolean = true;
  63. /** das grid */
  64. public var grid:TileGrid;
  65. /** markers are attached here */
  66. public var markerClip:MarkerClip;
  67. /** Who do we get our Map urls from? How far can we pan? */
  68. protected var mapProvider:IMapProvider;
  69. /** fraction of width/height to pan panLeft, panRight, panUp, panDown
  70. * @default 0.333333333
  71. */
  72. public var panFraction:Number = 0.333333333;
  73. /**
  74. * Initialize the map: set properties, add a tile grid, draw it.
  75. * Default extent covers the entire globe, (+/-85, +/-180).
  76. *
  77. * @param Width of map, in pixels.
  78. * @param Height of map, in pixels.
  79. * @param Whether the map can be dragged or not.
  80. * @param Desired map provider, e.g. Blue Marble.
  81. * @param Either a MapExtent or a Location and zoom (comma separated)
  82. *
  83. * @see com.modestmaps.core.TileGrid
  84. */
  85. public function Map(width:Number=320, height:Number=240, draggable:Boolean=true, mapProvider:IMapProvider=null, ... rest)
  86. {
  87. if (!mapProvider) mapProvider = new MicrosoftProvider(MicrosoftProvider.ROAD);
  88. // TODO getter/setter for this that disables interaction in TileGrid
  89. __draggable = draggable;
  90. // don't call setMapProvider here
  91. // the extent calculations are all squirrely
  92. this.mapProvider = mapProvider;
  93. // initialize the grid (so point/location/coordinate functions should be valid after this)
  94. grid = new TileGrid(width, height, draggable, mapProvider);
  95. grid.addEventListener(Event.CHANGE, onExtentChanged);
  96. addChild(grid);
  97. setSize(width, height);
  98. markerClip = new MarkerClip(this);
  99. addChild(markerClip);
  100. // if rest was passed in from super constructor in a subclass,
  101. // it will be an array...
  102. if (rest && rest.length > 0 && rest[0] is Array) {
  103. rest = rest[0];
  104. }
  105. // (doing that is OK because none of the arguments we're expecting are Arrays)
  106. // look at ... rest arguments for MapExtent or Location/zoom
  107. if (rest && rest.length > 0 && rest[0] is MapExtent) {
  108. setExtent(rest[0] as MapExtent);
  109. }
  110. else if (rest && rest.length > 1 && rest[0] is Location && rest[1] is Number) {
  111. setCenterZoom(rest[0] as Location, rest[1] as Number);
  112. }
  113. else {
  114. // use the whole world as a default
  115. var extent:MapExtent = new MapExtent(85, -85, 180, -180);
  116. // but adjust to fit the mapprovider's outer limits if there are any:
  117. var l1:Location = mapProvider.coordinateLocation(mapProvider.outerLimits()[0]);
  118. var l2:Location = mapProvider.coordinateLocation(mapProvider.outerLimits()[1]);
  119. if (!isNaN(l1.lat) && Math.abs(l1.lat) != Infinity) {
  120. extent.north = l1.lat;
  121. }
  122. if (!isNaN(l2.lat) && Math.abs(l2.lat) != Infinity) {
  123. extent.south = l2.lat;
  124. }
  125. if (!isNaN(l1.lon) && Math.abs(l1.lon) != Infinity) {
  126. extent.west = l1.lon;
  127. }
  128. if (!isNaN(l2.lon) && Math.abs(l2.lon) != Infinity) {
  129. extent.east = l2.lon;
  130. }
  131. setExtent(extent);
  132. }
  133. //addChild(grid.debugField);
  134. }
  135. /**
  136. * Based on an array of locations, determine appropriate map
  137. * bounds using calculateMapExtent(), and inform the grid of
  138. * tile coordinate and point by calling grid.resetTiles().
  139. * Resulting map extent will ensure that all passed locations
  140. * are visible.
  141. *
  142. * @param extent the minimum area to fit inside the map view
  143. *
  144. * @see com.modestmaps.Map#calculateMapExtent
  145. * @see com.modestmaps.core.TileGrid#resetTiles
  146. */
  147. public function setExtent(extent:MapExtent):void
  148. {
  149. //trace('applying extent', extent);
  150. onExtentChanging();
  151. // tell grid what the rock is cooking
  152. grid.resetTiles(locationsCoordinate( [ extent.northWest, extent.southEast ] ));
  153. onExtentChanged();
  154. }
  155. /**
  156. * Based on a location and zoom level, determine appropriate initial
  157. * tile coordinate and point using calculateMapCenter(), and inform
  158. * the grid of tile coordinate and point by calling grid.resetTiles().
  159. *
  160. * @param Location of center.
  161. * @param Desired zoom level.
  162. *
  163. * @see com.modestmaps.Map#calculateMapExtent
  164. * @see com.modestmaps.core.TileGrid#resetTiles
  165. */
  166. public function setCenterZoom(location:Location, zoom:Number):void
  167. {
  168. if (zoom == grid.zoomLevel) {
  169. setCenter(location);
  170. }
  171. else {
  172. onExtentChanging();
  173. zoom = Math.min(Math.max(zoom, grid.minZoom), grid.maxZoom);
  174. // tell grid what the rock is cooking
  175. grid.resetTiles(mapProvider.locationCoordinate(location).zoomTo(zoom));
  176. onExtentChanged();
  177. }
  178. }
  179. /**
  180. * Based on a zoom level, determine appropriate initial
  181. * tile coordinate and point using calculateMapCenter(), and inform
  182. * the grid of tile coordinate and point by calling grid.resetTiles().
  183. *
  184. * @param Desired zoom level.
  185. *
  186. * @see com.modestmaps.Map#calculateMapExtent
  187. * @see com.modestmaps.core.TileGrid#resetTiles
  188. */
  189. public function setZoom(zoom:Number):void
  190. {
  191. if (zoom != grid.zoomLevel) {
  192. // TODO: if grid enforces this in enforceBounds, do we need to do it here too?
  193. grid.zoomLevel = Math.min(Math.max(zoom, grid.minZoom), grid.maxZoom);
  194. }
  195. }
  196. public function extentCoordinate(extent:MapExtent):Coordinate
  197. {
  198. return locationsCoordinate([ extent.northWest, extent.southEast ]);
  199. }
  200. public function locationsCoordinate(locations:Array, fitWidth:Number=0, fitHeight:Number=0):Coordinate
  201. {
  202. if (!fitWidth) fitWidth = mapWidth;
  203. if (!fitHeight) fitHeight = mapHeight;
  204. var TL:Coordinate = mapProvider.locationCoordinate(locations[0].normalize());
  205. var BR:Coordinate = TL.copy();
  206. // get outermost top left and bottom right coordinates to cover all locations
  207. for (var i:int = 1; i < locations.length; i++)
  208. {
  209. var coordinate:Coordinate = mapProvider.locationCoordinate(locations[i].normalize());
  210. TL.row = Math.min(TL.row, coordinate.row);
  211. TL.column = Math.min(TL.column, coordinate.column);
  212. TL.zoom = Math.min(TL.zoom, coordinate.zoom);
  213. BR.row = Math.max(BR.row, coordinate.row);
  214. BR.column = Math.max(BR.column, coordinate.column);
  215. BR.zoom = Math.max(BR.zoom, coordinate.zoom);
  216. }
  217. // multiplication factor between horizontal span and map width
  218. var hFactor:Number = (BR.column - TL.column) / (fitWidth / mapProvider.tileWidth);
  219. // multiplication factor expressed as base-2 logarithm, for zoom difference
  220. var hZoomDiff:Number = Math.log(hFactor) / Math.LN2;
  221. // possible horizontal zoom to fit geographical extent in map width
  222. var hPossibleZoom:Number = TL.zoom - Math.ceil(hZoomDiff);
  223. // multiplication factor between vertical span and map height
  224. var vFactor:Number = (BR.row - TL.row) / (fitHeight / mapProvider.tileHeight);
  225. // multiplication factor expressed as base-2 logarithm, for zoom difference
  226. var vZoomDiff:Number = Math.log(vFactor) / Math.LN2;
  227. // possible vertical zoom to fit geographical extent in map height
  228. var vPossibleZoom:Number = TL.zoom - Math.ceil(vZoomDiff);
  229. // initial zoom to fit extent vertically and horizontally
  230. // additionally, make sure it's not outside the boundaries set by provider limits
  231. var initZoom:Number = Math.min(hPossibleZoom, vPossibleZoom);
  232. initZoom = Math.min(initZoom, mapProvider.outerLimits()[1].zoom);
  233. initZoom = Math.max(initZoom, mapProvider.outerLimits()[0].zoom);
  234. // coordinate of extent center
  235. var centerRow:Number = (TL.row + BR.row) / 2;
  236. var centerColumn:Number = (TL.column + BR.column) / 2;
  237. var centerZoom:Number = (TL.zoom + BR.zoom) / 2;
  238. var centerCoord:Coordinate = (new Coordinate(centerRow, centerColumn, centerZoom)).zoomTo(initZoom);
  239. return centerCoord;
  240. }
  241. /*
  242. * Return a MapExtent for the current map view.
  243. * TODO: MapExtent needs adapting to deal with non-rectangular map projections
  244. *
  245. * @return MapExtent object
  246. */
  247. public function getExtent():MapExtent
  248. {
  249. var extent:MapExtent = new MapExtent();
  250. if(!mapProvider) {
  251. throw new Error("WHOAH, no mapProvider in getExtent!");
  252. }
  253. extent.northWest = mapProvider.coordinateLocation(grid.topLeftCoordinate);
  254. extent.southEast = mapProvider.coordinateLocation(grid.bottomRightCoordinate);
  255. return extent;
  256. }
  257. /*
  258. * Return the current center location and zoom of the map.
  259. *
  260. * @return Array of center and zoom: [center location, zoom number].
  261. */
  262. public function getCenterZoom():Array
  263. {
  264. return [ mapProvider.coordinateLocation(grid.centerCoordinate), grid.zoomLevel ];
  265. }
  266. /*
  267. * Return the current center location of the map.
  268. *
  269. * @return center Location
  270. */
  271. public function getCenter():Location
  272. {
  273. return mapProvider.coordinateLocation(grid.centerCoordinate);
  274. }
  275. /*
  276. * Return the current zoom level of the map.
  277. *
  278. * @return zoom number
  279. */
  280. public function getZoom():int
  281. {
  282. return Math.floor(grid.zoomLevel);
  283. }
  284. /**
  285. * Set new map size, dispatch MapEvent.RESIZED.
  286. * The MapEvent includes the newSize.
  287. *
  288. * @param w New map width.
  289. * @param h New map height.
  290. *
  291. * @see com.modestmaps.events.MapEvent.RESIZED
  292. */
  293. public function setSize(w:Number, h:Number):void
  294. {
  295. if (w != mapWidth || h != mapHeight)
  296. {
  297. mapWidth = w;
  298. mapHeight = h;
  299. // mask out out of bounds marker remnants
  300. scrollRect = new Rectangle(0,0,mapWidth,mapHeight);
  301. grid.resizeTo(new Point(mapWidth, mapHeight));
  302. dispatchEvent(new MapEvent(MapEvent.RESIZED, this.getSize()));
  303. }
  304. }
  305. /**
  306. * Get map size.
  307. *
  308. * @return Array of [width, height].
  309. */
  310. public function getSize():/*Number*/Array
  311. {
  312. var size:/*Number*/Array = [mapWidth, mapHeight];
  313. return size;
  314. }
  315. public function get size():Point
  316. {
  317. return new Point(mapWidth, mapHeight);
  318. }
  319. public function set size(value:Point):void
  320. {
  321. setSize(value.x, value.y);
  322. }
  323. /** Get map width. */
  324. public function getWidth():Number
  325. {
  326. return mapWidth;
  327. }
  328. /** Get map height. */
  329. public function getHeight():Number
  330. {
  331. return mapHeight;
  332. }
  333. /**
  334. * Get a reference to the current map provider.
  335. *
  336. * @return Map provider.
  337. *
  338. * @see com.modestmaps.mapproviders.IMapProvider
  339. */
  340. public function getMapProvider():IMapProvider
  341. {
  342. return mapProvider;
  343. }
  344. /**
  345. * Set a new map provider, repainting tiles and changing bounding box if necessary.
  346. *
  347. * @param Map provider.
  348. *
  349. * @see com.modestmaps.mapproviders.IMapProvider
  350. */
  351. public function setMapProvider(newProvider:IMapProvider):void
  352. {
  353. var previousGeometry:String;
  354. if (mapProvider)
  355. {
  356. previousGeometry = mapProvider.geometry();
  357. }
  358. var extent:MapExtent = getExtent();
  359. mapProvider = newProvider;
  360. if (grid)
  361. {
  362. grid.setMapProvider(mapProvider);
  363. }
  364. if (mapProvider.geometry() != previousGeometry)
  365. {
  366. setExtent(extent);
  367. }
  368. // among other things this will notify the marker clip that its cached coordinates are invalid
  369. dispatchEvent(new MapEvent(MapEvent.MAP_PROVIDER_CHANGED, newProvider));
  370. }
  371. /**
  372. * Get a point (x, y) for a location (lat, lon) in the context of a given clip.
  373. *
  374. * @param Location to match.
  375. * @param Movie clip context in which returned point should make sense.
  376. *
  377. * @return Matching point.
  378. */
  379. public function locationPoint(location:Location, context:DisplayObject=null):Point
  380. {
  381. var coord:Coordinate = mapProvider.locationCoordinate(location);
  382. return grid.coordinatePoint(coord, context);
  383. }
  384. /**
  385. * Get a location (lat, lon) for a point (x, y) in the context of a given clip.
  386. *
  387. * @param Point to match.
  388. * @param Movie clip context in which passed point should make sense.
  389. *
  390. * @return Matching location.
  391. */
  392. public function pointLocation(point:Point, context:DisplayObject=null):Location
  393. {
  394. var coord:Coordinate = grid.pointCoordinate(point, context);
  395. return mapProvider.coordinateLocation(coord);
  396. }
  397. /** Pan up by 1/3 (or panFraction) of the map height. */
  398. public function panUp(event:Event=null):void
  399. {
  400. panBy(0, mapHeight*panFraction);
  401. }
  402. /** Pan down by 1/3 (or panFraction) of the map height. */
  403. public function panDown(event:Event=null):void
  404. {
  405. panBy(0, -mapHeight*panFraction);
  406. }
  407. /** Pan left by 1/3 (or panFraction) of the map width. */
  408. public function panLeft(event:Event=null):void
  409. {
  410. panBy((mapWidth*panFraction), 0);
  411. }
  412. /** Pan left by 1/3 (or panFraction) of the map width. */
  413. public function panRight(event:Event=null):void
  414. {
  415. panBy(-(mapWidth*panFraction), 0);
  416. }
  417. public function panBy(px:Number, py:Number):void
  418. {
  419. if (!grid.panning && !grid.zooming) {
  420. grid.prepareForPanning();
  421. grid.tx += px;
  422. grid.ty += py;
  423. grid.donePanning();
  424. }
  425. }
  426. /** zoom in, keeping the requested point in the same place */
  427. public function zoomInAbout(targetPoint:Point=null, duration:Number=-1):void
  428. {
  429. zoomByAbout(1, targetPoint, duration);
  430. }
  431. /** zoom out, keeping the requested point in the same place */
  432. public function zoomOutAbout(targetPoint:Point=null, duration:Number=-1):void
  433. {
  434. zoomByAbout(-1, targetPoint, duration);
  435. }
  436. /** zoom in or out by zoomDelta, keeping the requested point in the same place */
  437. public function zoomByAbout(zoomDelta:Number, targetPoint:Point=null, duration:Number=-1):void
  438. {
  439. if (!targetPoint) targetPoint = new Point(mapWidth/2, mapHeight/2);
  440. if (grid.zoomLevel + zoomDelta < grid.minZoom) {
  441. zoomDelta = grid.minZoom - grid.zoomLevel;
  442. }
  443. else if (grid.zoomLevel + zoomDelta > grid.maxZoom) {
  444. zoomDelta = grid.maxZoom - grid.zoomLevel;
  445. }
  446. var sc:Number = Math.pow(2, zoomDelta);
  447. grid.prepareForZooming();
  448. grid.prepareForPanning();
  449. var m:Matrix = grid.getMatrix();
  450. m.translate(-targetPoint.x, -targetPoint.y);
  451. m.scale(sc, sc);
  452. m.translate(targetPoint.x, targetPoint.y);
  453. grid.setMatrix(m);
  454. grid.doneZooming();
  455. grid.donePanning();
  456. }
  457. public function getRotation():Number
  458. {
  459. var m:Matrix = grid.getMatrix();
  460. var px:Point = m.deltaTransformPoint(new Point(0, 1));
  461. return Math.atan2(px.y, px.x);
  462. }
  463. /** rotate to angle (radians), keeping the requested point in the same place */
  464. public function setRotation(angle:Number, targetPoint:Point=null):void
  465. {
  466. var rotation:Number = getRotation();
  467. rotateByAbout(angle - rotation, targetPoint);
  468. }
  469. /** rotate by angle (radians), keeping the requested point in the same place */
  470. public function rotateByAbout(angle:Number, targetPoint:Point=null):void
  471. {
  472. if (!targetPoint) targetPoint = new Point(mapWidth/2, mapHeight/2);
  473. grid.prepareForZooming();
  474. grid.prepareForPanning();
  475. var m:Matrix = grid.getMatrix();
  476. m.translate(-targetPoint.x, -targetPoint.y);
  477. m.rotate(angle);
  478. m.translate(targetPoint.x, targetPoint.y);
  479. grid.setMatrix(m);
  480. grid.doneZooming();
  481. grid.donePanning();
  482. }
  483. /** zoom in and put the given location in the center of the screen, or optionally at the given targetPoint */
  484. public function panAndZoomIn(location:Location, targetPoint:Point=null):void
  485. {
  486. panAndZoomBy(2, location, targetPoint);
  487. }
  488. /** zoom out and put the given location in the center of the screen, or optionally at the given targetPoint */
  489. public function panAndZoomOut(location:Location, targetPoint:Point=null):void
  490. {
  491. panAndZoomBy(0.5, location, targetPoint);
  492. }
  493. /** zoom in or out by sc, moving the given location to the requested target */
  494. public function panAndZoomBy(sc:Number, location:Location, targetPoint:Point=null, duration:Number=-1):void
  495. {
  496. if (!targetPoint) targetPoint = new Point(mapWidth/2, mapHeight/2);
  497. var p:Point = locationPoint(location);
  498. grid.prepareForZooming();
  499. grid.prepareForPanning();
  500. var m:Matrix = grid.getMatrix();
  501. m.translate(-p.x, -p.y);
  502. m.scale(sc, sc);
  503. m.translate(targetPoint.x, targetPoint.y);
  504. grid.setMatrix(m);
  505. grid.donePanning();
  506. grid.doneZooming();
  507. }
  508. /** put the given location in the middle of the map */
  509. public function setCenter(location:Location):void
  510. {
  511. onExtentChanging();
  512. // tell grid what the rock is cooking
  513. grid.resetTiles(mapProvider.locationCoordinate(location).zoomTo(grid.zoomLevel));
  514. onExtentChanged();
  515. }
  516. /**
  517. * Zoom in by one zoom level (to 200%) immediately,
  518. * rounding up to the nearest zoom level if we're currently between zooms.
  519. *
  520. * <p>Triggers MapEvent.START_ZOOMING and MapEvent.STOP_ZOOMING events.</p>
  521. *
  522. * @param event an optional event so that zoomIn can directly function as an event listener.
  523. */
  524. public function zoomIn(event:Event=null):void
  525. {
  526. zoomBy(1);
  527. }
  528. /**
  529. * Zoom out by one zoom level (to 50%) immediately,
  530. * rounding down to the nearest zoom level if we're currently between zooms.
  531. *
  532. * <p>Triggers MapEvent.START_ZOOMING and MapEvent.STOP_ZOOMING events.</p>
  533. *
  534. * @param event an optional event so that zoomOut can directly function as an event listener.
  535. */
  536. public function zoomOut(event:Event=null):void
  537. {
  538. zoomBy(-1);
  539. }
  540. /**
  541. * Adds dir to grid.zoomLevel, and rounds up or down to the nearest whole number.
  542. * Used internally by zoomIn and zoomOut (keeping it DRY, as they say)
  543. * and overridden by TweenMap for animation.
  544. *
  545. * <p>grid.zoomLevel calls the grid.scale setter for us
  546. * which will call grid.prepareForZooming if we didn't already
  547. * and grid.doneZooming after modifying the zoom level.</p>
  548. *
  549. * <p>Animating/tweening grid.scale fires START_ZOOMING, and STOP_ZOOMING
  550. * MapEvents unless you call grid.prepareForZooming first. Be sure
  551. * to also call grid.stopZooming at the end of your animation.
  552. *
  553. * @param dir the direction of zoom, generally 1 for zooming in, or -1 for zooming out
  554. *
  555. */
  556. protected function zoomBy(dir:int):void
  557. {
  558. if (!grid.panning) {
  559. var target:Number = dir < 0 ? Math.floor(grid.zoomLevel+dir) : Math.ceil(grid.zoomLevel+dir);
  560. grid.zoomLevel = Math.min(Math.max(grid.minZoom, target), grid.maxZoom);
  561. }
  562. }
  563. /**
  564. * Add a marker at the given location (lat, lon)
  565. *
  566. * @param Location of marker.
  567. * @param optionally, a sprite (where sprite.name=id) that will always be in the right place
  568. */
  569. public function putMarker(location:Location, marker:DisplayObject=null):void
  570. {
  571. markerClip.attachMarker(marker, location);
  572. }
  573. /**
  574. * Get a marker with the given id if one was created.
  575. *
  576. * @param ID of marker, opaque string.
  577. */
  578. public function getMarker(id:String):DisplayObject
  579. {
  580. return markerClip.getMarker(id);
  581. }
  582. /**
  583. * Remove a marker with the given id.
  584. *
  585. * @param ID of marker, opaque string.
  586. */
  587. public function removeMarker(id:String):void
  588. {
  589. markerClip.removeMarker(id); // also calls grid.removeMarker
  590. }
  591. public function removeAllMarkers():void {
  592. markerClip.removeAllMarkers()
  593. }
  594. /**
  595. * Dispatches MapEvent.EXTENT_CHANGED when the map is recentered.
  596. * The MapEvent includes the new extent.
  597. *
  598. * TODO: dispatch this on resize?
  599. * TODO: should we move Map to com.modestmaps.core so that this could be made internal instead of public?
  600. *
  601. * @see com.modestmaps.events.MapEvent.EXTENT_CHANGED
  602. */
  603. protected function onExtentChanged(event:Event=null):void
  604. {
  605. if (hasEventListener(MapEvent.EXTENT_CHANGED)) {
  606. dispatchEvent(new MapEvent(MapEvent.EXTENT_CHANGED, getExtent()));
  607. }
  608. }
  609. /**
  610. * Dispatches MapEvent.BEGIN_EXTENT_CHANGE when the map is about to be resized.
  611. * The MapEvent includes the current.
  612. *
  613. * @see com.modestmaps.events.MapEvent.BEGIN_EXTENT_CHANGE
  614. */
  615. protected function onExtentChanging():void
  616. {
  617. if (hasEventListener(MapEvent.BEGIN_EXTENT_CHANGE)) {
  618. dispatchEvent(new MapEvent(MapEvent.BEGIN_EXTENT_CHANGE, getExtent()));
  619. }
  620. }
  621. override public function set doubleClickEnabled(enabled:Boolean):void
  622. {
  623. super.doubleClickEnabled = enabled;
  624. trace("doubleClickEnabled on Map is no longer necessary!");
  625. trace("\tto enable useful defaults, use:");
  626. trace("\tmap.addEventListener(MouseEvent.DOUBLE_CLICK, map.onDoubleClick);");
  627. }
  628. /** pans and zooms in on double clicked location */
  629. public function onDoubleClick(event:MouseEvent):void
  630. {
  631. if (!__draggable) return;
  632. var p:Point = grid.globalToLocal(new Point(event.stageX, event.stageY));
  633. if (event.shiftKey) {
  634. if (grid.zoomLevel > grid.minZoom) {
  635. zoomOutAbout(p);
  636. }
  637. else {
  638. panBy(mapWidth/2 - p.x, mapHeight/2 - p.y);
  639. }
  640. }
  641. else if (event.ctrlKey) {
  642. panAndZoomIn(pointLocation(p));
  643. }
  644. else {
  645. if (grid.zoomLevel < grid.maxZoom) {
  646. zoomInAbout(p);
  647. }
  648. else {
  649. panBy(mapWidth/2 - p.x, mapHeight/2 - p.y);
  650. }
  651. }
  652. }
  653. private var previousWheelEvent:Number = 0;
  654. private var minMouseWheelInterval:Number = 100;
  655. public function onMouseWheel(event:MouseEvent):void
  656. {
  657. if (getTimer() - previousWheelEvent > minMouseWheelInterval) {
  658. if (event.delta > 0) {
  659. zoomInAbout(new Point(mouseX, mouseY), 0);
  660. }
  661. else if (event.delta < 0) {
  662. zoomOutAbout(new Point(mouseX, mouseY), 0);
  663. }
  664. previousWheelEvent = getTimer();
  665. }
  666. }
  667. }
  668. }