Changeset 629

Show
Ignore:
Timestamp:
07/22/08 12:49:17 (1 month ago)
Author:
tom
Message:

big check-in with new MAP_RENDERED event, new copyright helper, bug-fix in MS tile server choice, new (optional) load order behaviour, and more

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/tom-tweenlite/lib/com/modestmaps/core/MarkerClip.as

    r609 r629  
    4343        public var markerSortFunction:Function = sortMarkersByYPosition; 
    4444 
    45                 // setting this.dirty = true will request an Event.RENDER 
     45                // setting this.dirty = true will redraw an MapEvent.RENDERED 
    4646                protected var _dirty:Boolean; 
    4747 
     
    7070                this.x = map.getWidth() / 2; 
    7171                this.y = map.getHeight() / 2; 
    72                 //map.addEventListener(MarkerEvent.ENTER, onMapMarkerEnters); 
    73                 //map.addEventListener(MarkerEvent.LEAVE, onMapMarkerLeaves); 
     72 
    7473                map.addEventListener(MapEvent.START_ZOOMING, onMapStartZooming); 
    7574                map.addEventListener(MapEvent.STOP_ZOOMING, onMapStopZooming); 
     
    8079                map.addEventListener(MapEvent.RESIZED, onMapResized); 
    8180                map.addEventListener(MapEvent.EXTENT_CHANGED, onMapExtentChanged); 
     81                map.addEventListener(MapEvent.RENDERED, updateClips); 
    8282 
    8383                addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); 
     
    9696        protected function onAddedToStage(event:Event):void 
    9797        { 
     98                //addEventListener(Event.RENDER, updateClips); 
     99                 
     100                dirty = true; 
     101                updateClips(); 
     102                 
    98103                removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); 
    99                 addEventListener(Event.RENDER, updateClips); 
    100                 addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage); 
    101         } 
     104                addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);          
     105        } 
     106 
    102107        protected function onRemovedFromStage(event:Event):void 
    103108        { 
    104                 removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage); 
    105                 removeEventListener(Event.RENDER, updateClips); 
     109                //removeEventListener(Event.RENDER, updateClips); 
     110                 
     111                removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);               
    106112                addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); 
    107113        } 
     
    109115        public function attachMarker(marker:DisplayObject, location:Location):void 
    110116            { 
    111                 // TODO: optionally index markers and throw marker events? 
    112                 //map.grid.putMarker(marker.name, map.getMapProvider().locationCoordinate(location), location); 
    113                  
    114                 locations[marker] = new Location(location.lat, location.lon); 
     117                locations[marker] = location.clone(); 
    115118                coordinates[marker] = map.getMapProvider().locationCoordinate(location); 
    116119                markersByName[marker.name] = marker; 
    117120                markers.push(marker); 
    118121                 
    119                 var point:Point = map.locationPoint(location, this); 
    120             marker.x = snapToPixels ? Math.round(point.x) : point.x; 
    121             marker.y = snapToPixels ? Math.round(point.y) : point.y; 
    122                  
    123                 var w:Number = map.getWidth() * 2; 
    124                 var h:Number = map.getHeight() * 2; 
    125                 if (markerInBounds(marker, w, h)) 
    126                 { 
    127                 addChild(marker); 
    128                 sortMarkers(true); 
    129             } 
     122                // set dirty to true, so that the next call to updateClips will set the  
     123                // position and add the marker to the stage if it's visible  
     124                dirty = true; 
    130125            } 
    131126             
     
    283278                        x = starting.x; 
    284279                        y = starting.y; 
     280                        starting = null; 
    285281                    } 
    286282                    else { 
     
    289285                        y = map.getHeight() / 2; 
    290286                    } 
    291                     /* 
    292                      * HACK: Apparently, in Safari the MouseEvent.MOUSE_UP event doesn't fire at the same 
    293                      * point in the render process that it does in other browsers. What ends up happening 
    294                      * is that when the pan stops and the stage is invalidated, an Event.RENDER isn't 
    295                      * dispatched until the next frame. This results in a single frame of incorrectly placed 
    296                      * markers. 
    297                      * 
    298                      * In order to get around this, we set _dirty to true and call updateClips() directly. 
    299                      * This should mean that updateClips() doesn't get called any more than it should, even 
    300                      * though calling it twice on a single frame shouldn't be much of a problem. --Shawn 
    301                      */  
    302287                    dirty = true; 
    303                 updateClips(); 
     288                //updateClips(); 
    304289            } 
    305290             
  • branches/tom-tweenlite/lib/com/modestmaps/core/Tile.as

    r621 r629  
    66package com.modestmaps.core 
    77{ 
     8        import flash.display.Bitmap; 
     9        import flash.display.DisplayObject; 
    810        import flash.display.Loader; 
    911        import flash.display.Sprite; 
     
    4143            { 
    4244                while (numChildren > 0) { 
    43                         var loader:Loader = removeChildAt(0) as Loader
    44                         if (loader) { 
     45                        var child:DisplayObject = removeChildAt(0)
     46                        if (child is Loader) { 
    4547                                try { 
    46                                         loader.unload(); 
     48                                        Loader(child).unload(); 
    4749                                } 
    4850                                catch (error:Error) { 
  • branches/tom-tweenlite/lib/com/modestmaps/core/TileGrid.as

    r628 r629  
    44        import com.modestmaps.mapproviders.IMapProvider; 
    55         
     6        import flash.display.Bitmap; 
    67        import flash.display.DisplayObject; 
    78        import flash.display.Loader; 
     
    2324        public class TileGrid extends Sprite 
    2425        { 
    25         // TILE_WIDTH and TILE_HEIGHT are now tileWidth and tileHeight 
    26         // this was needed for the NASA DailyPlanetProvider which has 512x512px tiles 
    27                 // public static const TILE_WIDTH:Number = 256; 
    28                 // public static const TILE_HEIGHT:Number = 256;         
    29          
    30         // read-only, kept up to date by calculateBounds() 
    31         protected var _minZoom:Number; 
    32         protected var _maxZoom:Number; 
    33  
    34                 protected var minTx:Number, maxTx:Number, minTy:Number, maxTy:Number; 
    35  
    36                 // read-only, convenience for tileWidth/Height 
    37                 protected var _tileWidth:Number; 
    38                 protected var _tileHeight:Number; 
    39  
    40  
    41                 // pan and zoom etc are stored in here 
    42                 // NB: this matrix is never applied to a DisplayObject's transform 
    43                 //     because it would require scaling tile positions to compensate 
    44                 //     instead, we adapt its values such that the current zoom level 
    45                 //     is approximately scale 1, and positions make sense in screen pixels 
    46                 protected var worldMatrix:Matrix; 
    47                  
    48                 // this turns screen points into coordinates 
    49                 protected var _invertedMatrix:Matrix; // use lazy getter for this 
    50                  
    51                 // the corners and center of the screen, in map coordinates 
    52                 // (these also have lazy getters) 
    53                 protected var _topLeftCoordinate:Coordinate; 
    54                 protected var _bottomRightCoordinate:Coordinate; 
    55                 protected var _centerCoordinate:Coordinate; 
    56  
    57                 // where the tiles live: 
    58                 protected var well:Sprite; 
    59  
    60                 protected var provider:IMapProvider; 
    61  
    62                 protected var tileQueue:TileQueue; 
    63  
    64                 protected var tileCache:TileCache; 
    65  
    66                 protected var tilePool:TilePool; 
    67                  
    68                 // per-tile, the array of images we're going to load, which can be empty 
    69                 // TODO: document this in IMapProvider, so that provider implementers know 
    70                 // they are free to check the bounds of their overlays and don't have to serve 
    71                 // millions of 404s 
    72                 protected var layersNeeded:Object = {}; 
    73  
    74                 // keys we've recently seen 
    75                 protected var recentlySeen:Array = []; 
    76                  
    77                 // open requests 
    78                 protected var openRequests:Array = []; 
    79  
    80                 // keeping track for dispatching MapEvent.ALL_TILES_LOADED and MapEvent.BEGIN_TILE_LOADING 
    81                 protected var previousOpenRequests:int = 0; 
    82                  
    83                 // currently visible tiles 
    84                 protected var visibleTiles:Array = []; 
    85                                  
    86                 // number of tiles we're failing to show 
    87                 protected var blankCount:int = 0; 
    88  
    89                 // a textfield with lots of stats 
    90                 public var debugField:TextField; 
    91                  
    92                 // for stats: 
    93                 protected var lastFrameTime:Number; 
    94                 protected var fps:Number = 30; 
    95  
    96                 // what zoom level of tiles is 'correct'? 
    97                 protected var _currentTileZoom:int;  
    98                 // so we know if we're going in or out 
    99                 protected var previousTileZoom:int;              
    100                  
    101                 // for sorting the queue: 
    102                 protected var centerRow:Number; 
    103                 protected var centerColumn:Number; 
    104  
    105                 // for pan events 
    106                 protected var startPan:Point; 
    107                 public var panning:Boolean; 
    108                  
    109                 // for zoom events 
    110                 protected var startZoom:Number = -1; 
    111                 public var zooming:Boolean; 
    112  
     26                // OPTIONS 
     27                /////////////////////////////// 
     28                 
     29                // TODO: split these out into a TileGridOptions class and allow mass setting/getting? 
     30                 
    11331                protected static const DEFAULT_MAX_PARENT_SEARCH:int = 5; 
     32                protected static const DEFAULT_MAX_PARENT_LOAD:int = 0; 
    11433                protected static const DEFAULT_MAX_CHILD_SEARCH:int = 1; 
    115                 protected static const DEFAULT_MAX_TILES_TO_KEEP:int = 256; 
    116                 protected static const DEFAULT_TILE_BUFFER:int = 0
     34                protected static const DEFAULT_MAX_TILES_TO_KEEP:int = 256; // 256*256*4bytes = 0.25MB ... so 256 tiles is 64MB of memory, minimum! 
     35                protected static const DEFAULT_TILE_BUFFER:int = 1
    11736                protected static const DEFAULT_ENFORCE_BOUNDS:Boolean = true; 
    11837                protected static const DEFAULT_MAX_OPEN_REQUESTS:int = 4; // TODO: should this be split into max-new-requests-per-frame, too? 
    11938                protected static const DEFAULT_ROUND_POSITIONS:Boolean = true; 
    12039                protected static const DEFAULT_ROUND_SCALES:Boolean = true; 
     40                protected static const DEFAULT_CACHE_LOADERS:Boolean = false; // !!! TODO: change to false :) 
     41                protected static const DEFAULT_MAX_LOADER_CACHE_SIZE:int = 0; // !!! TODO: change to 0 :) 
    12142 
    12243                /** if we don't have a tile at currentZoom, onRender will look for tiles up to 5 levels out. 
     
    12950                 *  - it works, but you probably don't want to change this number :) */ 
    13051                public var maxChildSearch:int = DEFAULT_MAX_CHILD_SEARCH; 
    131                  
    132                 public var maxTilesToKeep:int = DEFAULT_MAX_TILES_TO_KEEP; // 256*256*4bytes = 0.25MB ... so 256 tiles is 64MB of memory, minimum! 
     52 
     53                /** if maxParentSearch is enabled, setting maxParentLoad to between 1 and maxParentSearch will make requests for lower zoom levels first */ 
     54                public var maxParentLoad:int = DEFAULT_MAX_PARENT_LOAD; 
     55 
     56                /** this is the maximum size of tileCache (visible tiles will also be kept in the cache) */              
     57                public var maxTilesToKeep:int = DEFAULT_MAX_TILES_TO_KEEP; 
    13358                 
    13459                // 0 or 1, really: 2 will load *lots* of extra tiles 
     
    14772                public var roundScalesEnabled:Boolean = DEFAULT_ROUND_SCALES; 
    14873                 
    149                 public var mapWidth:Number; 
    150                 public var mapHeight:Number; 
     74                /** with tile providers that you have crossdomain.xml support for,  
     75                 *  it's possible to avoid extra requests by reusing bitmapdata. enable cacheLoaders to try and do that */ 
     76                public static var cacheLoaders:Boolean = DEFAULT_CACHE_LOADERS; 
     77                public static var maxLoaderCacheSize:int = DEFAULT_MAX_LOADER_CACHE_SIZE; 
     78                protected static var loaderCache:Object = {}; 
     79                protected static var cachedUrls:Array = []; 
     80                 
     81                /////////////////////////////// 
     82                // END OPTIONS 
     83 
     84        // TILE_WIDTH and TILE_HEIGHT are now tileWidth and tileHeight 
     85        // this was needed for the NASA DailyPlanetProvider which has 512x512px tiles 
     86                // public static const TILE_WIDTH:Number = 256; 
     87                // public static const TILE_HEIGHT:Number = 256;         
     88         
     89        // read-only, kept up to date by calculateBounds() 
     90        protected var _minZoom:Number; 
     91        protected var _maxZoom:Number; 
     92 
     93                protected var minTx:Number, maxTx:Number, minTy:Number, maxTy:Number; 
     94 
     95                // read-only, convenience for tileWidth/Height 
     96                protected var _tileWidth:Number; 
     97                protected var _tileHeight:Number; 
     98 
     99                // pan and zoom etc are stored in here 
     100                // NB: this matrix is never applied to a DisplayObject's transform 
     101                //     because it would require scaling tile positions to compensate. 
     102                //     Instead, we adapt its values such that the current zoom level 
     103                //     is approximately scale 1, and positions make sense in screen pixels 
     104                protected var worldMatrix:Matrix; 
     105                 
     106                // this turns screen points into coordinates 
     107                protected var _invertedMatrix:Matrix; // use lazy getter for this 
     108                 
     109                // the corners and center of the screen, in map coordinates 
     110                // (these also have lazy getters) 
     111                protected var _topLeftCoordinate:Coordinate; 
     112                protected var _bottomRightCoordinate:Coordinate; 
     113                protected var _centerCoordinate:Coordinate; 
     114 
     115                // where the tiles live: 
     116                protected var well:Sprite; 
     117 
     118                protected var provider:IMapProvider; 
     119 
     120                protected var tileQueue:TileQueue; 
     121 
     122                protected var tileCache:TileCache; 
     123 
     124                protected var tilePool:TilePool; 
     125                 
     126                // per-tile, the array of images we're going to load, which can be empty 
     127                // TODO: document this in IMapProvider, so that provider implementers know 
     128                // they are free to check the bounds of their overlays and don't have to serve 
     129                // millions of 404s 
     130                protected var layersNeeded:Object = {}; 
     131 
     132                // keys we've recently seen 
     133                protected var recentlySeen:Array = []; 
     134                 
     135                // open requests 
     136                protected var openRequests:Array = []; 
     137 
     138                // keeping track for dispatching MapEvent.ALL_TILES_LOADED and MapEvent.BEGIN_TILE_LOADING 
     139                protected var previousOpenRequests:int = 0; 
     140                 
     141                // currently visible tiles 
     142                protected var visibleTiles:Array = []; 
     143                                 
     144                // number of tiles we're failing to show 
     145                protected var blankCount:int = 0; 
     146 
     147                // a textfield with lots of stats 
     148                public var debugField:TextField; 
     149                 
     150                // for stats: 
     151                protected var lastFrameTime:Number; 
     152                protected var fps:Number = 30; 
     153 
     154                // what zoom level of tiles is 'correct'? 
     155                protected var _currentTileZoom:int;  
     156                // so we know if we're going in or out 
     157                protected var previousTileZoom:int;              
     158                 
     159                // for sorting the queue: 
     160                protected var centerRow:Number; 
     161                protected var centerColumn:Number; 
     162 
     163                // for pan events 
     164                protected var startPan:Point; 
     165                public var panning:Boolean; 
     166                 
     167                // previous mouse position when dragging  
     168                protected var pmouse:Point; 
     169                 
     170                // for zoom events 
     171                protected var startZoom:Number = -1; 
     172                public var zooming:Boolean; 
     173                 
     174                protected var mapWidth:Number; 
     175                protected var mapHeight:Number; 
    151176                 
    152177                protected var draggable:Boolean; 
     
    154179                // setting this.dirty = true will request an Event.RENDER 
    155180                protected var _dirty:Boolean; 
    156  
    157                 // previous mouse position when dragging  
    158                 protected var pmouse:Point; 
    159181                 
    160182                public function TileGrid(w:Number, h:Number, draggable:Boolean, provider:IMapProvider) 
     
    289311                { 
    290312                        if (!dirty || !stage) { 
     313                                dispatchEvent(new MapEvent(MapEvent.RENDERED)); 
    291314                                return; 
    292315                        } 
     
    391414                        if (recentlySeen.length > maxRecentlySeen) { 
    392415 
     416                                // can we sort so that biggest zoom levels get removed first, without removing currently visible tiles? 
     417/*                              var visibleKeys:Array = recentlySeen.slice(recentlySeen.length - visibleTiles.length, recentlySeen.length); 
     418 
     419                                // take a look at everything else 
     420                                recentlySeen = recentlySeen.slice(0, recentlySeen.length - visibleTiles.length); 
     421                                recentlySeen = recentlySeen.sort(Array.DESCENDING); 
     422                                recentlySeen = recentlySeen.concat(visibleKeys); */ 
     423                                 
    393424                                // throw away keys at the beginning of recentlySeen 
    394425                                recentlySeen = recentlySeen.slice(recentlySeen.length - maxRecentlySeen, recentlySeen.length); 
     
    404435                        centerColumn = center.column; 
    405436 
     437                        // listen out for this if you want to be sure map is in its final state before reprojecting markers etc. 
     438                        dispatchEvent(new MapEvent(MapEvent.RENDERED)); 
     439 
    406440                        dirty = false; 
    407441                } 
     
    419453                        // for use in loops etc. 
    420454                        var coord:Coordinate = new Coordinate(0,0,0); 
    421  
     455                 
    422456                        // loop over currently visible tiles 
    423457                        for (var col:int = minCol; col <= maxCol; col++) { 
     
    427461                                        var key:String = tileKey(col, row, currentTileZoom); 
    428462                                         
     463/*                                      // see if we already have this tile in the well 
     464                                        var tile:Tile = well.getChildByName(key) as Tile;  
     465                                         
     466                                        // if not, see if we already have this tile in the cache 
     467                                        if (!tile) { 
     468                                                tile = ensureVisible(key); 
     469                                        } 
     470                                         
     471                                        // finally load it if we really don't have it 
     472                                        if (!tile) { 
     473                                                tile = requestLoad(col, row, currentTileZoom); 
     474                                                visibleTiles.push(tile); 
     475                                        } */ 
     476 
    429477                                        // see if we already have this tile 
    430478                                        var tile:Tile = well.getChildByName(key) as Tile; 
     
    436484                                                        tile = tilePool.getTile(col, row, currentTileZoom); 
    437485                                                        tile.name = key; 
    438                                                       coord.row = tile.row; 
     486                                                      coord.row = tile.row; 
    439487                                                        coord.column = tile.column; 
    440                                                         coord.zoom = tile.zoom; 
     488                                                        coord.zoom = tile.zoom;  
    441489                                                        var urls:Array = provider.getTileUrls(coord); 
    442490                                                        if (urls && urls.length > 0) { 
     
    456504                                         
    457505                                        visibleTiles.push(tile); 
    458  
     506                                         
    459507                                        var tileReady:Boolean = tile.isShowing() && (layersNeeded[tile.name] == null); 
    460508                                         
     
    504552                                                } 
    505553         
    506                                                 var startZoomSearch:int = currentTileZoom - 1; 
    507                                                  
    508                                                 if (currentTileZoom > previousTileZoom) { 
    509                                                         // we already looked for parent level 1, and didn't find it, so: 
    510                                                         startZoomSearch -= 1; 
    511                                                 } 
    512                                                  
    513                                                 var endZoomSearch:int = Math.max(minZoom, currentTileZoom-maxParentSearch); 
    514          
    515554                                                var stillNeedsAnImage:Boolean = !foundParent && foundChildren < 4;                                       
     555         
    516556                                                // if it still doesn't have an image yet, try more parent zooms 
    517557                                                if (stillNeedsAnImage && maxParentSearch > 1 && currentTileZoom > minZoom) { 
     558 
     559                                                        var startZoomSearch:int = currentTileZoom - 1; 
     560                                                         
     561                                                        if (currentTileZoom > previousTileZoom) { 
     562                                                                // we already looked for parent level 1, and didn't find it, so: 
     563                                                                startZoomSearch -= 1; 
     564                                                        } 
     565                                                         
     566                                                        var endZoomSearch:int = Math.max(minZoom, currentTileZoom-maxParentSearch); 
     567                                                         
    518568                                                        for (var pzoom:int = startZoomSearch; pzoom >= endZoomSearch; pzoom--) { 
    519569                                                                if (ensureVisible(parentKey(col, row, currentTileZoom, pzoom))) {                                                                
    520570                                                                        stillNeedsAnImage = false; 
    521571                                                                        break; 
     572                                                                } 
     573                                                                else if (currentTileZoom - pzoom < maxParentLoad) { 
     574                                                                        trace("requesting parent tile at zoom", pzoom); 
     575                                                                        var pcoord:Array = parentCoord(col, row, currentTileZoom, pzoom); 
     576                                                                        visibleTiles.push(requestLoad(pcoord[0], pcoord[1], pzoom)); 
    522577                                                                } 
    523578                                                        } 
     
    532587                                } // for row 
    533588                        } // for col 
     589                         
     590                        trace("zoomLevel", zoomLevel, "currentTileZoom", currentTileZoom, "blankCount", blankCount); 
    534591                         
    535592                } // repopulateVisibleTiles 
     
    560617                        } 
    561618                         
     619                        //trace(); 
     620                        //trace("tile.zoom, tile.alpha, tile.numChildren ? tile.getChildAt(0).alpha : '', tile.isShowing() && (layersNeeded[tile.name] == null), tileCache.containsKey(tile.name)"); 
     621                         
    562622                        // apply the sorted depths, position all the tiles and also keep recentlySeen updated: 
    563623                        for each (var tile:Tile in visibleTiles) { 
     
    583643                                } 
    584644                                 
    585                         }                        
     645                                //trace(tile.zoom, tile.alpha, tile.numChildren ? tile.getChildAt(0).alpha : '', tile.isShowing() && (layersNeeded[tile.name] == null), tileCache.containsKey(tile.name)); 
     646                                 
     647                        } 
     648                                                 
     649                        //trace(); 
    586650                } 
    587651                 
     
    602666                                // reuse visible tiles for the queue we'll be loading the same things over and over 
    603667         
    604                                 // sort queue by distance from 'center' 
    605                                 tileQueue.sortTiles(centerDistanceCompare); 
     668                                if (maxParentLoad == 0) { 
     669                                        // sort queue by distance from 'center' 
     670                                        tileQueue.sortTiles(centerDistanceCompare); 
     671                                } 
     672                                else { 
     673                                        tileQueue.sortTiles(zoomThenCenterCompare);                                      
     674                                } 
    606675                                                                 
    607676                                // process the queue 
     
    635704                        if (urls && urls.length > 0) { 
    636705                                var url:* = urls.shift(); 
    637                                 var tileLoader:Loader = new Loader();  
    638                                 tileLoader.name = tile.name; 
    639                                 try { 
    640                                         tileLoader.load((url is URLRequest) ? url : new URLRequest(url)); 
    641                                         tileLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadEnd, false, 0, true); 
    642                                         tileLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError, false, 0, true); 
    643                                         openRequests.push(tileLoader); 
    644                                 } 
    645                                 catch(error:Error) { 
    646                                         tile.paintError(); 
     706                                if (cacheLoaders && (url is String) && loaderCache[url]) { 
     707                                        var original:Bitmap = loaderCache[url] as Bitmap; 
     708                                        var bitmap:Bitmap = new Bitmap(original.bitmapData);  
     709                                        tile.addChild(bitmap); 
     710                                        loadNextURLForTile(tile); 
     711                                } 
     712                                else { 
     713                                        var tileLoader:Loader = new Loader();  
     714                                        tileLoader.name = tile.name; 
     715                                        try { 
     716                                                tileLoader.load((url is URLRequest) ? url : new URLRequest(url)); 
     717                                                tileLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadEnd, false, 0, true); 
     718                                                tileLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError, false, 0, true); 
     719                                                openRequests.push(tileLoader); 
     720                                        } 
     721                                        catch(error:Error) { 
     722                                                tile.paintError(); 
     723                                        } 
    647724                                } 
    648725                        } 
     
    657734                                delete layersNeeded[tile.name]; 
    658735                        }                        
     736                } 
     737 
     738                private function zoomThenCenterCompare(t1:Tile, t2:Tile):int 
     739                { 
     740                        if (t1.zoom == t2.zoom) { 
     741                                return centerDistanceCompare(t1, t2); 
     742                        } 
     743                        return t1.zoom < t2.zoom ? -1 : t1.zoom > t2.zoom ? 1 : 0;  
    659744                } 
    660745 
     
    678763                } 
    679764 
    680                 // makes sure the tile with the given key is in the well and added to visibleTiles 
    681                 // returns false if alreadySeen[key] does not exist  
    682                 private function ensureVisible(key:String):Boolean 
     765                // makes sure that if a tile with the given key exists in the cache that it is added to the well and added to visibleTiles 
     766                // returns null if tile does not exist in cache 
     767                private function ensureVisible(key:String):Tile 
    683768                { 
    684769                        if (tileCache.containsKey(key)) { 
     
    692777                                } 
    693778                                tile.showNow(); 
    694                                 return true; 
    695                         } 
    696                         return false; 
    697                 } 
    698  
     779                                return tile; 
     780                        } 
     781                        return null; 
     782                }                 
     783/*              private function ensureVisible(key:String):Tile 
     784                { 
     785                        var tile:Tile = null; 
     786                        if (tileCache.containsKey(key)) { 
     787                                tile = well.getChildByName(key) as Tile; 
     788                                if (!tile) { 
     789                                        tile = tileCache.getTile(key); 
     790                                        well.addChildAt(tile,0); 
     791                                } 
     792                                if (tile.zoom == currentTileZoom) { 
     793                                        tile.show(); 
     794                                } 
     795                                else { 
     796                                        tile.showNow(); 
     797                                } 
     798                        } 
     799                        if (tile) { 
     800                                if (visibleTiles.indexOf(tile) < 0) { 
     801                                        visibleTiles.push(tile); // don't get rid of it yet! 
     802                                } 
     803                                else { 
     804                                        // we've already got this tile this frame 
     805                                        // (this happens quite a bit with parent tiles,  
     806                                        //  since they cover more than one tile at the current zoom level) 
     807                                } 
     808                        } 
     809                        return tile; 
     810                } */ 
     811                 
     812                // for use in requestLoad 
     813                private var tempCoord:Coordinate = new Coordinate(0,0,0); 
     814 
     815                /** create a tile and add it to the queue - WARNING: this is buggy for the current zoom level, it's only used for parent zooms when maxParentLoad is > 0 */  
     816                private function requestLoad(col:int, row:int, zoom:int):Tile 
     817                { 
     818                        var key:String = tileKey(col, row, zoom); 
     819                        if (tileCache.containsKey(key)) throw new Error("requested load for an already cached tile");                    
     820                        var tile:Tile = well.getChildByName(key) as Tile;  
     821                        if (!tile) { 
     822                                tile = tilePool.getTile(col, row, zoom); 
     823                                tile.name = key; 
     824                                tempCoord.row = row; 
     825                                tempCoord.column = col; 
     826                                tempCoord.zoom = zoom; 
     827                                var urls:Array = provider.getTileUrls(tempCoord); 
     828                                if (urls && urls.length > 0) { 
     829                                        // keep a local copy of the URLs so we don't have to call this twice: 
     830                                        layersNeeded[tile.name] = urls; 
     831                                        tileQueue.push(tile); 
     832                                } 
     833                                else { 
     834                                        trace("no urls needed for that tile", tempCoord); 
     835                                        tile.show(); 
     836                                } 
     837                                well.addChild(tile); 
     838                        } 
     839                        return tile; 
     840                } 
     841 
     842                private static const zoomLetter:Array = "abcdefghijklmnopqrstuvwxyz".split(''); 
     843                                                 
     844                /** zoom is translated into a letter so that keys can easily be sorted (alphanumerically) by zoom level */ 
    699845                private function tileKey(col:int, row:int, zoom:int):String 
    700                 {  
    701                         return col+":"+row+":"+zoom
     846                { 
     847                        return zoomLetter[zoom]+":"+col+":"+row
    702848                } 
    703849                 
     
    710856                        return tileKey(pcol,prow,parentZoom);                    
    711857                } 
     858 
     859                // used when maxParentLoad is > 0 
     860                // TODO: check that this does the right thing with negative row/col? 
     861                private function parentCoord(col:int, row:int, zoom:int, parentZoom:int):Array 
     862                { 
     863                        var scaleFactor:Number = Math.pow(2.0, zoom-parentZoom); 
     864                        var pcol:int = Math.floor(Number(col) / scaleFactor);  
     865                        var prow:int = Math.floor(Number(row) / scaleFactor); 
     866                        return [ pcol, prow ];                   
     867                }                
    712868                 
    713869                // TODO: check that this does the right thing with negative row/col