Created
June 9, 2011 08:26
-
-
Save gasi/1016326 to your computer and use it in GitHub Desktop.
OpenZoom Multitouch IViewportController
This file contains 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
// Author: http://getsatisfaction.com/people/natxopedreira | |
// Source: http://getsatisfaction.com/openzoom/topics/implementing_gesture_controller | |
package org.openzoom.flash.viewport.controllers | |
{ | |
import flash.display.Graphics; | |
import flash.display.Sprite; | |
import flash.events.Event; | |
import flash.events.MouseEvent; | |
import flash.events.TimerEvent; | |
import flash.events.TouchEvent; | |
import flash.geom.Matrix; | |
import flash.geom.Point; | |
import flash.text.TextField; | |
import flash.ui.Multitouch; | |
import flash.utils.Dictionary; | |
import flash.utils.Timer; | |
import flash.events.Event; | |
import flash.events.MouseEvent; | |
import flash.events.TimerEvent; | |
import flash.geom.Point; | |
import flash.geom.Rectangle; | |
import flash.ui.MultitouchInputMode; | |
import org.openzoom.flash.core.openzoom_internal; | |
import org.openzoom.flash.utils.math.clamp; | |
import org.openzoom.flash.viewport.IViewportController; | |
use namespace openzoom_internal; | |
import xd.geometry.MatrixHelper; | |
[Event(name = 'change',type = 'flash.events.Event')] | |
public final class controlTotal extends ViewportControllerBase | |
implements IViewportController | |
{ | |
include "../../core/Version.as" | |
protected var _downQueue:Vector.<int > = new Vector.<int > ; | |
private var _touches:Dictionary = new Dictionary ;// id --> point map | |
private var _downMatrix:Matrix; | |
private var pts:Array = [null,null]; | |
private var numDedos:Number = 0; | |
private var firstPos:Point = new Point ; | |
private var centerPointBlob1Blob2:Point; | |
private var STATE_DRAGGING:String = "dragging"; | |
private var STATE_SCALE:String = "scale"; | |
private var STATE_NOTHING:String = "nada"; | |
private var ZOOM_THRESHOLD:Number = 1; | |
private var distanceBlob1Blob2:Number; | |
private var oldDistanceBlob1Blob2:Number = 0; | |
private var angleBlob1Blob2:Number; | |
//private var centerPointBlob1Blob2:Point; | |
private var state:String; | |
private var blob1:Object; | |
private var blob2:Object; | |
private var isDragging:Boolean; | |
private var zoomDistance:Number; | |
private var viewDragVector:Rectangle = new Rectangle() | |
private var viewportDragVector:Rectangle = new Rectangle() | |
private var distanceX:Number; | |
private var distanceY:Number; | |
private var targetX:Number; | |
private var targetY:Number; | |
private var panning:Boolean = false | |
private var clickTimer:Timer | |
private var click:Boolean = false | |
public function controlTotal() | |
{ | |
//mouseEnabled = true; | |
createClickTimer() | |
Multitouch.inputMode=MultitouchInputMode.TOUCH_POINT; | |
} | |
override protected function view_addedToStageHandler(event:Event):void | |
{ | |
view.addEventListener(TouchEvent.TOUCH_BEGIN,start); | |
} | |
private function get p0():Point | |
{ | |
var t:Point = _touches[_downQueue[0]]; | |
return t; | |
} | |
private function get p1():Point | |
{ | |
if (_downQueue.length < 2) | |
{ | |
return null; | |
} | |
var t:Point = _touches[_downQueue[1]]; | |
return t; | |
} | |
private function createClickTimer():void | |
{ | |
clickTimer = new Timer(500, 1) | |
clickTimer.addEventListener(TimerEvent.TIMER_COMPLETE, | |
clickTimer_completeHandler, | |
false, 0, true) | |
} | |
private function clickTimer_completeHandler(event:TimerEvent):void | |
{ | |
click = false | |
clickTimer.reset() | |
} | |
private function beginPanning():void | |
{ | |
// begin panning | |
panning = true | |
// add by me | |
//viewport.touchBeginTransform(); | |
/* | |
function touchBeginTransform():void | |
function touchEndTransform():void | |
*/ | |
} | |
/** | |
* @private | |
*/ | |
private function stopPanning():void | |
{ | |
panning = false | |
} | |
protected function start(e:TouchEvent):void | |
{ | |
trace("start",e); | |
if (_downQueue.length == 0) | |
{ | |
view.stage.addEventListener(TouchEvent.TOUCH_MOVE,update); | |
view.stage.addEventListener(TouchEvent.TOUCH_END,end); | |
} | |
_downQueue.push(e.touchPointID); | |
_touches[e.touchPointID] = new Point(e.stageX,e.stageY); | |
numDedos = numDedos + 1; | |
if (numDedos > 0 && _downQueue.length > 0) | |
{ | |
// hay dedakos | |
if (_downQueue.length < 2 && numDedos == 1) | |
{ | |
// | |
state = STATE_DRAGGING; | |
var _blob1pt:Point = p0; | |
blob1 = {id:e.touchPointID,px:_blob1pt.x,py:_blob1pt.y}; | |
click = true; | |
// start click timer | |
clickTimer.reset(); | |
clickTimer.start(); | |
// register where we are in the view as well as in the viewport | |
viewDragVector.topLeft = new Point(_blob1pt.x, _blob1pt.y); | |
viewportDragVector.topLeft = new Point(viewport.transformer.target.x,viewport.transformer.target.y); | |
beginPanning(); | |
} | |
else if (numDedos>1) | |
{ | |
try | |
{ | |
state = STATE_SCALE; | |
var _blob1pt1:Point = p0; | |
var _blob1pt2:Point = p1; | |
blob1 = {id:1,px:p0.x,py:p0.y}; | |
blob2 = {id:2,px:p1.x,py:p1.y}; | |
distanceBlob1Blob2 = calculateDistance(blob1.px,blob1.py,blob2.px,blob2.py); | |
} | |
catch (e:Error) | |
{ | |
trace("catch error. activeEvents.length",_downQueue.length); | |
state = STATE_DRAGGING; | |
var _blob1pt:Point = p0; | |
blob1 = {id:e.touchPointID,px:p0.x,py:p0.y}; | |
//viewportDragVector.topLeft = new Point(viewport.transformer.target.x,viewport.transformer.target.y) | |
//viewDragVector.topLeft = new Point(p0.x, p0.y) | |
} | |
} | |
} | |
firstPos.x = p0.x; | |
firstPos.y = p0.y; | |
} | |
/////////////////////// END TOUCH | |
protected function end(e:TouchEvent):void | |
{ | |
numDedos = _downQueue.length; | |
trace("end "+numDedos) | |
if (numDedos == 0) | |
{ | |
state = STATE_NOTHING; | |
isDragging = false; | |
// view.removeEventListener(TouchEvent.MOUSE_UP, localMouseUp); | |
// eventListener.removeEventListener(Event.ENTER_FRAME, handleEnterFrame); | |
stopPanning(); | |
// issue event | |
if(viewport) { | |
// viewport.touchEndTransform(); | |
} | |
} | |
if (numDedos == 1) | |
{ | |
state = STATE_DRAGGING; | |
} | |
if (numDedos < 2) | |
{ | |
oldDistanceBlob1Blob2 = 0; | |
distanceBlob1Blob2 = 0; | |
zoomDistance = 0; | |
} | |
if (numDedos > 1) | |
{ | |
state = STATE_SCALE; | |
} | |
var idx:int = _downQueue.indexOf(e.touchPointID); | |
if (idx < 0) | |
{ | |
return; | |
} | |
_downQueue.splice(idx,1); | |
if (_downQueue.length > 0) | |
{ | |
} | |
else | |
{ | |
view.stage.removeEventListener(TouchEvent.TOUCH_MOVE,update); | |
view.stage.removeEventListener(TouchEvent.TOUCH_END,end); | |
} | |
} | |
////////////////////// UPATE TOUCH | |
function update(e:TouchEvent):void | |
{ | |
//trace("update", e); | |
var idx:int = _downQueue.indexOf(e.touchPointID); | |
if (idx == -1) | |
{ | |
return; | |
} | |
_touches[e.touchPointID] = new Point(e.stageX,e.stageY); | |
firstPos = new Point() | |
if (state == STATE_DRAGGING) | |
{ | |
trace(state); | |
/* | |
if(viewportDragVector.topLeft.x ==0){ | |
viewDragVector.topLeft = new Point(p0.x, p0.y) | |
viewportDragVector.topLeft = new Point(viewport.transformer.target.x,viewport.transformer.target.y) | |
} | |
viewDragVector.bottomRight = new Point(p0.x, p0.y) | |
distanceX = viewDragVector.width / viewport.viewportWidth; | |
distanceY = viewDragVector.height / viewport.viewportHeight; | |
targetX = viewportDragVector.x - (distanceX * viewport.width); | |
targetY = viewportDragVector.y - (distanceY * viewport.height); | |
viewport.panTo(targetX,targetY,false); | |
*/ | |
var getSizeX:Number = 1360; | |
var getSizeY:Number = 768; | |
var percentPannedX:Number = (p0.x - firstPos.x)/getSizeX; | |
var percentPannedY:Number = (p0.y - firstPos.y)/getSizeY; | |
// update view drag vector | |
if (!panning){ | |
return; | |
} | |
viewDragVector.bottomRight = new Point(p0.x, p0.y); | |
var distanceX:Number; | |
var distanceY:Number; | |
var targetX:Number; | |
var targetY:Number; | |
distanceX = viewDragVector.width / viewport.viewportWidth; | |
distanceY = viewDragVector.height / viewport.viewportHeight; | |
targetX = viewportDragVector.x - (distanceX * viewport.width); | |
targetY = viewportDragVector.y - (distanceY * viewport.height); | |
// FIXME: Zoom skipping when smoothPanning = false | |
// if(viewport) | |
viewport.panTo(targetX, targetY, false) | |
try{ | |
firstPos.x = p0.x; | |
firstPos.y = p0.y; | |
}catch(e:Error){ | |
trace(firstPos); | |
} | |
} | |
if (state == STATE_SCALE) | |
{ | |
if (p0 && p1) | |
{ | |
var zoomScale:Number; | |
//find out distance of your fingers in this frame | |
var distanceBlob1Blob2Enter:Number = calculateDistance(p0.x,p0.y,p1.x,p1.y); | |
//find out where the center of your fingers is. this is the point where you want to | |
//zoom in later! | |
centerPointBlob1Blob2 = new Point(p0.x + p1.x - p0.x / 2,p0.y + p1.y - p0.y / 2); | |
//this is the really tricky part: | |
//google maps has only ~22 zoom steps. there is no continous zooming but | |
//you can only set one of those steps. that means you cannot set the next | |
//step after your fingers have moved a bit away from each other but you have | |
//to check if they have moved a certain distance (i took ZOOM_THRESHOLD for this | |
//certain distance). that means that i have to add every little bit (distanceToLastFrame) | |
//that the | |
//fingers have moved away from each other to zoomDistance in every frame. if zoomDistance | |
//is eventually bigger or smaller (zoom in or out) than ZOOM_THRESHOLD i can zoom in | |
//or out one step. | |
var distanceToLastFrame:Number = distanceBlob1Blob2Enter - distanceBlob1Blob2; | |
zoomDistance = zoomDistance + distanceToLastFrame; | |
trace(state+zoomDistance) | |
var littleZoom:Number = distanceBlob1Blob2Enter / distanceBlob1Blob2; | |
trace(littleZoom) | |
viewport.zoomBy(littleZoom); | |
/* | |
var zoomedIn:Boolean = false; | |
if (zoomDistance > 0 && zoomDistance > ZOOM_THRESHOLD) | |
{ | |
//padiante | |
while(viewport.zoom >=1){ | |
} | |
} | |
if (zoomDistance < 0 && zoomDistance < - ZOOM_THRESHOLD) | |
{ | |
//patras | |
} | |
*/ | |
distanceBlob1Blob2 = distanceBlob1Blob2Enter; | |
} | |
} | |
} | |
public function calculateDistance(blob1X:Number,blob1Y:Number,blob2X:Number,blob2Y:Number):Number | |
{ | |
var initalDistanceX:Number = blob1X - blob2X; | |
var initalDistanceY:Number = blob1Y - blob2Y; | |
var initalDistance:Number = Math.sqrt(initalDistanceX * initalDistanceX + initalDistanceY * initalDistanceY); | |
return initalDistance; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment