1

私は HTML5 Canvas プロジェクトを開発しています。モバイル デバイスのマルチタッチ サポートを追加しているときに、iOS 7.1 の Mobile Safari で問題が発生したようです。

ユーザーが私のアプリを操作する主な方法は、クリックしてドラッグすることです。デスクトップでは、適切なマウス イベント リスナーをキャンバスに追加します...

c.addEventListener('mousedown', mouseDown, false);
c.addEventListener('mousemove', mouseMoved, false);
c.addEventListener('mouseup', mouseUp, false);

... これらのイベント ハンドラーにマウスの位置を計算させ、イベントの X と Y の位置だけを受け取る、より一般的な関数を呼び出します...

function mouseDown(evt) 
{
    var pos = getMousePos(evt);
    inputDown(pos);
}

function mouseUp(evt) 
{
    var pos = getMousePos(evt);
    inputUp(pos);
}

function mouseMoved(evt) 
{
    var pos = getMousePos(evt);
    inputMoved(pos);
}

function getMousePos(evt) 
{
    var rect = c.getBoundingClientRect();
    return { 'x': evt.clientX - rect.left, 'y': evt.clientY - rect.top }
}

...そして、すべてがうまく機能します。このレベルの抽象化を設計して、他の入力方法に簡単に拡張できるようにしました。そこで、Touch API を使用してこれを拡張しようとしました。最初に、ハンドラーをキャンバスのマウス ハンドラーのすぐ隣に追加します...

c.addEventListener("touchstart", touchDown, false);
c.addEventListener("touchmove", touchMoved, false);
c.addEventListener("touchend", touchUp, false);
c.addEventListener("touchcancel", touchUp, false);

...次に、薄いイベント ハンドラーを追加して、タッチ イベントを抽象化します ...

function touchDown(evt) 
{
    evt.preventDefault();

    // Ignore touches after the first.
    if (activeTouch != null)
        return;

    if (evt.changedTouches.length > 0)
    {
        activeTouch = evt.changedTouches[0].identifier;
        var pos = getTouchPos(evt);
        inputDown(pos);
    }
}

function touchUp(evt) 
{
    var pos = getTouchPos(evt);
    activeTouch = null;
    inputUp(pos);
}

function touchMoved(evt) 
{
    var pos = getTouchPos(evt);
    inputMoved(pos);
}

function getTouchPos(evt) 
{
    var canX = 0;
    var canY = 0;

    for( var i = 0; i < evt.touches.length; i++ )
    {
        if (evt.touches[i].identifier == activeTouch)
        {
            canX = evt.touches[i].pageX - c.offsetLeft;
            canY = evt.touches[i].pageY - c.offsetTop;
            break;
        }
    }

    return { 'x': canX, 'y': canY }
}

...そして、ここで問題が発生します。物事が少し毛むくじゃらになっていることがわかりますが、非効率性はさておき、私はすべてを正しく使用していると思います。問題は、getTouchPos(evt)上のタッチの正しい X、Y 位置を取得できないように見えることtouchstartです。最初のタッチで、0,0 の位置を取得します。指をドラッグするtouchmoveと、複数回発火し、報告された X、Y 座標は問題ないようです。指をtouchend離すと発火し、正しい位置も取得します。ただし、もう一度タッチするとtouchstart発火し、タッチしている場所ではなく、最後のタッチが終了した場所の X、Y 座標を取得します。

デバッガーを使ってみたところ、確かに古い/初期化されていない値が、イベント データで取得した Touch オブジェクトに含まれています。私は明らかに間違ったことをしていますか?touchstartイベントから悪い座標を取得しているように見える理由がわかりません。この問題を回避するにはどうすればよいですか? 正しい位置を取得するために使用できる別のソースはありますか? イベントの順序を微調整?

ブラウザ内デバッグを実行したい場合は、完全なコードのオンライン デモへのリンクを次に示します。

そして、助けてくれてありがとう。

4

1 に答える 1

3

明らかかどうかはわかりませんが、デバッグするのは楽しい問題でした。したがって、基本的に、混乱はこの男に帰着します。

function mouseMoved(evt) {
    var pos = getMousePos(evt);
    inputMoved(pos);
}

マウス イベントの場合は、mousemove.

c.addEventListener('mousemove', mouseMoved, false);

どの呼び出し

function mouseMoved(evt) {
    var pos = getMousePos(evt);
    inputMoved(pos);
}

したがって、マウスを動かすと、posX/posY値が継続的に更新されます。(うまくいけば、今問題が表示されます:)

TouchEvents の場合、ユーザーがタッチしたとき (動かないとき) と のみをトリガーtouchstarttouchendます。ユーザーがドラッグするまで、それtouchmoveが呼び出され、それが関数touchMovedを呼び出します (呼び出しinputMoved- 値を更新しますposX/posY)。

ページでこの問題に対処する最も簡単な方法はinputMoved、両方touchstartを呼び出しtouchmoveMassHaverインスタンスを最新の状態にすることです。

于 2014-05-14T08:40:27.060 に答える