Changeset 671

Show
Ignore:
Timestamp:
09/07/08 16:11:40 (3 months ago)
Author:
tom
Message:

stopped overloading EXTENT_CHANGED for simultaneous pan/zoom
- you should listen for both ZOOMED and PANNED instead, see MarkerClip? for an example
tidied up MarkerClip? and PolygonClip? to better respond to events
made reprojection in PolygonMarker? more efficient (caching Coordinates gives big speed boost)
added MapExtent?.fromLocation to initialize an extent on a sinlge point
added Redrawable interface so that PolygonClip? can handle DisplayObjects? other than PolygonMarker?

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/as3/lib/com/modestmaps/core/MapExtent.as

    r670 r671  
    165165                        return extent; 
    166166                } 
     167 
     168                public static function fromLocation(location:Location):MapExtent 
     169                { 
     170                        return new MapExtent(location.lat, location.lat, location.lon, location.lon); 
     171                } 
     172                 
    167173                 
    168174                public static function fromLocationProperties(objects:Array, locationProp:String='location'):MapExtent 
  • trunk/as3/lib/com/modestmaps/core/MarkerClip.as

    r670 r671  
    1818        import flash.geom.Point; 
    1919        import flash.utils.Dictionary; 
     20        import flash.utils.clearTimeout; 
     21        import flash.utils.getTimer; 
     22        import flash.utils.setTimeout; 
    2023         
    2124    [Event(name="markerRollOver",    type="com.modestmaps.events.MarkerEvent")] 
     
    2427        public class MarkerClip extends Sprite 
    2528        { 
    26                 // TODO: mask me? 
    2729            protected var map:Map; 
    28             protected var starting:Point; 
     30             
     31            protected var drawCoord:Coordinate; 
     32             
    2933            protected var locations:Dictionary = new Dictionary(); 
    3034            protected var coordinates:Dictionary = new Dictionary(); 
     
    3438        // enable this if you want intermediate zooming steps to 
    3539        // stretch your graphics instead of reprojecting the points 
     40        // it's useful for polygons, but for points  
    3641        // it looks worse and probably isn't faster, but there it is :) 
    3742        public var scaleZoom:Boolean = false; 
     
    7580                this.x = map.getWidth() / 2; 
    7681                this.y = map.getHeight() / 2; 
    77                          
     82                 
     83                drawCoord = map.grid.centerCoordinate.copy(); 
     84                 
    7885                previousGeometry = map.getMapProvider().geometry(); 
    7986 
    80                 map.addEventListener(MapEvent.START_ZOOMING, onMapStartZooming); 
     87                       map.addEventListener(MapEvent.START_ZOOMING, onMapStartZooming); 
    8188                map.addEventListener(MapEvent.STOP_ZOOMING, onMapStopZooming); 
    8289                map.addEventListener(MapEvent.ZOOMED_BY, onMapZoomedBy); 
     
    195202            } 
    196203                 
     204            private var sortTimer:uint; 
     205                 
    197206            public function updateClips(event:Event=null):void 
    198207            { 
     
    201210                } 
    202211                 
     212                var center:Coordinate = map.grid.centerCoordinate; 
     213                 
     214                if (center.equalTo(drawCoord)) { 
     215                        dirty = false; 
     216                        return; 
     217                } 
     218                 
     219                drawCoord = center.copy(); 
     220                 
     221                this.x = map.getWidth() / 2; 
     222                this.y = map.getHeight() / 2;            
     223                 
     224                if (scaleZoom) { 
     225                    scaleX = scaleY = 1.0; 
     226                }                
     227                 
    203228                var marker:DisplayObject; 
    204229 
    205                 //var t:int = flash.utils.getTimer(); 
    206230                var doSort:Boolean = false; 
    207231                for each (marker in markers) 
     
    210234                } 
    211235 
    212             if (doSort) sortMarkers(true); 
     236            if (doSort) { 
     237                // use a timer so we don't do this every single frame 
     238                // sorting markers and applying depths pretty much doubles the time to update  
     239                if (sortTimer) { 
     240                        clearTimeout(sortTimer); 
     241                } 
     242                sortTimer = setTimeout(sortMarkers, 100, true);  
     243            } 
    213244             
    214245                dirty = false; 
    215                 //trace("reprojected all markers in " + (flash.utils.getTimer() - t) + "ms"); 
    216246            } 
    217247             
     
    225255                                coordinates[marker] = provider.locationCoordinate(locations[marker]); 
    226256                } 
     257                dirty = true; 
    227258            } 
    228259             
     
    278309            return false;             
    279310            } 
    280  
    281             protected function onMapStartPanning(event:MapEvent):void 
    282             { 
    283                 starting = new Point(x, y); 
     311             
     312            ///// Events.... 
     313 
     314            protected function onMapExtentChanged(event:MapEvent):void 
     315            { 
     316                onMapZoomedBy(event); 
     317                onMapPanned(event); 
    284318            } 
    285319             
    286320            protected function onMapPanned(event:MapEvent):void 
    287321            { 
    288                 if (map.grid.panning && map.grid.zooming) { 
    289                         // only reprojecting can save you now 
    290                         dirty = true; 
    291                         return; 
    292                 } 
    293                 else if (starting) { 
    294                     x = starting.x + event.panDelta.x; 
    295                     y = starting.y + event.panDelta.y; 
    296                 } 
    297                 else { 
    298                         // TODO: this shouldn't really ever happen, and the following might not work: 
    299                     x = event.panDelta.x; 
    300                     y = event.panDelta.y;                    
    301                 } 
    302             } 
    303              
    304             protected function onMapStopPanning(event:MapEvent):void 
    305             { 
    306                 if (starting) { 
    307                         x = starting.x; 
    308                         y = starting.y; 
    309                         starting = null; 
    310                     } 
    311                     else { 
    312                         // make sure we're centered 
    313                         x = map.getWidth() / 2; 
    314                         y = map.getHeight() / 2; 
    315                     } 
    316                     dirty = true; 
    317                 //updateClips(); 
    318             } 
    319              
    320             protected function onMapResized(event:MapEvent):void 
    321             { 
    322                 x = event.newSize[0] / 2; 
    323                 y = event.newSize[1] / 2; 
    324                 dirty = true; 
    325                 updateClips(); // force redraw because flash seems stingy about it 
    326             } 
    327              
    328             protected function onMapStartZooming(event:MapEvent):void 
    329             { 
    330                 dirty = true; 
    331             } 
    332  
    333             protected function onMapExtentChanged(event:MapEvent):void 
    334             { 
    335                         dirty = true; 
    336             } 
    337              
    338             protected function onMapStopZooming(event:MapEvent):void 
    339             { 
     322                var p:Point = map.grid.coordinatePoint(drawCoord); 
     323                this.x = p.x; 
     324                this.y = p.y; 
     325            } 
     326             
     327            protected function onMapZoomedBy(event:MapEvent):void 
     328            { 
     329                cacheAsBitmap = false; 
    340330                if (scaleZoom) { 
    341                     //trace("scaling zoom back to 1"); 
    342                     scaleX = scaleY = 1.0; 
    343                 } 
    344                 dirty = true; 
    345             } 
    346              
    347             protected function onMapZoomedBy(event:MapEvent):void 
    348             { 
    349                 if (scaleZoom) { 
    350                         //trace("scaling zoom"); 
    351                 scaleX = scaleY = Math.pow(2, event.zoomDelta); 
     331                scaleX = scaleY = Math.pow(2, map.grid.zoomLevel - drawCoord.zoom); 
    352332                } 
    353333                else {  
     
    355335                } 
    356336            } 
     337 
     338            protected function onMapStartPanning(event:MapEvent):void 
     339            { 
     340                // optimistically, we set this to true in case we're just moving 
     341                    cacheAsBitmap = true; 
     342            } 
     343             
     344            protected function onMapStartZooming(event:MapEvent):void 
     345            { 
     346                // overrule onMapStartPanning if there's scaling involved 
     347                cacheAsBitmap = false; 
     348            } 
     349             
     350            protected function onMapStopPanning(event:MapEvent):void 
     351            { 
     352                // tidy up 
     353                cacheAsBitmap = false; 
     354                    dirty = true; 
     355            } 
     356             
     357            protected function onMapStopZooming(event:MapEvent):void 
     358            { 
     359                dirty = true; 
     360            } 
     361             
     362            protected function onMapResized(event:MapEvent):void 
     363            { 
     364                x = map.getWidth() / 2; 
     365                y = map.getHeight() / 2; 
     366                dirty = true; 
     367                updateClips(); // force redraw because flash seems stingy about it 
     368            } 
     369             
    357370             
    358371            protected function onMapProviderChanged(event:MapEvent):void 
    359372            { 
    360                 var mapProvider:IMapProvider = event.newProvider;      
     373                var mapProvider:IMapProvider = map.getMapProvider();   
    361374                if (mapProvider.geometry() != previousGeometry) 
    362375                        { 
     
    365378                } 
    366379            } 
     380             
     381            ///// Invalidations... 
    367382             
    368383                protected function set dirty(d:Boolean):void 
     
    379394                } 
    380395 
     396                ////// Marker Events... 
     397 
    381398                /** 
    382399            * Dispatches MarkerEvent.CLICK when a marker is clicked. 
  • trunk/as3/lib/com/modestmaps/core/PolygonClip.as

    r670 r671  
    66        import flash.geom.Rectangle; 
    77 
     8        /**  
     9         *  PolygonClip extends MarkerClip to take the bounds of the marker into account when showing/hiding, 
     10         *  and to trigger a redraw of content that needs scaling. 
     11         *   
     12         *  To trigger the redraw, markers must implement the Redrawable interface provided in this package. 
     13         *   
     14         *  See PolygonMarker for an example, but if you need multi-geometries, complex styling, holes etc.,  
     15         *  you'll need to write your own for the moment. 
     16         *   
     17         */ 
    818        public class PolygonClip extends MarkerClip 
    919        { 
     
    1121                { 
    1222                        super(map); 
    13                         //this.scaleZoom = true; 
     23                        this.scaleZoom = true; 
    1424                        this.markerSortFunction = null 
    1525                } 
     
    1727                override protected function markerInBounds(marker:DisplayObject, w:Number, h:Number):Boolean 
    1828                { 
    19                       var rect:Rectangle = new Rectangle(-w, -h, w*2, h*2); 
     29                      var rect:Rectangle = new Rectangle(-w, -h, w*2, h*2); 
    2030                        return rect.intersects(marker.getBounds(this)); 
    21                 }                
     31                } 
     32                 
     33                override public function updateClip(marker:DisplayObject):Boolean 
     34                { 
     35                        var needsSort:Boolean = super.updateClip(marker); 
     36                        if (contains(marker) && marker is Redrawable) { 
     37                                Redrawable(marker).redraw(); 
     38                        } 
     39                        return needsSort; 
     40                } 
    2241                 
    2342        } 
  • trunk/as3/lib/com/modestmaps/core/PolygonMarker.as

    r670 r671  
    22{ 
    33        import com.modestmaps.Map; 
    4         import com.modestmaps.events.MapEvent; 
    54        import com.modestmaps.geo.Location; 
    65         
     6        import flash.display.LineScaleMode; 
    77        import flash.display.Sprite; 
    88        import flash.events.Event; 
    99        import flash.geom.Point; 
    1010 
    11         public class PolygonMarker extends Sprite 
     11        public class PolygonMarker extends Sprite implements Redrawable 
    1212        { 
    1313                protected var map:Map; 
    1414                protected var drawZoom:Number; 
    1515                 
     16                public var zoomTolerance:Number = 4; 
     17                 
    1618                public var locations:Array; 
     19                protected var coordinates:Array; 
    1720                public var extent:MapExtent; 
    1821                public var location:Location; 
     
    3235                        this.mouseEnabled = false; 
    3336 
    34                         map.addEventListener(MapEvent.EXTENT_CHANGED, rescale); 
    35                         map.addEventListener(MapEvent.ZOOMED_BY, rescale); 
    36                         map.addEventListener(MapEvent.STOP_ZOOMING, redraw); 
    37                          
    3837                        if (locations && locations.length > 0) { 
    3938                                this.locations = locations; 
    4039                                this.extent = MapExtent.fromLocations(locations); 
    4140                                this.location = locations[0] as Location; 
     41                                this.coordinates = locations.map(l2c); 
    4242                        } 
    4343                } 
     44                 
     45                protected function l2c(l:Location, ...rest):Coordinate 
     46                { 
     47                        return map.getMapProvider().locationCoordinate(l); 
     48                } 
    4449         
    45                 public function rescale(event:Event=null):void 
    46                 { 
    47                         scaleX = scaleY = Math.pow(2, map.grid.zoomLevel - drawZoom); 
    48                 } 
    49                  
    5050                public function redraw(event:Event=null):void 
    51                 { 
    52                         drawZoom = map.grid.zoomLevel; 
     51                {        
     52                        var grid:TileGrid = map.grid; 
     53                         
     54                        if (drawZoom && Math.abs(grid.zoomLevel-drawZoom) < zoomTolerance) { 
     55                                scaleX = scaleY = Math.pow(2, grid.zoomLevel-drawZoom); 
     56                                return; 
     57                        } 
     58                         
     59                        drawZoom = grid.zoomLevel; 
    5360                        scaleX = scaleY = 1; 
    5461                         
    55                         var firstPoint:Point = map.locationPoint(location)             
     62                        var firstPoint:Point = grid.coordinatePoint(coordinates[0]); // map.locationPoint(location)            
    5663                        graphics.clear(); 
    5764                        if (line && lineAlpha) { 
    58                                 graphics.lineStyle(lineThickness, lineColor, lineAlpha); 
     65                                graphics.lineStyle(lineThickness, lineColor, lineAlpha, false, LineScaleMode.NONE); 
    5966                        } 
    6067                        else { 
     
    6572                        } 
    6673                        graphics.moveTo(0, 0); 
    67                         for each (var loc:Location in locations.slice(1)) { 
    68                                 var p:Point = map.locationPoint(loc); 
     74                        var p:Point; 
     75                        for each (var coord:Coordinate in coordinates.slice(1)) { 
     76                                p = grid.coordinatePoint(coord); 
    6977                                graphics.lineTo(p.x-firstPoint.x, p.y-firstPoint.y); 
    7078                        } 
    71                       if (loc.lat != location.lat && loc.lon != location.lon) { 
     79/*                    if (loc.lat != location.lat && loc.lon != location.lon) { 
    7280                                graphics.lineTo(0, 0); 
    73                         } 
     81                        } */ 
    7482                        if (fillAlpha) { 
    7583                                graphics.endFill(); 
  • trunk/as3/lib/com/modestmaps/core/TileGrid.as

    r647 r671  
    165165 
    166166                // for pan events 
    167                 protected var startPan:Point
     167                protected var startPan:Coordinate
    168168                public var panning:Boolean; 
    169169                 
     
    339339                        var boundsEnforced:Boolean = enforceBounds(); 
    340340 
    341                         if (zooming && panning) { 
    342                                 // doesn't bubble, unlike MapEvent 
    343                                 // Map will pick this up and dispatch MapEvent.EXTENT_CHANGED for us 
    344                                 dispatchEvent(new Event(Event.CHANGE, false, false)); 
    345                         }  
    346                         else if (panning) { 
    347                                 if (startPan) { 
    348                                         dispatchEvent(new MapEvent(MapEvent.PANNED, new Point(worldMatrix.tx-startPan.x, worldMatrix.ty-startPan.y))); 
    349                                 }                        
    350                                 else { 
    351                                         // TODO: this should probably be an error, but I'm not convinced that it can't happen yet :) 
    352                                         //trace("panning but no startPan"); 
    353                                 }                
    354                         }        
    355                         else if (zooming) { 
    356                         var zoomEvent:MapEvent = new MapEvent(MapEvent.ZOOMED_BY, zoomLevel-startZoom); 
    357                         // this might also be useful 
    358                 zoomEvent.zoomLevel = zoomLevel; 
    359                 dispatchEvent(zoomEvent); 
     341                        if (zooming || panning) { 
     342                                if (panning) { 
     343                                        var pt:Point = coordinatePoint(startPan); 
     344                                        dispatchEvent(new MapEvent(MapEvent.PANNED, pt.subtract(new Point(mapWidth/2, mapHeight/2)))); 
     345                                }        
     346                                if (zooming) { 
     347                                var zoomEvent:MapEvent = new MapEvent(MapEvent.ZOOMED_BY, zoomLevel-startZoom); 
     348                                // this might also be useful 
     349                    zoomEvent.zoomLevel = zoomLevel; 
     350                        dispatchEvent(zoomEvent); 
     351                                } 
    360352                        } 
    361353                        else if (boundsEnforced) { 
     
    10791071                { 
    10801072                        // this is the same as coord.zoomTo, but doesn't make a new Coordinate: 
    1081                         var zoomFactor:Number = Math.pow(2, zoomLevel - coord.zoom) 
     1073                        var zoomFactor:Number = Math.pow(2, zoomLevel - coord.zoom); 
     1074                        //zoomFactor *= tileWidth/scale; 
    10821075                        var zoomedColumn:Number = coord.column * zoomFactor; 
    10831076                        var zoomedRow:Number = coord.row * zoomFactor; 
    10841077                         
    1085                       var tl:Coordinate = topLeftCoordinate; 
     1078                      var tl:Coordinate = topLeftCoordinate; 
    10861079                        var br:Coordinate = bottomRightCoordinate; 
    10871080                         
     
    10891082                        var rows:Number = br.row - tl.row; 
    10901083                         
    1091                         var screenPoint:Point = new Point(mapWidth * (zoomedColumn-tl.column) / cols, mapHeight * (zoomedRow-tl.row) / rows); 
     1084                        var screenPoint:Point = new Point(mapWidth * (zoomedColumn-tl.column) / cols, mapHeight * (zoomedRow-tl.row) / rows);  
     1085                         
     1086                        //var screenPoint:Point = worldMatrix.transformPoint(new Point(zoomedColumn, zoomedRow)); 
    10921087 
    10931088                        if (context && context != this) 
     
    11211116                                } 
    11221117                        } 
    1123                         startPan = new Point(tx, ty); 
     1118                        startPan = centerCoordinate.copy(); 
    11241119                        panning = true; 
    11251120                        dispatchEvent(new MapEvent(MapEvent.START_PANNING));