Add Leaflet-style zoom-to-bbox with shift-drag
authorRichard Fairhurst <richard@systemeD.net>
Sun, 26 Feb 2017 20:04:14 +0000 (20:04 +0000)
committerRichard Fairhurst <richard@systemeD.net>
Sun, 26 Feb 2017 20:04:14 +0000 (20:04 +0000)
net/systemeD/halcyon/Map.as
net/systemeD/potlatch2/controller/ControllerState.as
net/systemeD/potlatch2/controller/ZoomArea.as [new file with mode: 0644]

index db15bf4..779a1e4 100644 (file)
@@ -178,6 +178,14 @@ package net.systemeD.halcyon {
                        updateAllEntityUIs(false,false);
                        download();
                }
+
+               public function moveMapFromLatLonScale(lat:Number,lon:Number,z:Number):void {
+                       setScale(z);
+                       updateCoordsFromLatLon(lat,lon);
+                       tileset.changeScale(z);
+                       updateAllEntityUIs(true,true);
+                       download();
+               }
                
                /** Recentre map at given lat/lon, if that point is currently outside the visible area. */
                public function scrollIfNeeded(lat:Number,lon:Number): void{
@@ -308,7 +316,7 @@ package net.systemeD.halcyon {
                // ------------------------------------------------------------------------------------------
                // Redraw all items, zoom in and out
                
-               private function updateAllEntityUIs(redraw:Boolean,remove:Boolean):void {
+               public function updateAllEntityUIs(redraw:Boolean,remove:Boolean):void {
                        for (var i:uint=0; i<paintContainer.numChildren; i++)
                                getLayerAt(i).updateEntityUIs(redraw, remove);
                }
@@ -328,11 +336,15 @@ package net.systemeD.halcyon {
                public function zoomOut():void {
                        if (scale!=MINSCALE_TILES) changeScale(scale-1);
                }
-
-               public function changeScale(newscale:uint):void {
+               
+               public function setScale(newscale:uint):void {
                        scale=newscale;
                        this.dispatchEvent(new MapEvent(MapEvent.SCALE, {scale:scale}));
                        scalefactor=MASTERSCALE/Math.pow(2,13-scale);
+               }
+
+               public function changeScale(newscale:uint):void {
+                       setScale(newscale);
                        updateCoordsFromLatLon((edge_t+edge_b)/2,(edge_l+edge_r)/2);    // recentre
                        tileset.changeScale(scale);
                        updateAllEntityUIs(true,true);
index f769e3f..188f70a 100644 (file)
@@ -154,6 +154,8 @@ package net.systemeD.potlatch2.controller {
                                        return new DragSelection(selection, event);
                                } else if (entity) {
                                        return controller.findStateForSelection([entity]);
+                               } else if (!entity && event.shiftKey) {
+                                       return new ZoomArea(event.localX,event.localY,this);
                                } else if (event.ctrlKey && !layer.isBackground) {
                                        return new SelectArea(event.localX,event.localY,selection);
                                }
diff --git a/net/systemeD/potlatch2/controller/ZoomArea.as b/net/systemeD/potlatch2/controller/ZoomArea.as
new file mode 100644 (file)
index 0000000..8189dd8
--- /dev/null
@@ -0,0 +1,79 @@
+package net.systemeD.potlatch2.controller {
+
+       import flash.display.*;
+       import flash.events.*;
+       import net.systemeD.halcyon.connection.*;
+
+    public class ZoomArea extends ControllerState {
+
+               private var startX:Number;
+               private var startY:Number;
+               private var endX:Number;
+               private var endY:Number;
+               private var box:Shape;
+               private const TOLERANCE:uint=4;
+        protected var previousState:ControllerState;
+
+               public function ZoomArea(x:Number,y:Number,previousState:ControllerState) {
+            this.previousState = previousState;
+                       startX=endX=x;
+                       startY=endY=y;
+               }
+
+        override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
+            if (event.type==MouseEvent.MOUSE_MOVE) { 
+                               // ** FIXME: weird things happen if you mouse-over the drag-and-drop panel
+                               endX=event.localX;
+                               endY=event.localY;
+                               drawSelectionBox();
+                       } else if (event.type==MouseEvent.MOUSE_UP) { 
+                               // select everything within boundary
+                               var a:Number;
+                               if (startX>endX) { a=startX; startX=endX; endX=a; }
+                               if (startY>endY) { a=startY; startY=endY; endY=a; }
+                               if (endX-startX>=TOLERANCE || endY-startY>=TOLERANCE) { 
+                                       var left:Number=controller.map.coord2lon(startX);
+                                       var right:Number=controller.map.coord2lon(endX);
+                                       var top:Number=controller.map.coord2lat(startY);
+                                       var bottom:Number=controller.map.coord2lat(endY);
+                                       var lon:Number = (left+right)/2;
+                                       var lat:Number = (top+bottom)/2;
+
+                                       var z:uint = controller.map.scale;
+                                       var w:Number = controller.map.edge_r-controller.map.edge_l;
+                                       var h:Number = controller.map.edge_t-controller.map.edge_b;
+
+                                       do {
+                                               z++; w/=2; h/=2;
+                                       } while (left>=(lon-w/2) && right<=(lon+w/2) && bottom>=(lat-h/2) && top<=(lat+h/2) && z<controller.map.MAXSCALE);
+                                       controller.map.moveMapFromLatLonScale(lat,lon,z-1);
+                               }
+                       return previousState;
+                       }
+            return this;
+        }
+
+               private function drawSelectionBox():void {
+                       box.graphics.clear();
+                       box.graphics.beginFill(0xDDDDFF,0.5);
+                       box.graphics.lineStyle(1,0xFF0000);
+                       box.graphics.drawRect(startX,startY,endX-startX,endY-startY);
+               }
+               
+               override public function enterState():void {
+                       box=new Shape();
+                       var l:DisplayObject=layer.getPaintSpriteAt(layer.maxlayer);
+                       var o:DisplayObject=Sprite(l).getChildAt(3);
+                       (o as Sprite).addChild(box);
+                       controller.map.draggable=false;
+               }
+               override public function exitState(newState:ControllerState):void {
+                       box.parent.removeChild(box);
+                       controller.map.draggable=true;
+               }
+               override public function toString():String {
+                       return "ZoomArea";
+               }
+       }
+
+}