Skip to content

Instantly share code, notes, and snippets.

@gasi
Created June 9, 2011 08:26
Show Gist options
  • Save gasi/1016326 to your computer and use it in GitHub Desktop.
Save gasi/1016326 to your computer and use it in GitHub Desktop.
OpenZoom Multitouch IViewportController
// 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