私は 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
イベントから悪い座標を取得しているように見える理由がわかりません。この問題を回避するにはどうすればよいですか? 正しい位置を取得するために使用できる別のソースはありますか? イベントの順序を微調整?
ブラウザ内デバッグを実行したい場合は、完全なコードのオンライン デモへのリンクを次に示します。
そして、助けてくれてありがとう。