Last active
December 10, 2015 17:08
-
-
Save kukulski/4465533 to your computer and use it in GitHub Desktop.
PanZoom logic -- logic to maintain expected 1:1 correspondence with dragged content as it is simultaneously dragged and scaled
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| I'm building a plugin for Illustrator enable the expected behavior for multitouch pan-zoom, | |
| and needed to get the geometry right for the CoreImage draw API, (for fast feedback) | |
| so here's a tiny as3 implementation that confirms the correct behavior | |
| */ | |
| package { | |
| import flash.geom.Point; | |
| import flash.geom.Rectangle; | |
| public class RectScaler { | |
| private var offset:Point; | |
| private var offsetNow:Point = new Point; | |
| private var scaleNow:Number; | |
| public function startDrag(downLocation:Point):void { | |
| offset = new Point(-downLocation.x, -downLocation.y); | |
| } | |
| public function setPanZoom(cursor:Point, scale:Number):void { | |
| offsetNow.x = offset.x * scale + cursor.x; | |
| offsetNow.y = offset.y * scale + cursor.y; | |
| scaleNow = scale; | |
| } | |
| public function transformRect(r:Rectangle):Rectangle { | |
| return new Rectangle( | |
| r.x*scaleNow + offsetNow.x, | |
| r.y*scaleNow + offsetNow.y, | |
| r.width*scaleNow, | |
| r.height*scaleNow); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class RectTransformer { | |
| public: | |
| void startDrag(const AIRealPoint &startPosition, NSRect bounds) { | |
| centeredAroundCursor = bounds; | |
| centeredAroundCursor.origin.x -= startPosition.h; | |
| centeredAroundCursor.origin.y -= startPosition.v; | |
| } | |
| NSRect panZoom(float scale, const AIRealPoint &newCenter) { | |
| NSRect scaledAroundCursor = scaleAll(centeredAroundCursor,scale); | |
| scaledAroundCursor.origin.x += newCenter.h; | |
| scaledAroundCursor.origin.y += newCenter.v; | |
| return scaledAroundCursor; | |
| } | |
| private: | |
| NSRect scaleAll(const NSRect &r, float scale) { | |
| return {{r.origin.x * scale, r.origin.y * scale}, | |
| {r.size.width * scale, r.size.height * scale}}; | |
| } | |
| NSRect centeredAroundCursor; | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package | |
| { | |
| import flash.display.Sprite; | |
| import flash.display.StageAlign; | |
| import flash.display.StageScaleMode; | |
| import flash.events.Event; | |
| import flash.events.MouseEvent; | |
| import flash.geom.Point; | |
| import flash.geom.Rectangle; | |
| public class TestScaleRects extends Sprite | |
| { | |
| private var rects:Vector.<Rectangle> = new <Rectangle>[ | |
| new Rectangle(100,100,250,140), | |
| new Rectangle(0,100,250,140), | |
| new Rectangle(50,50,250,140), | |
| new Rectangle(100,150,250,140)]; | |
| private var downPoint:Point; | |
| private var currentPoint:Point = new Point; | |
| private var scaler:RectScaler = new RectScaler; | |
| private var theta:Number = 0; | |
| public function TestScaleRects() | |
| { | |
| stage.scaleMode = StageScaleMode.NO_SCALE; | |
| stage.align = StageAlign.TOP_LEFT; | |
| stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown); | |
| stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove); | |
| stage.addEventListener(MouseEvent.MOUSE_UP, onUp); | |
| addEventListener(Event.ENTER_FRAME, redrawEveryFrame); | |
| } | |
| protected function redrawEveryFrame(event:Event):void | |
| { | |
| theta += .05; | |
| var scale:Number = .5 + .25 * Math.sin(theta); | |
| graphics.clear(); | |
| if(downPoint) scaler.setPanZoom(currentPoint, scale); | |
| for(var i:int =0; i < rects.length; i++) { | |
| var drawRect:Rectangle = downPoint ? scaler.transformRect(rects[i]) : rects[i]; | |
| /* this is not how you use the flash display list. | |
| we do this to mirror the usage within a drag-loop in a Cocoa app */ | |
| graphics.lineStyle(3*scale,0); | |
| graphics.drawRect(drawRect.x, drawRect.y, drawRect.width, drawRect.height); | |
| } | |
| } | |
| protected function onUp(event:MouseEvent):void | |
| { | |
| downPoint = null; | |
| } | |
| protected function onMove(event:MouseEvent):void | |
| { | |
| currentPoint.x = event.stageX; | |
| currentPoint.y = event.stageY; | |
| } | |
| protected function onDown(event:MouseEvent):void | |
| { | |
| downPoint = new Point(event.stageX, event.stageY); | |
| scaler.startDrag(downPoint); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment