如何通过javascript确定触摸事件(或鼠标事件)中真正的x坐标?

问题描述:

我一直在研究触摸事件,并且有一些代码工作得很好,直到画布没有从左上角开始。只要我在它之前添加任何东西,报告的事件就会被画布的位置所抵消。如何通过javascript确定触摸事件(或鼠标事件)中真正的x坐标?

我通过在触摸所在的位置绘制一个圆来确定此点。圆圈总是偏移画布左上角的偏移量。

查看触摸开始的事件,我可以看到有一个pageY可用(在chrome中,使用usb调试)。但是,当我谷歌,似乎它不是标准的一部分,似乎有一些争论,它可能会贬值(虽然我找不到一种方式或其他)。

所以我的问题是什么是最好的跨浏览器方法来处理这个(主要问题是Safari和铬,即webkit,Firefox是一个不错的)?

鼠标事件发生同样的问题,为此我创建了JSFiddle of the problem。不过,我不确定是否有相同的属性可用于鼠标事件和触摸事件。

我应该注意到,我知道我可以硬编码的偏移量和问题解决,但我正在寻找一种解决方案,使用手头的信息,而不需要任何硬连线特定于我的HTML代码。

要重新创建的jsfiddle的HTML,CSS和Javascript如下:

<div class="title"></div> 
<div class="container"> 
    <canvas id="myCanvas"></canvas> 
</div> 

CSS:

body { 
    background-color: #ff0000; 
    margin: 0px; 
} 

canvas { 
    display:block; 
    position:absolute; 
    width:100%; 
    height:100%; 
    background-color:#000; 
} 

.title { 
    position:absolute; 
    top:0px; 
    left:0px; 
    width: 100%; 
    height: 40px; 
    background-color: #888; 
} 

.container { 
    width:auto; 
    text-align:center; 
    background-color:#777; 
    width:100%; 
    position:absolute; 
    top:40px; 
    left:0px; 
    bottom:0px; 
} 

的Javascript:

var onMouseDown = function(e) { 
    draw(document.getElementById('myCanvas').getContext('2d'), e.clientX, e.clientY); 
} 

$(function() { 
    document.getElementById('myCanvas').addEventListener('mousedown', onMouseDown, false); 
}); 


function draw(ctx, x, y) { 
ctx.canvas.width = ctx.canvas.offsetWidth; 
ctx.canvas.height = ctx.canvas.offsetHeight;  

    var radius = 50; 
    var lineWidth = 15; 
    var r = 255; 
    var g = 75; 
    var b = 75; 
    var a75 = 0.05; 

    var adj = Math.abs(lineWidth/2); 

    rad = radius + adj; 

    var stop1 = (rad - lineWidth)/rad; 
    var stop2 = 0; 
    var stop3 = stop1 + (1 - stop1)/2; 
    var stop4 = 0; 
    var stop5 = 1; 

    stop2 = stop3 - (stop3 - stop1)/2; 
    stop4 = stop3 + (stop5 - stop3)/2; 

    var radgrad = ctx.createRadialGradient(x, y, 0, x, y, rad); 

    radgrad.addColorStop(stop1, 'rgba(' + r + ',' + g + ',' + b + ', 0)'); 
    radgrad.addColorStop(stop2, 'rgba(' + r + ',' + g + ',' + b + ', .4)'); 
    radgrad.addColorStop(stop3, 'rgba(' + r + ',' + g + ',' + b + ', 1)'); 
    radgrad.addColorStop(stop4, 'rgba(' + r + ',' + g + ',' + b + ', .4)'); 
    radgrad.addColorStop(stop5, 'rgba(' + r + ',' + g + ',' + b + ', 0)'); 

    ctx.fillStyle = radgrad; 
    ctx.arc(x, y, rad, 0, 2 * Math.PI, true); 
    ctx.fill(); 
} 

这应该工作:http://jsfiddle.net/DG4fb/3/

您画布的顶部和左侧不是clientX == 0; clientY == 0;,因此您需要计算偏移量。你的画布的左上角在哪里?这是它的offsetLeftoffsetTop加上它的offsetParent的价值和它的offsetParent.offsetParent的价值,等等。这就是recursiveOffsetLeftAndTop函数为您处理的。

+0

谢谢猫陈,很好地工作。有趣的是,鼠标下的事件有offsetX和offsetY,但由于某些奇怪的原因,它们不适用于触摸事件。非常沮丧。 顺便说一句,你的解决方案存在问题,它没有考虑元素何时离开可见屏幕。例如,在传送带中有左右两个不可见的div。在我的例子中,它把X搞砸了,但说实话,我可以忽略它,因为只有Y让我感到悲伤。 :-) – Metalskin

+0

我的代码中有一个小错误。它不计算页面滚动。请在这里查看正确的答案:http://www.quirksmode.org/js/events_properties.html#position –

如果用户pageX属性和PageY代替ClientX和ClientY,它在我的情况下完美地工作......

 var offsets = recursiveOffsetLeftAndTop(canvas); 
     var x = evt.targetTouches[0].pageX - offsets.offsetLeft; 
     var y = evt.targetTouches[0].pageY - offsets.offsetTop; 

谢谢你的解决方案。