package { import flash.display.Sprite; import flash.events.*; import flash.display.MovieClip; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.utils.getTimer; import flash.ui.Multitouch; import flash.ui.MultitouchInputMode; public dynamic class RotatableScalable extends Sprite { public var blobs:Vector.; // blobs we are currently interacting with public var state:String; private var curScale:Number; private var curAngle:Number; private var curPosition:Point = new Point(0,0); private var GRAD_PI:Number = 180.0 / 3.14159; private var basePos1:Point = new Point(0,0); private var basePos2:Point = new Point(0, 0); private var _unlock:Boolean = false; public var blob1:Object; public var blob2:Object; public var bringToFront:Boolean = true; public var noScale:Boolean = false; public var noRotate:Boolean = false; public var noMove:Boolean = false; public var mouseSelection:Boolean = false; public var dX:Number; public var dY:Number; public var dAng:Number; public var dcoef:Number = 0.5; private var curPos:Point = new Point(0, 0); private var lastPos:Point = new Point(0, 0); private var velocity:Point = new Point(0, 0); private var decay:Number = 0.9; private var blobObject:Object = new Object(); private var _rp:Point = new Point(0,0); private var ts:Boolean = Multitouch.supportsTouchEvents; public function RotatableScalable() { state = "none"; blobs = new Vector.(); dX = 0; dY = 0; dAng = 0; } public function setRegistration(X:Number=0, Y:Number=0):void { _rp = new Point(X, Y); } public function setProperty2(prop:String, n:Number):void { var a:Point = new Point(); var b:Point = new Point(); a = this.localToGlobal(_rp); b = this.localToGlobal(_rp); this[prop] = n; var offset:Point = new Point(this.x - a.x, this.y - a.y); this.x -= offset.x; this.y -= offset.y; } public function get x2():Number { var p:Point = this.parent.globalToLocal(this.localToGlobal(_rp)); return p.x; } public function set x2(val:Number):void { var p:Point = this.parent.globalToLocal(this.localToGlobal(_rp)); this.x += val - p.x; } public function get y2():Number { var p:Point = this.parent.globalToLocal(this.localToGlobal(_rp)); return p.y; } public function set y2(value:Number):void { var p:Point = this.parent.globalToLocal(this.localToGlobal(_rp)); this.y += value - p.y; } private function addBlob(id:Number, origX:Number, origY:Number):void { for (var i:int = 0; i < blobs.length; i++) { if (blobs[i].id == id) return; } blobs.push( {id: id, origX: origX, origY: origY, myOrigX: x, myOrigY:y} ); switch (blobs.length) { case 1 : state = "dragging"; curPos.x = x; curPos.y = y; lastPos.x = x; lastPos.y = y; velocity.x = 0; velocity.y = 0; curScale = this.scaleX; curAngle = this.rotation; curPosition.x = x; curPosition.y = y; blob1 = blobs[0]; break; case 2 : state = "rotatescale"; curScale = this.scaleX; curAngle = this.rotation; curPosition.x = x; curPosition.y = y; velocity.x = 0; velocity.y = 0; blob1 = blobs[0]; blob2 = blobs[1]; var tuioobj1:Object = blobObject[blob1.id]; var tuioobj2:Object = blobObject[blob2.id]; var midPoint:Point = Point.interpolate(this.globalToLocal(new Point(tuioobj1.x, tuioobj1.y)),this.globalToLocal(new Point(tuioobj2.x, tuioobj2.y)),0.5); setRegistration(midPoint.x, midPoint.y); if(tuioobj1) { var curPt1:Point = parent.globalToLocal(new Point(tuioobj1.x, tuioobj1.y)); blob1.origX = curPt1.x; blob1.origY = curPt1.y; } break; default : state = "dragging"; return; } } private function removeBlob(id:Number):void { for(var i=0; i= 2) { state = "rotatescale"; curScale = this.scaleX; curAngle = this.rotation; curPosition.x = x; curPosition.y = y; blob1 = blobs[0]; blob2 = blobs[1]; tuioobj1 = blobObject[blob1.id]; if(tuioobj1) { curPt1 = parent.globalToLocal(new Point(tuioobj1.x, tuioobj1.y)); blob1.origX = curPt1.x; blob1.origY = curPt1.y; } } return; } } } private function downEvent(e:TouchEvent):void { if(e.stageX == 0 && e.stageY == 0) return; var curPt:Point = parent.globalToLocal(new Point(e.stageX, e.stageY)); addBlob(e.touchPointID, curPt.x, curPt.y); blobObject[e.touchPointID] = {x:e.stageX,y:e.stageY}; e.stopPropagation(); } private function upEvent(e:TouchEvent):void { removeBlob(e.touchPointID); blobObject[e.touchPointID] = null; e.stopPropagation(); } private function moveHandler(e:TouchEvent):void { e.stopPropagation(); blobObject[e.touchPointID] = {x:e.stageX,y:e.stageY}; } private function mouseDownEvent(e:MouseEvent):void { if(_unlock) { this.startDrag(); e.stopPropagation(); } } private function mouseUpEvent(e:MouseEvent):void { if(_unlock) { this.stopDrag(); e.stopPropagation(); } } private function getAngleTrig(X:Number, Y:Number): Number { if (X == 0.0) { if(Y < 0.0) return 270; else return 90; } else if (Y == 0) { if(X < 0) return 180; else return 0; } if ( Y > 0.0) if (X > 0.0) return Math.atan(Y/X) * GRAD_PI; else return 180.0-Math.atan(Y/-X) * GRAD_PI; else if (X > 0.0) return 360.0-Math.atan(-Y/X) * GRAD_PI; else return 180.0+Math.atan(-Y/-X) * GRAD_PI; } public function released(dx:Number, dy:Number, dang:Number) { } public function set unlock(b:Boolean):void { _unlock = b; blobs = new Vector.(); blobObject = new Object(); if (ts) { if (b) { this.addEventListener(TouchEvent.TOUCH_MOVE, moveHandler); this.addEventListener(TouchEvent.TOUCH_BEGIN, downEvent); this.addEventListener(TouchEvent.TOUCH_END, upEvent); this.addEventListener(TouchEvent.TOUCH_OUT, upEvent); this.addEventListener(Event.ENTER_FRAME, loop); } else { this.removeEventListener(TouchEvent.TOUCH_MOVE, moveHandler); this.removeEventListener(TouchEvent.TOUCH_BEGIN, downEvent); this.removeEventListener(TouchEvent.TOUCH_END, upEvent); this.removeEventListener(TouchEvent.TOUCH_OUT, upEvent); this.removeEventListener(Event.ENTER_FRAME, loop); } } else { if (b) { this.addEventListener(MouseEvent.MOUSE_DOWN, this.mouseDownEvent); this.addEventListener(MouseEvent.MOUSE_UP, this.mouseUpEvent); } else { this.removeEventListener(MouseEvent.MOUSE_DOWN, this.mouseDownEvent); this.removeEventListener(MouseEvent.MOUSE_UP, this.mouseUpEvent); } } } public function get unlock():Boolean { return _unlock; } private function loop(e:Event):void { if(state == "dragging") { var tuioobj:Object = blobObject[blob1.id]; if(!tuioobj) { removeBlob(blob1.id); return; } var curPt:Point = parent.globalToLocal(new Point(tuioobj.x, tuioobj.y)); var oldX:Number, oldY:Number; oldX = x; oldY = y; lastPos.x = curPos.x; lastPos.y = curPos.y; curPos.x = x; curPos.y = y; velocity.x = curPos.x - lastPos.x; velocity.y = curPos.y - lastPos.y; if(!noMove) { x = curPosition.x + (curPt.x - (blob1.origX )); y = curPosition.y + (curPt.y - (blob1.origY )); } dX *= dcoef; dY *= dcoef; dAng *= dcoef; dX += x - oldX; dY += y - oldY; } else if(state == "rotatescale") { var tuioobj1:Object = blobObject[blob1.id]; // if not found, then it must have died.. if(!tuioobj1) { removeBlob(blob1.id); return; } velocity.x = 0; velocity.y = 0; var curPt1:Point = parent.globalToLocal(new Point(tuioobj1.x, tuioobj1.y)); var tuioobj2 = blobObject[blob2.id]; // if not found, then it must have died.. if(!tuioobj2) { removeBlob(blob2.id); return; } var midPoint:Point = Point.interpolate( this.globalToLocal(new Point(tuioobj1.x, tuioobj1.y)), this.globalToLocal(new Point(tuioobj2.x, tuioobj2.y)), 0.5); setRegistration(midPoint.x,midPoint.y); var curPt2:Point = parent.globalToLocal(new Point(tuioobj2.x, tuioobj2.y)); var curCenter:Point = Point.interpolate(curPt1, curPt2, 0.5); var origPt1:Point = new Point(blob1.origX, blob1.origY); var origPt2:Point = new Point(blob2.origX, blob2.origY); var centerOrig:Point = Point.interpolate(origPt1, origPt2, 0.5); var offs:Point = curCenter.subtract(centerOrig); var len1:Number = Point.distance(origPt1, origPt2); var len2:Number = Point.distance(curPt1, curPt2); var len3:Number = Point.distance(origPt1, new Point(0, 0)); var newscale:Number = curScale * len2 / len1; if(!noScale) { setProperty2('scaleX', newscale); setProperty2('scaleY', newscale); } var origLine:Point = origPt1; origLine = origLine.subtract(origPt2); var ang1:Number = getAngleTrig(origLine.x, origLine.y); var curLine:Point = curPt1; curLine = curLine.subtract(curPt2); var ang2:int = getAngleTrig(curLine.x, curLine.y); var oldAngle:int = this.rotation; if(!noRotate) { setProperty2("rotation", curAngle + (ang2 - ang1)); } oldX = x; oldY = y; if(!noMove) { x2 = curCenter.x; y2 = curCenter.y; } dX *= dcoef; dY *= dcoef; dAng *= dcoef; dX += x - oldX; dY += y - oldY; dAng += this.rotation - oldAngle; } else if (state == "none") { x += velocity.x; y += velocity.y; velocity.x *= decay; velocity.y *= decay; if (Math.abs(velocity.x) < 0.03) { velocity.x = 0; } if (Math.abs(velocity.y) < 0.03) { velocity.y = 0; } } else { if(dX != 0 || dY != 0) { this.released(dX, dY, dAng); dX = 0; dY = 0; dAng = 0; } } } } }