1

How can I expand the simple function below to determine the intended direction of movement and lock movement to that axis?

In other words, the user is intending to pan down, but since they're human they pan down but slightly to the right as well at a ratio of say 6:1 how can I infer the intended direction and lock to it?

Here is my pithy little pan function:

function onPan(e:TransformGestureEvent):void
{
    e.target.x += e.offsetX;
    e.target.y += e.offsetY;
}
4

3 に答える 3

2

While the suggestion from Shaun Husain above was close, gestures in AS3 don't provide start and end points so far as I can tell. To get around this, I took a sampling of 5 trigger points from the GESTURE_PAN event and used a variation on Levenshtein Distance calculation to determine the intended direction. Below is the working solution to this problem:

var onPanPointer:Number;
var onPanLevString:String;
var onPanLevSampleSize:Number;

onPanLevSampleSize = 5;

function onPan(e:TransformGestureEvent):void
{

    if (Math.abs(e.offsetX) > Math.abs(e.offsetY))
    {
        // Looks like we intended to move on the X axis
        if (e.offsetX > 0)
        {
            if (onPanLevString == null)
            {
                onPanLevString = "r"
            }
            else
            {
                onPanLevString = onPanLevString + "r"
            }
        }
        else
        {
            if (onPanLevString == null)
            {
                onPanLevString = "l"
            }
            else
            {
                onPanLevString = onPanLevString + "l"
            }
        }
    }
    else
    {
        // Looks like we intended to move on the Y axis
        if (e.offsetY > 0)
        {
            if (onPanLevString == null)
            {
                onPanLevString = "d"
            }
            else
            {
                onPanLevString = onPanLevString + "d"
            }
        }
        else
        {
            if (onPanLevString == null)
            {
                onPanLevString = "u"
            }
            else
            {
                onPanLevString = onPanLevString + "u"
            }
        }
    }

    if (onPanPointer < onPanLevSampleSize)
    {
        onPanPointer += 1;
    }
    else
    {
        //trace("Pointer Value has reached the desired count of: " + onPanPointer);
        //trace("The Levenshtein String is: " + onPanLevString);

        if (levenshteinDistance(onPanLevString,repeatString("u",onPanLevSampleSize)) <= ((onPanLevSampleSize/2)+1))
        {
            e.target.y += e.offsetY*onPanLevSampleSize;
            //trace("Panning Up");
        }
        else if (levenshteinDistance(onPanLevString,repeatString("d",onPanLevSampleSize)) <= ((onPanLevSampleSize/2)+1))
        {
            e.target.y += e.offsetY*onPanLevSampleSize;
            //trace("Panning Down");
        }
        else if (levenshteinDistance(onPanLevString,repeatString("l",onPanLevSampleSize)) <= ((onPanLevSampleSize/2)+1))
        {
            e.target.x += e.offsetX*onPanLevSampleSize;
            //trace("Panning Left");
        }
        else
        {
            e.target.x += e.offsetX*onPanLevSampleSize;
            //trace("Panning Right");
        }


        onPanPointer = 1;
        onPanLevString = null;
    }

    //trace("X Offset = " + e.offsetX);
    //trace("Y Offset = " + e.offsetY);
}

The levenshteinDistance function being used (below) was written by mircea16 on Snipplr and can be found here.

function levenshteinDistance(s1:String,s2:String):int
{
    var m:int=s1.length;
    var n:int=s2.length;
    var matrix:Array=new Array();
    var line:Array;
    var i:int;
    var j:int;
    for (i=0;i<=m;i++)
    {
        line=new Array();
        for (j=0;j<=n;j++)
        {
            if (i!=0)line.push(0)
            else line.push(j);
        }
        line[0]=i
        matrix.push(line);
    }
    var cost:int;
    for (i=1;i<=m;i++)
    for (j=1;j<=n;j++)
    {
        if (s1.charAt(i-1)==s2.charAt(j-1)) cost=0
        else cost=1;
        matrix[i][j]=Math.min(matrix[i-1][j]+1,matrix[i][j-1]+1,matrix[i-1][j-1]+cost);
    }
    return matrix[m][n];
}

And the last function you'll need to make the sample above work is a repeatString function I use. (This is needed to enable you to change the sample size using the onPanLevSampleSize var without having to alter anything else)

function repeatString(string:String, numTimes:uint):String
{
    var output:String = "";
    for(var i:uint = 0; i < numTimes; i++)
        output += string;
    return output;
}

The only number you need to change to adjust the sample size used is the onPanLevSampleSize, all the calculations are performed using that number as the basis.

Hope this helps someone in the future!

于 2012-06-09T17:25:17.553 に答える
1

これを試したことはありませんが、彼は次のようなことをもっと望んでいると思います。

        private var startX:Number;
        private var startY:Number;
        private function onPan(e:TransformGestureEvent):void
        {
            var currentX:Number = e.localX;
            var currentY:Number = e.localY;
            if(Math.pow(currentX-startX,2) > Math.pow(currentY - startY,2))
            {
                e.target.x = currentX;
            }
            else
            {
                e.target.y = currentY;
            }
        }

startXとstartYを設定する部分は省略していますが、TransformGestureEventはまだ使用していませんが、startX/startYをマークできる最初のダウンイベントがあると思います。基本的に、Xの変化がYの変化よりも大きいかどうかを確認するために言っているだけです。そうでない場合は、Xを調整し、そうでない場合はYを調整します。つまり、スティッキーパンのようなものです。

于 2012-06-08T03:56:42.840 に答える
0

Odd question but I think I understand what you are looking for.

function onPan(e:TransformGestureEvent):void
{
    e.target.x += e.offsetX + (e.offsetY/6); // use ratio from offsetY
    e.target.y += e.offsetY;
}
于 2012-06-08T03:45:04.600 に答える