触摸事件“touchstart”在Mobile Safari上返回不正确的位置。解决方法? [英] Touch Events "touchstart" returns incorrect position on Mobile Safari. Workarounds?

查看:430
本文介绍了触摸事件“touchstart”在Mobile Safari上返回不正确的位置。解决方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个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

//在第一个之后忽略触摸。
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}
}
pre>

...这是我遇到麻烦的地方!你可以看到事情有点毛,但低效率在一边,我想我使用一切正确。问题是 getTouchPos(evt)似乎无法获得触摸 touchstart 的正确X,Y位置。在我第一次触摸,我得到一个位置0,0。如果我拖动手指, touchmove 多次触发,报告的X,Y坐标看起来很好。如果我抬起手指, touchend 发射,我也得到正确的位置。但是,如果我再次触摸, touchstart 触发,而不是我触摸的地方,我得到我的最后一次触摸结束的X,Y坐标!



我使用了一个调试器,并且确实足够的,过期/未初始化的值就在我在事件数据中获得的Touch对象。我做明显错误吗?我不明白为什么我似乎从 touchstart 事件中得到不好的坐标。我该如何解决这个问题?有没有另一个来源,我可以用来获得正确的位置?对事件顺序的细微调整?



如果您想要运行一些在浏览器中的调试,请点击此链接指向完整代码的在线演示



并提前感谢任何帮助。

解决方案

我不知道是否明显,但这是一个有趣的问题,调试。所以基本上,混乱归结为这个家伙:

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

对于鼠标事件,一切都很好, code> mousemove 。

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

哪些电话

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

因此,当你移动鼠标时, posX / posY 值将不断更新。 (希望你看到的问题现在:)



对于TouchEvents,当用户触摸(但不移动),你只触发 touchstart touchend 。直到用户拖动, touchmove 被调用,这又调用函数 touchMoved (调用 inputMoved - 更新您的 posX / posY 值)。



在页面上解决此问题的最简单方法是在 touchstart 和<$ c中调用 inputMoved $ c> touchmove ,因此您的 MassHaver 实例具有最新状态。


I am developing an HTML5 Canvas project and while adding multitouch support for mobile devices, I seem to have run into an issue on Mobile Safari in iOS 7.1.

The main way that users interact with my app is by clicking and dragging. On the desktop, I add the appropriate mouse event listeners to my canvas...

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

... have these event handlers calculate mouse position and call out to a more generic function that just accepts the X and Y position of the event...

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 }
}

... and everything works great. I designed this level of abstraction to allow for easy expansion to other input methods. So now I attempt to use the Touch API to expand this. First I add my handlers to the canvas right next to the mouse handlers...

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

... then add my thin event handlers to abstract away the touch events ...

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 }
}

... and this is where I run into trouble! You can see things get a little hairy but inefficiencies aside, I think I am using everything correctly. The problem is that getTouchPos(evt) seems unable to get the correct X, Y position of a touch on touchstart. On my first touch, I get a position of 0,0. If I drag my finger, the touchmove fires multiple times and the X,Y coordinates reported seem fine. If I lift my finger, touchend fires and I also get a correct location. However, if I touch again, touchstart fires and rather than where I am touching, I get the X,Y coordinates of where my last touch ended!

I've gone in with a debugger and sure enough, the stale/uninitialized values are right there in the Touch objects I get in the event data. Am I doing anything obviously wrong? I don't understand why I seem to be getting bad coordinates from touchstart events. What can I do to work around this issue? Is there another source I can use to get the correct position? A subtle tweak to event order?

Here's a link to an online demo of the full code if you'd like to run some in-browser debug.

And thanks in advance for any help.

解决方案

I'm not sure if it's obvious, but it was a fun issue to debug. So basically, the confusion comes down to this guy:

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

For your mouse events, everything works great, because you're bound to mousemove.

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

Which calls

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

So, as you move your mouse around, your posX/posY values are updated continuously. (Hopefully you see the issue now :)

For TouchEvents, when a user touches (but does not move), you only trigger touchstart and touchend. It isn't until a user drags, that touchmove gets called, which in turn calls the function touchMoved (that calls inputMoved - which updates your posX/posY values).

The easiest way to address this issue on your page is just to call inputMoved in both touchstart and touchmove so your MassHaver instance has the latest state.

这篇关于触摸事件“touchstart”在Mobile Safari上返回不正确的位置。解决方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆