Changeset 599
- Timestamp:
- 07/16/08 12:57:21 (2 months ago)
- Files:
-
- branches/tom-tweenlite/lib/com/modestmaps/core/Coordinate.as (modified) (1 diff)
- branches/tom-tweenlite/lib/com/modestmaps/core/MarkerClip.as (modified) (2 diffs)
- branches/tom-tweenlite/lib/com/modestmaps/core/TileGrid.as (modified) (31 diffs)
- branches/tom-tweenlite/lib/com/modestmaps/extras/ZoomSlider.as (added)
- branches/tom-tweenlite/lib/com/modestmaps/Map.as (modified) (12 diffs)
- branches/tom-tweenlite/lib/com/modestmaps/mapproviders/AbstractMapProvider.as (modified) (2 diffs)
- branches/tom-tweenlite/lib/com/modestmaps/TweenMap.as (modified) (11 diffs)
- branches/tom-tweenlite/samples/as3/ModestMapsSample.as (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/tom-tweenlite/lib/com/modestmaps/core/Coordinate.as
r292 r599 11 11 public var zoom:Number; 12 12 13 public static const MAX_ZOOM:Number = 20;14 15 13 public function Coordinate(row:Number, column:Number, zoom:Number) 16 14 { branches/tom-tweenlite/lib/com/modestmaps/core/MarkerClip.as
r595 r599 262 262 protected function onMapPanned(event:MapEvent):void 263 263 { 264 if (starting) { 264 if (map.grid.panning && map.grid.zooming) { 265 // only reprojecting can save you now 266 dirty = true; 267 return; 268 } 269 else if (starting) { 265 270 x = starting.x + event.panDelta.x; 266 271 y = starting.y + event.panDelta.y; 267 272 } 268 273 else { 274 // TODO: this shouldn't really ever happen, and the following might not work: 269 275 x = event.panDelta.x; 270 276 y = event.panDelta.y; … … 295 301 */ 296 302 dirty = true; 297 //updateClips();303 updateClips(); 298 304 } 299 305 branches/tom-tweenlite/lib/com/modestmaps/core/TileGrid.as
r598 r599 27 27 // we need a reference to our map for createTile() only, 28 28 // slightly messy but better than a whole TileFactory hierarchy! 29 // TODO: can we just use a function? how would TweenMap override it? 29 30 private var map:Map; 30 31 … … 39 40 protected var minTx:Number, maxTx:Number, minTy:Number, maxTy:Number; 40 41 41 // pan and zoom 42 protected var _panX:Number;43 protected var _panY:Number;44 protected var _scale:Number;45 42 // pan and zoom etc are stored in here 43 // NB: this matrix is never applied to a DisplayObject's transform 44 // because it would require scaling tile positions to compensate 45 // instead, we adapt its values such that the current zoom level 46 // is approximately scale 1, and positions make sense in screen pixels 46 47 protected var worldMatrix:Matrix; 48 49 // this turns screen points into coordinates 47 50 protected var _invertedMatrix:Matrix; // use lazy getter for this 48 51 49 // these also have lazy getters 52 // the corners of the screen, in map coordinates 53 // (these also have lazy getters) 50 54 protected var _topLeftCoordinate:Coordinate; 51 55 protected var _bottomRightCoordinate:Coordinate; … … 114 118 protected static const DEFAULT_MAX_TILES_TO_KEEP:int = 256; 115 119 protected static const DEFAULT_TILE_BUFFER:int = 0; 116 protected static const DEFAULT_ENFORCE_BOUNDS:Boolean = false;120 protected static const DEFAULT_ENFORCE_BOUNDS:Boolean = true; 117 121 118 122 /** if we don't have a tile at currentZoom, onRender will look for tiles up to 5 levels out. … … 155 159 this.provider = provider; 156 160 157 _panX = -provider.tileWidth/2; 158 _panY = -provider.tileHeight/2; 159 _scale = 1; 161 doubleClickEnabled = true; 160 162 161 163 // from provider: … … 180 182 181 183 well = new Sprite(); 184 well.doubleClickEnabled = true; 185 well.mouseEnabled = true; 186 well.mouseChildren = false; 182 187 addChild(well); 183 188 184 worldMatrix = new Matrix();189 /* worldMatrix = new Matrix(); 185 190 worldMatrix.translate(_panX,_panX); 186 191 worldMatrix.scale(_scale,_scale); 187 worldMatrix.translate(mapWidth/2, mapHeight/2); 192 worldMatrix.translate(mapWidth/2, mapHeight/2); */ 193 194 worldMatrix = new Matrix(); 195 /* worldMatrix.translate(-provider.tileWidth/2, -provider.tileHeight/2); 196 worldMatrix.scale(1, 1); 197 worldMatrix.translate(mapWidth/2, mapHeight/2); */ 188 198 189 199 addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); … … 229 239 } 230 240 231 debugField.text = "tx: " + _panX.toFixed(3) + " ty: " + _panY.toFixed(3) + " sc: " + _scale.toFixed(4)241 debugField.text = "tx: " + tx.toFixed(3) + " ty: " + tx.toFixed(3) + " sc: " + scale.toFixed(4) 232 242 + "\nfps: " + fps.toFixed(0) 233 243 + "\ncurrent child count: " + well.numChildren … … 253 263 if (!dirty || !stage) { 254 264 return; 265 } 266 267 enforceBounds(); 268 269 if (zooming && panning) { 270 map.onExtentChanged(map.getExtent()); 271 } 272 else if (panning) { 273 if (startPan) { 274 dispatchEvent(new MapEvent(MapEvent.PANNED, new Point(worldMatrix.tx-startPan.x, worldMatrix.ty-startPan.y))); 275 } 276 else { 277 trace("panning but no startPan"); 278 } 279 } 280 else if (zooming) { 281 var zoomEvent:MapEvent = new MapEvent(MapEvent.ZOOMED_BY); 282 zoomEvent.zoomDelta = zoomLevel-startZoom; 283 zoomEvent.zoomLevel = zoomLevel; 284 dispatchEvent(zoomEvent); 255 285 } 256 286 … … 476 506 tile.x = positionCol*provider.tileWidth*positionScaleCompensation; 477 507 tile.y = positionRow*provider.tileHeight*positionScaleCompensation; 478 tile.scaleX = tile.scaleY = Math.pow(2, zoomLevel-tile.zoom); 508 509 var tileScale:Number = Math.pow(2, zoomLevel-tile.zoom); 510 tileScale = Math.ceil(tileScale * provider.tileWidth) / provider.tileWidth; // round up to the nearest pixel 511 tile.scaleX = tile.scaleY = tileScale; 479 512 } 480 513 … … 482 515 // let's make sure we keep them around: 483 516 var maxRecentlySeen:int = Math.max(visibleTiles.length,maxTilesToKeep); 484 /* trace();485 trace('visibleTiles', visibleTiles.length);486 trace('maxRecentlySeen', maxRecentlySeen);487 trace('recentlySeen', recentlySeen.length); */488 517 489 518 // prune cache of already seen tiles if it's getting too big: … … 691 720 } 692 721 693 public function mousePressed(event:MouseEvent =null):void722 public function mousePressed(event:MouseEvent):void 694 723 { 695 724 prepareForPanning(true); 696 pmouse = globalToLocal(new Point(event.stageX, event.stageY));725 pmouse = new Point(event.stageX, event.stageY); 697 726 stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseDragged); 698 727 stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleased); … … 700 729 } 701 730 702 public function mouseReleased(event:Event =null):void731 public function mouseReleased(event:Event):void 703 732 { 704 733 stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseDragged); … … 713 742 public function mouseDragged(event:MouseEvent):void 714 743 { 715 var mousePoint:Point = globalToLocal(new Point(event.stageX, event.stageY));716 _panX += (mousePoint.x - pmouse.x) / _scale;717 _panY += (mousePoint.y - pmouse.y) / _scale;744 var mousePoint:Point = new Point(event.stageX, event.stageY); 745 tx += mousePoint.x - pmouse.x; 746 ty += mousePoint.y - pmouse.y; 718 747 pmouse = mousePoint; 719 calculateMatrix();720 var origin:Point = startPan || new Point(_panX,_panY);721 dispatchEvent(new MapEvent(MapEvent.PANNED, new Point(-(origin.x-_panX)*_scale, -(origin.y-_panY)*_scale)));722 748 event.updateAfterEvent(); 723 749 } 724 750 725 private function calculateMatrix():void726 {727 // first, simply do what was asked:728 worldMatrix.identity();729 worldMatrix.translate(_panX,_panY);730 worldMatrix.scale(_scale,_scale);731 worldMatrix.translate(mapWidth/2, mapHeight/2);732 733 // nullify things that will be recalculated as needed734 _invertedMatrix = null;735 _topLeftCoordinate = null;736 _bottomRightCoordinate = null;737 738 // enforce map bounds?739 if (enforceBounds()) {740 // try again!741 worldMatrix.identity();742 worldMatrix.translate(_panX,_panY);743 worldMatrix.scale(_scale,_scale);744 worldMatrix.translate(mapWidth/2, mapHeight/2);745 746 // nullify things that will be recalculated as needed747 _invertedMatrix = null;748 _topLeftCoordinate = null;749 _bottomRightCoordinate = null;750 }751 752 // and request a redraw:753 dirty = true;754 }755 756 751 // today is all about lazy evaluation 757 // this gets set to null by calculateMatrix752 // this gets set to null by 'dirty = true' 758 753 // and only calculated again if you need it 759 754 protected function get invertedMatrix():Matrix … … 762 757 _invertedMatrix = worldMatrix.clone(); 763 758 _invertedMatrix.invert(); 759 _invertedMatrix.scale(scale/provider.tileWidth, scale/provider.tileHeight); 764 760 } 765 761 return _invertedMatrix; … … 774 770 if (!_topLeftCoordinate) { 775 771 var tl:Point = invertedMatrix.transformPoint(new Point()); 776 tl.x *= _scale/provider.tileWidth;777 tl.y *= _scale/provider.tileHeight;778 772 _topLeftCoordinate = new Coordinate(tl.y, tl.x, zoomLevel); 779 773 } … … 789 783 if (!_bottomRightCoordinate) { 790 784 var br:Point = invertedMatrix.transformPoint(new Point(mapWidth, mapHeight)); 791 br.x *= _scale/provider.tileWidth;792 br.y *= _scale/provider.tileHeight;793 785 _bottomRightCoordinate = new Coordinate(br.y, br.x, zoomLevel); 794 786 } … … 805 797 { 806 798 var c:Point = invertedMatrix.transformPoint(new Point(mapWidth/2, mapHeight/2)); 807 c.x *= _scale/provider.tileWidth;808 c.y *= _scale/provider.tileHeight;809 799 return new Coordinate(c.y, c.x, zoomLevel); 810 800 } … … 842 832 843 833 var p:Point = invertedMatrix.transformPoint(point); 844 return new Coordinate( _scale*p.y/provider.tileHeight, _scale*p.x/provider.tileWidth, zoomLevel);834 return new Coordinate(p.y, p.x, zoomLevel); 845 835 } 846 836 … … 855 845 } 856 846 } 857 startPan = new Point( _panX,_panY);847 startPan = new Point(tx, ty); 858 848 panning = true; 859 849 dispatchEvent(new MapEvent(MapEvent.START_PANNING)); … … 874 864 public function prepareForZooming():void 875 865 { 866 //trace(getTimer(), 'TileGrid.prepareForZooming'); 876 867 if (startZoom >= 0) { 877 868 doneZooming(); … … 886 877 public function doneZooming():void 887 878 { 879 //trace(getTimer(), 'TileGrid.doneZooming'); 888 880 startZoom = -1; 889 881 zooming = false; … … 895 887 public function resetTiles(coord:Coordinate, point:Point):void 896 888 { 897 // set new scale according to zoom 898 _scale = Math.pow(2, coord.zoom); 899 900 // figure out where in the world we are 901 _panX = -provider.tileWidth*coord.column/_scale; 902 _panY = -provider.tileHeight*coord.row/_scale; 903 904 // plus the offset 905 _panX += point.x/_scale; 906 _panY += point.y/_scale; 907 889 //trace("resetTiles", coord, point); 890 891 var sc:Number = Math.pow(2, coord.zoom); 892 893 worldMatrix.identity(); 894 //worldMatrix.translate( -mapWidth/2, -mapHeight/2 ); 895 worldMatrix.scale(sc, sc); 896 worldMatrix.translate(mapWidth/2, mapHeight/2 ); 897 worldMatrix.translate(point.x, point.y); 898 worldMatrix.translate(-provider.tileWidth*coord.column, -provider.tileHeight*coord.row); 899 900 dirty = true; 908 901 // reset the worldMatrix 909 calculateMatrix(); 910 } 911 912 public function get panX():Number 913 { 914 return _panX; 915 } 916 917 public function set panX(n:Number):void 918 { 919 if (n != panX) 920 { 921 var origin:Point = startPan || new Point(_panX, _panY); 922 _panX = n; 923 calculateMatrix(); 924 dispatchEvent(new MapEvent(MapEvent.PANNED, new Point(-(origin.x - _panX) * _scale, -(origin.y - _panY) * _scale))); 925 } 926 } 927 928 public function get panY():Number 929 { 930 return _panY; 931 } 932 public function set panY(n:Number):void 933 { 934 if (n != panY) 935 { 936 var origin:Point = startPan || new Point(_panX, _panY); 937 _panY = n; 938 calculateMatrix(); 939 dispatchEvent(new MapEvent(MapEvent.PANNED, new Point(-(origin.x - _panX) * _scale, -(origin.y - _panY) * _scale))); 940 } 902 //calculateMatrix(); 941 903 } 942 904 943 905 public function get zoomLevel():Number 944 906 { 945 return Math.log( _scale) / Math.log(2);907 return Math.log(scale) / Math.log(2); 946 908 } 947 909 … … 950 912 if (zoomLevel != n) 951 913 { 952 _scale = Math.pow(2, n); 953 calculateMatrix(); 954 var zoomEvent:MapEvent = new MapEvent(MapEvent.ZOOMED_BY); 955 zoomEvent.zoomDelta = zoomLevel-startZoom; 956 zoomEvent.zoomLevel = zoomLevel; 957 dispatchEvent(zoomEvent); 914 scale = Math.pow(2, n); 958 915 } 959 916 } … … 961 918 public function get scale():Number 962 919 { 963 return _scale;920 return Math.sqrt(worldMatrix.a * worldMatrix.a + worldMatrix.b * worldMatrix.b); 964 921 } 965 922 … … 968 925 if (scale != n) 969 926 { 970 var old:Number = zoomLevel; 971 _scale = n; 972 calculateMatrix(); 973 prepareForZooming(); 974 var zoomEvent:MapEvent = new MapEvent(MapEvent.ZOOMED_BY); 975 zoomEvent.zoomDelta = zoomLevel-old; 976 zoomEvent.zoomLevel = zoomLevel; 977 dispatchEvent(zoomEvent); 978 doneZooming(); 927 var needsStop:Boolean = false; 928 if (!zooming) { 929 prepareForZooming(); 930 needsStop = true; 931 } 932 933 var sc:Number = n / scale; 934 worldMatrix.translate(-mapWidth/2, -mapHeight/2); 935 worldMatrix.scale(sc, sc); 936 worldMatrix.translate(mapWidth/2, mapHeight/2); 937 938 dirty = true; 939 940 if (needsStop) { 941 doneZooming(); 942 } 979 943 } 980 944 } … … 984 948 if (mapWidth != p.x || mapHeight != p.y) 985 949 { 950 var dx:Number = p.x - mapWidth; 951 var dy:Number = p.y - mapHeight; 952 953 // maintain the center point: 954 tx += dx/2; 955 ty += dy/2; 956 986 957 mapWidth = p.x; 987 958 mapHeight = p.y; 988 959 scrollRect = new Rectangle(0, 0, mapWidth, mapHeight); 989 calculateMatrix(); 960 961 dirty = true; 962 990 963 // force this but only for onResize 991 964 onRender(); … … 1060 1033 } 1061 1034 1062 /** called inside of calculateMatrixbefore events are fired1035 /** called inside of onRender before events are fired 1063 1036 * don't use setters inside of here to correct values otherwise we'll get stuck in a loop! */ 1064 protected function enforceBounds():Boolean1037 protected function enforceBounds():Boolean 1065 1038 { 1066 1039 if (!enforceBoundsEnabled) { … … 1068 1041 } 1069 1042 1070 /* if (zoomLevel < minZoom) { 1071 _scale = Math.pow(2, minZoom); 1072 return true; 1073 } 1074 1075 if (zoomLevel > maxZoom) { 1076 _scale = Math.pow(2, maxZoom); 1077 return true; 1078 } */ 1043 if (zoomLevel < minZoom) { 1044 scale = Math.pow(2, minZoom); 1045 } 1046 else if (zoomLevel > maxZoom) { 1047 scale = Math.pow(2, maxZoom); 1048 } 1079 1049 1080 1050 var touched:Boolean = false; … … 1088 1058 if (rightX-leftX > maxTx-minTx) { 1089 1059 //trace("CENTERING X"); 1090 _panX = -(minTx+maxTx)/2; 1060 //_panX = -(minTx+maxTx)/2; 1061 worldMatrix.tx = (mapWidth-(minTx+maxTx)*scale)/2; 1091 1062 touched = true; 1092 1063 } 1093 1064 else if (leftX < minTx) { 1094 1065 //trace("TOO LEFT"); 1095 _panX += leftX-minTx; 1066 //_panX += leftX-minTx; 1067 worldMatrix.tx += (leftX-minTx)*scale; 1096 1068 touched = true; 1097 1069 } 1098 1070 else if (rightX > maxTx) { 1099 1071 //trace("TOO RIGHT"); 1100 _panX += rightX-maxTx; 1072 //_panX += rightX-maxTx; 1073 worldMatrix.tx += (rightX-maxTx)*scale; 1101 1074 touched = true; 1102 } 1075 } 1103 1076 1104 1077 var upY:Number = tl.row * provider.tileHeight; … … 1107 1080 if (downY-upY > maxTy-minTy) { 1108 1081 //trace("CENTERING Y"); 1109 _panY = -(minTy+maxTy)/2; 1082 //_panY = -(minTy+maxTy)/2; 1083 worldMatrix.ty = (mapHeight-(minTy+maxTy)*scale)/2; 1110 1084 touched = true; 1111 1085 } 1112 1086 else if (upY < minTy) { 1113 1087 //trace("TOO HIGH"); 1114 _panY += upY-minTy; 1088 //_panY += upY-minTy; 1089 worldMatrix.ty += (upY-minTy)*scale; 1115 1090 touched = true; 1116 1091 } 1117 1092 else if (downY > maxTy) { 1118 1093 //trace("TOO LOW"); 1119 _panY += downY-maxTy; 1094 //_panY += downY-maxTy; 1095 worldMatrix.ty += (downY-maxTy)*scale; 1120 1096 touched = true; 1121 1097 } 1122 1098 1099 if (touched) { 1100 _invertedMatrix = null; 1101 _topLeftCoordinate = null; 1102 _bottomRightCoordinate = null; 1103 } 1104 1123 1105 //trace("bounds of visible map area: ", leftX, rightX, upY, downY); 1124 1106 1125 1107 return touched; 1126 }1127 1128 override public function set doubleClickEnabled(enabled:Boolean):void1129 {1130 if (enabled) {1131 well.doubleClickEnabled = true;1132 well.mouseEnabled = true;1133 well.mouseChildren = false;1134 }1135 else {1136 well.doubleClickEnabled = false;1137 }1138 super.doubleClickEnabled = false;1139 1108 } 1140 1109 … … 1144 1113 if (d) { 1145 1114 if (stage) stage.invalidate(); 1115 1116 _invertedMatrix = null; 1117 _topLeftCoordinate = null; 1118 _bottomRightCoordinate = null; 1146 1119 } 1147 1120 } … … 1151 1124 return _dirty; 1152 1125 } 1153 1126 1127 public function getMatrix():Matrix 1128 { 1129 return worldMatrix.clone(); 1130 } 1131 1132 public function setMatrix(m:Matrix):void 1133 { 1134 worldMatrix = m; 1135 dirty = true; 1136 } 1137 1138 public function get a():Number 1139 { 1140 return worldMatrix.a; 1141 } 1142 public function get b():Number 1143 { 1144 return worldMatrix.b; 1145 } 1146 public function get c():Number 1147 { 1148 return worldMatrix.c; 1149 } 1150 public function get d():Number 1151 { 1152 return worldMatrix.d; 1153 } 1154 public function get tx():Number 1155 { 1156 return worldMatrix.tx; 1157 } 1158 public function get ty():Number 1159 { 1160 return worldMatrix.ty; 1161 } 1162 1163 public function set a(n:Number):void 1164 { 1165 worldMatrix.a = n; 1166 dirty = true; 1167 } 1168 public function set b(n:Number):void 1169 { 1170 worldMatrix.b = n; 1171 dirty = true; 1172 } 1173 public function set c(n:Number):void 1174 { 1175 worldMatrix.c = n; 1176 dirty = true; 1177 } 1178 public function set d(n:Number):void 1179 { 1180 worldMatrix.d = n; 1181 dirty = true; 1182 } 1183 public function set tx(n:Number):void 1184 { 1185 worldMatrix.tx = n; 1186 dirty = true; 1187 } 1188 public function set ty(n:Number):void 1189 { 1190 worldMatrix.ty = n; 1191 dirty = true; 1192 } 1193 1154 1194 } 1155 1195 branches/tom-tweenlite/lib/com/modestmaps/Map.as
r595 r599 39 39 import flash.events.MouseEvent; 40 40 import flash.external.ExternalInterface; 41 import flash.geom.Matrix; 41 42 import flash.geom.Point; 42 43 import flash.geom.Rectangle; … … 91 92 * @see com.modestmaps.core.TileGrid 92 93 */ 93 public function Map(width:Number=320, height:Number=240, draggable:Boolean=true, provider:IMapProvider=null, ... rest)94 public function Map(width:Number=320, height:Number=240, draggable:Boolean=true, mapProvider:IMapProvider=null, ... rest) 94 95 { 95 96 if (!Reactor.running()) … … 100 101 } 101 102 102 // don't call set map provider here 103 // the extents are all squirrely 104 mapProvider = provider || new MicrosoftProvider(MicrosoftProvider.ROAD); 103 if (!mapProvider) mapProvider = new MicrosoftProvider(MicrosoftProvider.ROAD); 104 105 // don't call setMapProvider here 106 // the extent calculations are all squirrely 107 this.mapProvider = mapProvider; 105 108 106 109 // initialize the grid (so point/location/coordinate functions should be valid after this) … … 140 143 else { 141 144 var extent:MapExtent = new MapExtent(85, -85, 180, -180); 142 //setExtent(extent);143 145 144 146 var l1:Location = mapProvider.coordinateLocation(mapProvider.outerLimits()[0]); … … 157 159 extent.east = l2.lon; 158 160 } 159 160 //trace(extent);161 161 162 162 setExtent(extent); … … 307 307 var centerCoord:Coordinate = (new Coordinate(centerRow, centerColumn, centerZoom)).zoomTo(initZoom); 308 308 309 trace("centering on", centerCoord); 310 309 311 return coordinatePosition(centerCoord); 310 312 } … … 502 504 if (!grid.panning && !grid.zooming) { 503 505 grid.prepareForPanning(); 504 grid. panY = grid.panY+(mapHeight*panFraction/grid.scale);506 grid.ty += (mapHeight*panFraction); 505 507 grid.donePanning(); 506 508 } … … 512 514 if (!grid.panning && !grid.zooming) { 513 515 grid.prepareForPanning(); 514 grid. panY = grid.panY-(mapHeight*panFraction/grid.scale);516 grid.ty -= (mapHeight*panFraction); 515 517 grid.donePanning(); 516 518 } … … 522 524 if (!grid.panning && !grid.zooming) { 523 525 grid.prepareForPanning(); 524 grid. panX = grid.panX+(mapWidth*panFraction/grid.scale);526 grid.tx += (mapWidth*panFraction); 525 527 grid.donePanning(); 526 528 } … … 532 534 if (!grid.panning && !grid.zooming) { 533 535 grid.prepareForPanning(); 534 grid. panX = grid.panX-(mapWidth*panFraction/grid.scale);536 grid.tx -= (mapWidth*panFraction); 535 537 grid.donePanning(); 536 538 } 537 539 } 538 540 541 /** zoom in, keeping the requested point in the same place */ 542 public function zoomInAbout(targetPoint:Point=null, duration:Number=-1):void 543 { 544 zoomByAbout(1, targetPoint, duration); 545 } 546 547 /** zoom out, keeping the requested point in the same place */ 548 public function zoomOutAbout(targetPoint:Point=null, duration:Number=-1):void 549 { 550 zoomByAbout(-1, targetPoint, duration); 551 } 552 553 /** zoom in or out by zoomDelta, keeping the requested point in the same place */ 554 public function zoomByAbout(zoomDelta:int, targetPoint:Point=null, duration:Number=-1):void 555 { 556 if (!targetPoint) targetPoint = new Point(mapWidth/2, mapHeight/2); 557 558 var sc:Number = Math.pow(2, zoomDelta); 559 560 grid.prepareForZooming(); 561 grid.prepareForPanning(); 562 563 var m:Matrix = grid.getMatrix(); 564 565 m.translate(-targetPoint.x, -targetPoint.y); 566 m.scale(sc, sc); 567 m.translate(targetPoint.x, targetPoint.y); 568 569 &
