Changeset 622
- Timestamp:
- 07/20/08 17:43:15 (2 months ago)
- Files:
-
- branches/tom-tweenlite/lib/com/modestmaps/core/MapPosition.as (deleted)
- branches/tom-tweenlite/lib/com/modestmaps/core/TileGrid.as (modified) (35 diffs)
- branches/tom-tweenlite/lib/com/modestmaps/extras/ZoomSlider.as (modified) (6 diffs)
- branches/tom-tweenlite/lib/com/modestmaps/Map.as (modified) (10 diffs)
- branches/tom-tweenlite/lib/com/modestmaps/TweenMap.as (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/tom-tweenlite/lib/com/modestmaps/core/TileGrid.as
r621 r622 49 49 protected var _invertedMatrix:Matrix; // use lazy getter for this 50 50 51 // the corners of the screen, in map coordinates51 // the corners and center of the screen, in map coordinates 52 52 // (these also have lazy getters) 53 53 protected var _topLeftCoordinate:Coordinate; 54 54 protected var _bottomRightCoordinate:Coordinate; 55 protected var _centerCoordinate:Coordinate; 55 56 56 57 // where the tiles live: … … 94 95 95 96 // what zoom level of tiles is 'correct'? 96 protected var _current Zoom:int;97 protected var _currentTileZoom:int; 97 98 // so we know if we're going in or out 98 protected var previous Zoom:int;99 protected var previousTileZoom:int; 99 100 100 101 // for sorting the queue: … … 222 223 } 223 224 225 /** The classes themselves serve as factories! 226 * 227 * @param tileClass e.g. Tile, TweenTile, etc. 228 * 229 * @see http://norvig.com/design-patterns/img013.gif 230 */ 224 231 public function setTileClass(tileClass:Class):void 225 232 { … … 227 234 } 228 235 229 public function onEnterFrame(event:Event=null):void 230 { 231 // for stats... 232 var frameDuration:Number = getTimer() - lastFrameTime; 233 lastFrameTime = getTimer(); 234 235 fps = (0.9 * fps) + (0.1 * (1000.0/frameDuration)); 236 236 /** processes the tileQueue and optionally outputs stats into debugField */ 237 protected function onEnterFrame(event:Event=null):void 238 { 237 239 if (debugField.parent) { 240 // for stats... 241 var frameDuration:Number = getTimer() - lastFrameTime; 242 lastFrameTime = getTimer(); 243 244 fps = (0.9 * fps) + (0.1 * (1000.0/frameDuration)); 245 238 246 // report stats: 239 247 var tileChildren:int = 0; … … 267 275 } 268 276 277 /** 278 * figures out from worldMatrix which tiles we should be showing, adds them to the stage, adds them to the tileQueue if needed, etc. 279 */ 269 280 protected function onRender(event:Event=null):void 270 281 { … … 276 287 277 288 if (zooming && panning) { 289 // doesn't bubble, unlike MapEvent 290 // Map will pick this up and dispatch MapEvent.EXTENT_CHANGED for us 278 291 dispatchEvent(new Event(Event.CHANGE, false, false)); 279 292 } … … 288 301 } 289 302 else if (zooming) { 290 var zoomEvent:MapEvent = new MapEvent(MapEvent.ZOOMED_BY );291 zoomEvent.zoomDelta = zoomLevel-startZoom;303 var zoomEvent:MapEvent = new MapEvent(MapEvent.ZOOMED_BY, zoomLevel-startZoom); 304 // this might also be useful 292 305 zoomEvent.zoomLevel = zoomLevel; 293 306 dispatchEvent(zoomEvent); 294 307 } 295 308 else if (boundsEnforced) { 309 // doesn't bubble, unlike MapEvent 310 // Map will pick this up and dispatch MapEvent.EXTENT_CHANGED for us 296 311 dispatchEvent(new Event(Event.CHANGE, false, false)); 297 312 } 298 313 299 // find the extents of the ur-tile:300 // (where would the top left and bottom right corners of the301 // world be now if we only had one tile at zoom level 0?)302 // TODO deal with what happens with non-square projections!303 var worldMin:Point = worldMatrix.transformPoint(new Point(0,0));304 var worldMax:Point = worldMatrix.transformPoint(new Point(tileWidth, tileHeight));305 306 314 // what zoom level of tiles should we be loading, taking into account min/max zoom? 307 315 // (0 when scale == 1, 1 when scale == 2, 2 when scale == 4, etc.) … … 310 318 // see if the newZoom is different to currentZoom 311 319 // so we know which way we're zooming, if any: 312 if (current Zoom != newZoom) {313 previous Zoom = currentZoom;320 if (currentTileZoom != newZoom) { 321 previousTileZoom = currentTileZoom; 314 322 } 315 323 316 324 // this is the level of tiles we'll be loading: 317 _currentZoom = newZoom; 318 319 // this is how big the world is, in tiles: 320 // (same as rounding scale to the nearest power of 2) 321 var numCols:int = Math.pow(2, currentZoom); 322 var numRows:int = numCols; // TODO deal with what happens with non-square projections! 323 324 // find start and end columns for the visible tiles: 325 _currentTileZoom = newZoom; 326 327 // find start and end columns for the visible tiles, at current tile zoom 325 328 // TODO: take account of potential rotation in worldMatrix (ask Tom about this if you need it) 326 var realMinCol:Number = numCols * (-worldMin.x) / (worldMax.x-worldMin.x); 327 var realMaxCol:Number = numCols * (mapWidth-worldMin.x) / (worldMax.x-worldMin.x); 328 var realMinRow:Number = numRows * (-worldMin.y) / (worldMax.y-worldMin.y); 329 var realMaxRow:Number = numRows * (mapHeight-worldMin.y) / (worldMax.y-worldMin.y); 330 331 // round these up or down to pad things out a bit 332 var minCol:int = Math.floor(realMinCol); 333 var maxCol:int = Math.ceil(realMaxCol); 334 var minRow:int = Math.floor(realMinRow); 335 var maxRow:int = Math.ceil(realMaxRow); 336 337 // optionally pad it out a little bit more 329 var tlC:Coordinate = topLeftCoordinate.zoomTo(currentTileZoom); 330 var brC:Coordinate = bottomRightCoordinate.zoomTo(currentTileZoom); 331 332 // optionally pad it out a little bit more with a tile buffer 338 333 // TODO: investigate giving a directional bias to TILE_BUFFER when panning quickly 339 minCol -=tileBuffer;340 maxCol +=tileBuffer;341 minRow -=tileBuffer;342 maxRow += tileBuffer;334 var minCol:int = Math.floor(tlC.column) - tileBuffer; 335 var maxCol:int = Math.ceil(brC.column) + tileBuffer; 336 var minRow:int = Math.floor(tlC.row) - tileBuffer; 337 var maxRow:int = Math.ceil(brC.row) + tileBuffer; 343 338 344 339 // loop over all tiles and find parent or child tiles from cache to compensate for unloaded tiles: 345 340 repopulateVisibleTiles(minCol, maxCol, minRow, maxRow); 346 341 347 // m ake absolutlely sure all our newly visible tiles are cached if they're done loading348 // TODO: should this happen onLoadEnd when there are no URLs left?342 // move visible tiles to the end of recentlySeen if we're done loading them 343 // the 'least recently seen' tiles will be removed from the tileCache below 349 344 for each (var visibleTile:Tile in visibleTiles) { 350 // if we're done loading this one, add/move it to the end of recently seen:351 345 if (!layersNeeded[visibleTile.name]) { 352 346 var ri:int = recentlySeen.indexOf(visibleTile.name); … … 355 349 } 356 350 recentlySeen.push(visibleTile.name); 357 } 351 } 358 352 } 359 353 … … 377 371 378 372 // position tiles such that currentZoom is approximately scale 1 379 // and x and y make sense in pixels relative to realMinCol and realMinRow, topleft380 positionTiles( realMinCol, realMinRow);373 // and x and y make sense in pixels relative to tlC.column and tlC.row (topleft) 374 positionTiles(tlC.column, tlC.row); 381 375 382 376 // all the visible tiles will be at the end of recentlySeen … … 395 389 } 396 390 397 // update center position: 398 centerRow = (realMaxRow+realMinRow)/2; 399 centerColumn = (realMaxCol+realMinCol)/2.0; 391 // update centerRow and centerCol for sorting the tileQueue in processQueue() 392 var center:Coordinate = centerCoordinate.zoomTo(currentTileZoom); 393 centerRow = center.row; 394 centerColumn = center.column; 400 395 401 396 dirty = false; … … 420 415 421 416 // create a string key for this tile 422 var key:String = tileKey(col, row, current Zoom);417 var key:String = tileKey(col, row, currentTileZoom); 423 418 424 419 // see if we already have this tile … … 429 424 tile = tileCache.getTile(key); 430 425 if (!tile) { 431 tile = tilePool.getTile(col, row, current Zoom);426 tile = tilePool.getTile(col, row, currentTileZoom); 432 427 tile.name = key; 433 428 coord.row = tile.row; … … 468 463 var foundChildren:int = 0; 469 464 470 if (current Zoom > previousZoom) {465 if (currentTileZoom > previousTileZoom) { 471 466 472 467 // if it still doesn't have enough images yet, or it's fading in, try a double size parent instead 473 if (maxParentSearch > 0 && current Zoom > minZoom) {474 if (ensureVisible(parentKey(col, row, current Zoom, currentZoom-1))) {468 if (maxParentSearch > 0 && currentTileZoom > minZoom) { 469 if (ensureVisible(parentKey(col, row, currentTileZoom, currentTileZoom-1))) { 475 470 foundParent = true; 476 471 } … … 484 479 485 480 // if it doesn't have an image yet, see if we can make it from smaller images 486 if (!foundParent && maxChildSearch > 0 && current Zoom < maxZoom) {487 for (var czoom:int = current Zoom+1; czoom <= Math.min(maxZoom, currentZoom+maxChildSearch); czoom++) {488 var ckeys:Array = childKeys(col, row, current Zoom, czoom);481 if (!foundParent && maxChildSearch > 0 && currentTileZoom < maxZoom) { 482 for (var czoom:int = currentTileZoom+1; czoom <= Math.min(maxZoom, currentTileZoom+maxChildSearch); czoom++) { 483 var ckeys:Array = childKeys(col, row, currentTileZoom, czoom); 489 484 for each (var ckey:String in ckeys) { 490 485 if (ensureVisible(ckey)) { … … 499 494 } 500 495 501 var startZoomSearch:int = current Zoom - 1;496 var startZoomSearch:int = currentTileZoom - 1; 502 497 503 if (current Zoom > previousZoom) {498 if (currentTileZoom > previousTileZoom) { 504 499 // we already looked for parent level 1, and didn't find it, so: 505 500 startZoomSearch -= 1; 506 501 } 507 502 508 var endZoomSearch:int = Math.max(minZoom, current Zoom-maxParentSearch);503 var endZoomSearch:int = Math.max(minZoom, currentTileZoom-maxParentSearch); 509 504 510 505 var stillNeedsAnImage:Boolean = !foundParent && foundChildren < 4; 511 506 // if it still doesn't have an image yet, try more parent zooms 512 if (stillNeedsAnImage && maxParentSearch > 1 && current Zoom > minZoom) {507 if (stillNeedsAnImage && maxParentSearch > 1 && currentTileZoom > minZoom) { 513 508 for (var pzoom:int = startZoomSearch; pzoom >= endZoomSearch; pzoom--) { 514 if (ensureVisible(parentKey(col, row, current Zoom, pzoom))) {509 if (ensureVisible(parentKey(col, row, currentTileZoom, pzoom))) { 515 510 stillNeedsAnImage = false; 516 511 break; … … 537 532 538 533 // for fixing positions when we're between zoom levels: 539 var positionScaleCompensation:Number = Math.pow(2, zoomLevel-currentZoom); 534 var positionScaleCompensation:Number = Math.pow(2, zoomLevel-currentTileZoom); 535 536 // for positioning tile according to current transform, based on current tile zoom 537 var scaleFactors:Array = new Array(maxZoom+1); 538 // scales to compensate for zoom differences between current grid zoom level 539 var tileScales:Array = new Array(maxZoom+1); 540 for (var z:int = 0; z <= maxZoom; z++) { 541 scaleFactors[z] = Math.pow(2.0, currentTileZoom-z) 542 tileScales[z] = Math.pow(2, zoomLevel-z); 543 } 540 544 541 545 // apply the sorted depths, position all the tiles and also keep recentlySeen updated: … … 545 549 well.setChildIndex(tile, well.numChildren-1); 546 550 547 // scale to compensate for zoom differences 548 var tileScale:Number = Math.pow(2, zoomLevel-tile.zoom); 549 tileScale = Math.ceil(tileScale * tileWidth) / tileWidth; // round up to the nearest pixel 550 tile.scaleX = tile.scaleY = tileScale; 551 552 // position tile according to current transform 553 var scaleFactor:Number = Math.pow(2.0, currentZoom-tile.zoom); 554 var positionCol:Number = (scaleFactor*tile.column) - realMinCol; 555 var positionRow:Number = (scaleFactor*tile.row) - realMinRow; 556 tile.x = Math.floor(positionCol*tileWidth*positionScaleCompensation); 557 tile.y = Math.floor(positionRow*tileHeight*positionScaleCompensation); 551 var positionCol:Number = (scaleFactors[tile.zoom]*tile.column) - realMinCol; 552 var positionRow:Number = (scaleFactors[tile.zoom]*tile.row) - realMinRow; 553 554 // round up to the nearest pixel to avoid seams between zoom levels 555 tile.scaleX = tile.scaleY = Math.ceil(tileScales[tile.zoom] * tileWidth) / tileWidth;; 556 557 if (!zooming) { 558 // this also helps the rare seams not fixed by rounding the tile scale, 559 // but makes slow zooming uglier: 560 tile.x = Math.floor(positionCol*tileWidth*positionScaleCompensation); 561 tile.y = Math.floor(positionRow*tileHeight*positionScaleCompensation); 562 } 563 else { 564 tile.x = positionCol*tileWidth*positionScaleCompensation; 565 tile.y = positionRow*tileHeight*positionScaleCompensation; 566 } 567 558 568 } 559 569 } … … 561 571 private function processQueue():void 562 572 { 563 // prepare the queue564 573 if (openRequests.length < maxOpenRequests && tileQueue.length > 0) { 565 574 … … 567 576 var removedTiles:Array = tileQueue.retainAll(visibleTiles); 568 577 578 // keep layersNeeded tidy: 569 579 for each (var removedTile:Tile in removedTiles) { 570 580 delete layersNeeded[removedTile.name]; … … 576 586 577 587 // sort queue by distance from 'center' 578 tileQueue.sortTiles(centerDistanceCompare); 579 }580 581 // process the queue582 while (openRequests.length < maxOpenRequests && tileQueue.length > 0) {583 var tile:Tile = tileQueue.shift();584 // if it's still on the stage:585 if (tile.parent) {586 loadNextURLForTile(tile);587 } 588 } 589 588 tileQueue.sortTiles(centerDistanceCompare); 589 590 // process the queue 591 while (openRequests.length < maxOpenRequests && tileQueue.length > 0) { 592 var tile:Tile = tileQueue.shift(); 593 // if it's still on the stage: 594 if (tile.parent) { 595 loadNextURLForTile(tile); 596 } 597 } 598 } 599 590 600 // you might want to wait for tiles to load before displaying other data, interface elements, etc. 591 601 // these events take care of that for you... … … 595 605 else if (previousOpenRequests > 0 && openRequests.length == 0) { 596 606 dispatchEvent(new MapEvent(MapEvent.ALL_TILES_LOADED)); 597 } 607 trace("requesting redraw to take parent and child tiles off the stage if we haven't already"); 608 dirty = true; 609 } 610 598 611 previousOpenRequests = openRequests.length; 599 600 612 } 601 613 … … 619 631 } 620 632 else if (urls && urls.length == 0) { 621 if (tile.zoom == current Zoom) {633 if (tile.zoom == currentTileZoom) { 622 634 tile.show(); 623 635 } … … 633 645 private function centerDistanceCompare(t1:Tile, t2:Tile):int 634 646 { 635 if (t1.zoom == t2.zoom && t1.zoom == current Zoom && t2.zoom == currentZoom) {647 if (t1.zoom == t2.zoom && t1.zoom == currentTileZoom && t2.zoom == currentTileZoom) { 636 648 var d1:int = Math.pow(t1.row+0.5-centerRow,2) + Math.pow(t1.column+0.5-centerColumn,2); 637 649 var d2:int = Math.pow(t2.row+0.5-centerRow,2) + Math.pow(t2.column+0.5-centerColumn,2); 638 650 return d1 < d2 ? -1 : d1 > d2 ? 1 : 0; 639 651 } 640 return Math.abs(t1.zoom-current Zoom) < Math.abs(t2.zoom-currentZoom) ? -1 : 1;652 return Math.abs(t1.zoom-currentTileZoom) < Math.abs(t2.zoom-currentTileZoom) ? -1 : 1; 641 653 } 642 654 … … 644 656 private function distanceFromCurrentZoomCompare(t1:Tile, t2:Tile):int 645 657 { 646 var d1:int = Math.abs(t1.zoom-current Zoom);647 var d2:int = Math.abs(t2.zoom-current Zoom);658 var d1:int = Math.abs(t1.zoom-currentTileZoom); 659 var d2:int = Math.abs(t2.zoom-currentTileZoom); 648 660 return d1 < d2 ? -1 : d1 > d2 ? 1 : 0; 649 661 } … … 726 738 delete layersNeeded[tile.name]; 727 739 tile.paintError(tileWidth, tileHeight); 728 if (tile.zoom == current Zoom) {740 if (tile.zoom == currentTileZoom) { 729 741 tile.show(); 730 742 } … … 803 815 804 816 /** read-only, this is the level of tiles we'll be loading first */ 805 public function get current Zoom():Number806 { 807 return _current Zoom;817 public function get currentTileZoom():Number 818 { 819 return _currentTileZoom; 808 820 } 809 821 … … 827 839 } 828 840 829 // for backward compatibility: 830 831 public function centerCoordinate():Coordinate 832 { 833 var c:Point = invertedMatrix.transformPoint(new Point(mapWidth/2, mapHeight/2)); 834 return new Coordinate(c.y, c.x, zoomLevel); 841 public function get centerCoordinate():Coordinate 842 { 843 if (!_centerCoordinate) { 844 var c:Point = invertedMatrix.transformPoint(new Point(mapWidth/2, mapHeight/2)); 845 _centerCoordinate = new Coordinate(c.y, c.x, zoomLevel); 846 } 847 return _centerCoordinate; 835 848 } 836 849 … … 917 930 } 918 931 919 public function resetTiles(coord:Coordinate , point:Point):void932 public function resetTiles(coord:Coordinate):void 920 933 { 921 934 var sc:Number = Math.pow(2, coord.zoom); … … 924 937 worldMatrix.scale(sc, sc); 925 938 worldMatrix.translate(mapWidth/2, mapHeight/2 ); 926 worldMatrix.translate(point.x, point.y);927 939 worldMatrix.translate(-tileWidth*coord.column, -tileHeight*coord.row); 928 940 … … 1122 1134 _invertedMatrix = null; 1123 1135 _topLeftCoordinate = null; 1124 _bottomRightCoordinate = null; 1136 _bottomRightCoordinate = null; 1137 _centerCoordinate = null; 1125 1138 } 1126 1139 … … 1137 1150 _topLeftCoordinate = null; 1138 1151 _bottomRightCoordinate = null; 1152 _centerCoordinate = null; 1139 1153 } 1140 1154 } … … 1286 1300 } 1287 1301 1302 /** the alreadySeen Dictionary here will contain up to grid.maxTilesToKeep Tiles */ 1288 1303 class TileCache 1289 1304 { … … 1346 1361 } 1347 1362 1363 /** 1364 * This post http://lab.polygonal.de/2008/06/18/using-object-pools/ 1365 * suggests that using Object pools, especially for complex classes like Sprite 1366 * is a lot faster than calling new Object(). The suggested implementation 1367 * uses a linked list, but to get started with it here I'm using an Array. 1368 * 1369 * If anyone wants to try it with a linked list and compare the times, 1370 * it seems like it could be worth it :) 1371 */ 1348 1372 class TilePool 1349 1373 { 1374 protected static const MIN_POOL_SIZE:int = 128; 1375 protected static const MAX_NEW_TILES:int = 256; 1376 1350 1377 protected var pool:Array = []; 1351 1378 protected var tileClass:Class; … … 1364 1391 public function getTile(column:int, row:int, zoom:int):Tile 1365 1392 { 1366 if (pool.length > 0) { 1367 trace("reusing a tile"); 1368 var tile:Tile = pool.shift() as Tile; 1369 tile.init(column, row, zoom); 1370 return tile; 1393 if (pool.length < MIN_POOL_SIZE) { 1394 while (pool.length < MAX_NEW_TILES) { 1395 pool.push(new tileClass(0,0,0)); 1396 } 1371 1397 } 1372 trace("creating a tile"); 1373 return new tileClass(column, row, zoom) as Tile; 1398 var tile:Tile = pool.shift() as Tile; 1399 tile.init(column, row, zoom); 1400 return tile; 1374 1401 } 1375 1402 branches/tom-tweenlite/lib/com/modestmaps/extras/ZoomSlider.as
r613 r622 10 10 import flash.filters.BitmapFilterType; 11 11 import flash.filters.DropShadowFilter; 12 import flash.geom.Point; 12 13 import flash.geom.Rectangle; 13 14 14 15 import gs.TweenLite; 15 16 17 /** This is an example of a slider that modifies the zoom level of the given map. 18 * 19 * It is provided mainly for ModestMapsSample.as and to test the arbitrary 20 * zoom level functionality, but feel free to use it if you like yellow bevels. */ 16 21 public class ZoomSlider extends Sprite 17 22 { … … 22 27 23 28 private var dragging:Boolean = false; 29 private var trackHeight:Number; 24 30 25 private varHEIGHT:Number = 100;31 private static const DEFAULT_HEIGHT:Number = 100; 26 32 27 public function ZoomSlider(map:Map )33 public function ZoomSlider(map:Map, trackHeight:Number=DEFAULT_HEIGHT) 28 34 { 29 35 this.map = map; 36 this.trackHeight = trackHeight; 30 37 31 38 map.addEventListener(MapEvent.EXTENT_CHANGED, update); … … 39 46 track = new Sprite(); 40 47 track.filters = [ new BevelFilter(4, 45, 0xffffff, 0.2, 0x000000, 0.2, 4, 4, 1, 1, BitmapFilterType.INNER, false) ]; 41 track.mouseEnabled = false; 48 track.addEventListener(MouseEvent.CLICK, onTrackClick); 49 track.buttonMode = track.useHandCursor = true; 42 50 track.graphics.lineStyle(5, 0xd9c588); 43 51 track.graphics.moveTo(0, 0); 44 track.graphics.lineTo(0, HEIGHT);52 track.graphics.lineTo(0, trackHeight); 45 53 track.x = 5; 46 54 addChild(track); … … 59 67 update(); 60 68 } 69 70 private function onTrackClick(event:MouseEvent):void 71 { 72 var p:Point = globalToLocal(new Point(event.stageX, event.stageY)); 73 thumb.y = p.y; 74 map.grid.zoomLevel = Math.round(map.grid.minZoom + (map.grid.maxZoom - map.grid.minZoom) * proportion); 75 } 61 76 62 77 private function onThumbMouse(event:Event):void 63 78 { 64 79 if (event.type == MouseEvent.MOUSE_MOVE) { 65 proportion = thumb.y / HEIGHT;80 proportion = thumb.y / trackHeight; 66 81 } 67 82 else if (event.type == MouseEvent.MOUSE_DOWN) { 68 thumb.startDrag(false, new Rectangle(thumb.x, 0, 0, HEIGHT));83 thumb.startDrag(false, new Rectangle(thumb.x, 0, 0, trackHeight)); 69 84 dragging = true; 70 85 stage.addEventListener(MouseEvent.MOUSE_UP, onThumbMouse); … … 95 110 public function get proportion():Number 96 111 { 97 return thumb.y / HEIGHT;112 return thumb.y / trackHeight; 98 113 } 99 114 … … 101 116 { 102 117 if (!dragging) { 103 thumb.y = prop * HEIGHT;118 thumb.y = prop * trackHeight; 104 119 } 105 120 else { branches/tom-tweenlite/lib/com/modestmaps/Map.as
r621 r622 33 33 34 34 import flash.display.DisplayObject; 35 import flash.display.Loader;36 35 import flash.display.Sprite; 37 36 import flash.events.Event; … … 180 179 { 181 180 onExtentChanging(); 182 var position:MapPosition = extentPosition(extent);183 181 // tell grid what the rock is cooking 184 grid.resetTiles( position.coord, position.point);182 grid.resetTiles(locationsCoordinate( [ extent.northWest, extent.southEast ] )); 185 183 onExtentChanged(); 186 184 requestCopyrightUpdate(); … … 206 204 onExtentChanging(); 207 205 zoom = Math.min(Math.max(zoom, grid.minZoom), grid.maxZoom); 208 var center:MapPosition = coordinatePosition(mapProvider.locationCoordinate(location).zoomTo(zoom));209 206 // tell grid what the rock is cooking 210 grid.resetTiles( center.coord, center.point);207 grid.resetTiles(mapProvider.locationCoordinate(location).zoomTo(zoom)); 211 208 onExtentChanged(); 212 209 requestCopyrightUpdate(); … … 231 228 else { // else hard reset 232 229 onExtentChanging(); 233 var center:MapPosition = coordinatePosition(grid.centerCoordinate().zoomTo(zoom));234 230 // tell grid what the rock is cooking 235 grid.resetTiles( center.coord, center.point);231 grid.resetTiles(grid.centerCoordinate.zoomTo(zoom)); 236 232 onExtentChanged(); 237 233 requestCopyrightUpdate(); … … 239 235 } 240 236 241 /** 242 * Based on a coordinate, determine appropriate starting tile and position, 243 * and return a two-element object with a coord and a point. 244 */ 245 public function coordinatePosition(centerCoord:Coordinate):MapPosition 246 { 247 // initial tile coordinate 248 var initTileCoord:Coordinate = new Coordinate( Math.floor(centerCoord.row), 249 Math.floor(centerCoord.column), 250 Math.floor(centerCoord.zoom) ); 251 252 // initial tile position, assuming centered tile well in grid 253 var initX:Number = (initTileCoord.column - centerCoord.column) * mapProvider.tileWidth; 254 var initY:Number = (initTileCoord.row - centerCoord.row) * mapProvider.tileHeight; 255 var initPoint:Point = new Point(Math.round(initX), Math.round(initY)); 256 257 return new MapPosition(initTileCoord, initPoint); 258 } 259 260 261 public function locationsPosition(locations:Array):MapPosition 237 public function locationsCoordinate(locations:Array):Coordinate 262 238 { 263 239 var TL:Coordinate = mapProvider.locationCoordinate(locations[0]); … … 306 282 var centerCoord:Coordinate = (new Coordinate(centerRow, centerColumn, centerZoom)).zoomTo(initZoom); 307 283 308 return c oordinatePosition(centerCoord);284 return centerCoord; 309 285 } 310 311 /*312 * Based on an array of locations, determine appropriate map bounds313 * in terms of tile grid, and return a two-element object with a coord314 * and a point from calculateMapCenter().315 */316 public function ex
