fljot / Gestouch

Gestouch: multitouch gesture recognition library for Flash (ActionScript) development.
MIT License
355 stars 85 forks source link

cancel PanGesture when ZoomGeture begins... #45

Open smorales opened 11 years ago

smorales commented 11 years ago

Hi, at first i wanted to express here my gratitude for this great framework, it's really a fantastic framework!

But i'm having some troubles to cancel an actual PanGesture when the user starts a zoom gesture.

So i have this here:

zoomGesture = new ZoomGesture( obj );
zoomGesture.addEventListener(GestureEvent.GESTURE_CHANGED, onZoom);

panGesture = new PanGesture( obj );
panGesture.addEventListener(GestureEvent.GESTURE_CHANGED, onPanGesture);

private function onZoom(event : GestureEvent) : void
{
    // possible active panGesture should be cancelled here
}

private function onPanGesture(event : GestureEvent) : void
{
    // some pan code...
}

I tried to use panGesture.requireGestureToFail(zoomGesture); without success and i also tried to override canBePreventedByGesture and canPreventGesture, but nothing worked for me.

Has somebody any ideia how to accomplish this?

Thank you very much,

Solano

fljot commented 11 years ago
zoomGesture = new ZoomGesture( obj );
zoomGesture.addEventListener(GestureEvent.GESTURE_CHANGED, onZoom);

panGesture = new PanGesture( obj );
panGesture.addEventListener(GestureEvent.GESTURE_CHANGED, onPanGesture);

private function onZoom(event : GestureEvent) : void
{
    // possible active panGesture should be cancelled here

    if (event.newState == GestureState.BEGAN)
        panGesture.reset();
}

private function onPanGesture(event : GestureEvent) : void
{
    // some pan code...
}

+ you need to allow pan and zoom to be recognized simultaneously:

panGesture.gesturesShouldRecognizeSimultaneouslyCallback = gesturesShouldRecognizeSimultaneouslyCallback;
zoomGesture.gesturesShouldRecognizeSimultaneouslyCallback = gesturesShouldRecognizeSimultaneouslyCallback;

private function gesturesShouldRecognizeSimultaneouslyCallback(gesture:Gesture, otherGesture:Gesture):Boolean
{
    if ((gesture == panGesture && otherGesture == zoomGesture) ||
        (gesture == zoomGesture && otherGesture == panGesture))
        return true;// or if (gesture.target == otherGesture.target) return true; if you like it more

    // Default behavior
    return false;
}
smorales commented 11 years ago

Thank you very much for your fast reply. I tried your solution but it still doesn't work. Maybe because i'm using the develop branch? I switched to the develop version, because with the master branch i didn't get always the gestures recognized.

Thanks, Solano

fljot commented 11 years ago

Develop is okay. What "doesn't work" exactly?

upd: added if (event.newState ... ) check

smorales commented 11 years ago

Hi, i think that i didn't correctly express my intention. When i pan the stage with one finger and then add a second finder i wanted to start the zoomGesture and cancel the panGesture. But it doesn't happen and the method onZoom isn't neither called. Maybe it's because i'm developing for a interactive whiteboard...

Solano

smorales commented 11 years ago

Ok, just tested the project on a multitouch screen and the behaviour is the same.

fljot commented 11 years ago

Here's what was happening originally: once you put 1st finger both gestures get it, but as soon as you move your finger Pan becomes recognized and, normally, aborts Zoom(which is in recognition process at that moment). So when later you put your 2nd finger — Zoom will receive the touch, but that will be the only single touch it will track because previously it was reset (because of abortion). So no zoom could happen with the only one touch being analysed.

The things I wrote should do the trick, I can't imagine why it doesn't work for you. Does zoom work if you comment out all panning stuff?

And also why would anyone cancel panning once rotation begins?

smorales commented 11 years ago

I got it working! I changed so many times the code and tried so many combinations that i lastly forgot to override canBePreventedByGesture. This did the trick. Using canPreventGesture, canBePreventedByGesture together with gesturesShouldRecognizeSimultaneouslyCallback and panGesture.reset() works great.

Thank you very much!

Solano

fljot commented 11 years ago

No-no! You shouldn't use canPreventGesture and canBePreventedByGesture here. Those methods are only for certain gesture types (in other words they must be overridden in Gesture subclasses, for instance it's done in TapGesture because instance of single-tap should not abort another instance of double-tap gesture). In your case just gesturesShouldRecognizeSimultaneouslyCallback should really be enough.

Hitek55 commented 11 years ago

smorales, show how you solved the problem?

smorales commented 11 years ago

Hi, in fact i had to use the callbacks and override some methods in the gesture classes. Doing it alone how fljot recommended didn't work for me. And because tomorrow i have to present the software on a fair i didn't have more time to investigate the real problem. However it works now. The software will run on digital whiteboards and that's the reason why i had to change also the slop values. The default ones didn't work well on touch TVs and digital whiteboards.

zoomGesture = new StageZoomGesture( Away3DView.instance );
zoomGesture.lockAspectRatio = true;
zoomGesture.slop = 15;
zoomGesture.gestureShouldBeginCallback = zoomGestureShouldBegin;
zoomGesture.gesturesShouldRecognizeSimultaneouslyCallback = gesturesShouldRecognizeSimultaneously;
zoomGesture.addEventListener(GestureEvent.GESTURE_BEGAN, onZoomBegan);
panGesture = new StagePanGesture( Away3DView.instance );
panGesture.slop = 6;
panGesture.gesturesShouldRecognizeSimultaneouslyCallback = gesturesShouldRecognizeSimultaneously;
private function gesturesShouldRecognizeSimultaneously(gesture:Gesture, otherGesture:Gesture) : Boolean
{
    var value : Boolean = false;

    if (    (gesture == panGesture && otherGesture == zoomGesture) 
         || (gesture == zoomGesture && otherGesture == panGesture))
                value = true; 
    return value;
}
private function onZoomBegan(event : GestureEvent) : void
{
    panGesture.reset();
}
public class StageZoomGesture extends ZoomGesture
{
    public function StageZoomGesture(target : Object = null)
    {
        super(target);
    }

    override gestouch_internal function canBePreventedByGesture(preventingGesture : Gesture) : Boolean
    {
        return false;
    }
}
public class StagePanGesture extends PanGesture
{
    public function StagePanGesture(target : Object = null)
    {
        super(target);
    }

    override gestouch_internal function canBePreventedByGesture(preventingGesture : Gesture) : Boolean
    {
        return true;
    }   

    override gestouch_internal function canPreventGesture(preventedGesture : Gesture) : Boolean
    {
        var can : Boolean = super.gestouch_internal::canPreventGesture(preventedGesture);
        if(preventedGesture is StageZoomGesture) can = false;

        return can;
    }   
}
tomglanville commented 10 years ago

Late reply but couldn't you use TransformGesture instead of combining other gestures together? I'm not sure your exact requirements but if you need to pan and zoom the same object then all you need to do is comment out the rotation part of the transform gesture handler.

TransformGesture example here: https://github.com/fljot/GestouchExamples/blob/master/src/org/gestouch/examples/views/TransformGestureView.mxml

smorales commented 10 years ago

Thank you for your suggestion, but unfortunately it's not possible. I have a 3D environment and I'm using Gestouch to control the camera. A single touch slide rotates the world, two touches slide pans the camera and the zoom is done with approximating the touches. The problem is that the software runs on extremely sensible touch devices (digital whiteboards) and when I pan with two fingers and I change unintentionally the distance of the two fingers, Gestouch dispatches the zoom event which shouldn't happen. I could change the slope, but then it don't work more on the iPad well and vice versa.