我已经设置了一个jsfiddle来说明我的情况:http://jsfiddle.net/j5o0w5qc/1/
基本上,我有三个嵌套的HTML元素:外面有一个视口div,中间有一个舞台div,里面有一个画布。舞台div 为应用于画布的 3D 变换提供透视设置。视区具有overflow: hidden;
,因此我们在视区之外看不到任何内容。它还附加了一个侦听器,侦听mousedown
。
在我正在构建的实际应用程序中,画布可能会转换为任意 3D 转换,涉及 3D 空间中的平移和旋转。我想发生的是让视口div 拦截单击,并在画布上您单击的位置绘制一个点。我正在使用视口div 拦截事件,并且我在 Chrome 中使用 offsetX 和 offsetY。这适用于Chrome,但我知道我不能在其他浏览器中依赖offsetX和offsetY,所以我想使用pageX和pageY,通过jQuery规范化,但我不确定如何做到这一点。
我目前在 jsfiddle 中得到的东西在 Chrome 中效果很好,除非您在视口中单击而不是在画布上。当您单击画布时,它会在那里绘制一个点,而不考虑画布的变换。Chrome正在做所有艰苦的工作,并通过offsetX和offsetY为我提供了我想要的东西。但是,当您在视口中单击而不是在画布上时,我想它会给我相对于视口而不是画布的 offsetX 和 offsetY 值,然后解释并在画布上画一个点。例如,如果我变换画布,然后单击视区的右上角,则画布的右上角会出现一个点,而不管该角实际出现在页面上的位置。
然而,在 Firefox 中,只要没有对画布应用变换,它就可以很好地工作,但是一旦画布被变换,突然之间,正在绘制的点被移位,我不知道如何获取我的 pageX 和 pageY 值并找出我在画布中单击的确切位置。
有人有什么出色的解决方案吗?长期以来,我一直在抨击这个问题。我很确定我需要手动计算一些 3D 变换矩阵或其他东西,我花了几个小时编写方法来返回矩阵的逆矩阵,并将矩阵乘以向量,以及各种各样的东西,但没有一个真正为我解决问题,我不确定我错过了什么。
Stackoverflow说jsfiddle链接需要代码,所以这是我的所有代码:
.HTML:
<div id="viewport">
<div id="stage">
<canvas id="myCanvas" width="300" height="300"></canvas>
</div>
</div>
<div id="stuff">
<button onclick="transformMe()">Transform</button>
<input id="blah" type="text" size="45"></input>
</div>
.CSS:
#viewport, #stage, #myCanvas {
width: 300px;
height: 300px;
position: absolute;
top: 0;
left: 0;
}
#viewport {
border: 1px solid #000;
overflow: hidden;
}
#stage {
perspective: 1000px;
transform-style: preserve-3d;
}
#myCanvas {
background-color: green;
transform-style: preserve-3d;
}
#stuff {
position: absolute;
top: 350px;
}
Javascript:
var counter = 0;
$('#viewport').mousedown(function _drawOnCanvas (e)
{
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var xpos, ypos;
if (typeof e.offsetX=='undefined')
{
xpos = e.pageX - $('#myCanvas').offset().left;
ypos = e.pageY - $('#myCanvas').offset().top;
}
else
{
xpos = e.offsetX;
ypos = e.offsetY;
}
ctx.fillRect(xpos-5, ypos-5, 10, 10);
});
function transformMe()
{
counter++;
var angle = (counter * 30) % 360;
$('#myCanvas').css('transform','perspective(1000px) rotate3d(5,6,7,' + angle + 'deg)');
$('input').val('counter: ' + counter + ', angle: ' + angle);
};
对于 Firefox,您可以使用 event.layerX 和 event.layerY。将它们视为Firefox的offsetX
和offsetY
版本。
演示:http://jsfiddle.net/dirtyd77/j5o0w5qc/3/
JAVASCRIPT:
var counter = 0;
$('#viewport').mousedown(function _drawOnCanvas (e)
{
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var xpos, ypos;
if (typeof e.offsetX=='undefined')
{
xpos = e.originalEvent.layerX;
ypos = e.originalEvent.layerY;
}
else
{
xpos = e.offsetX;
ypos = e.offsetY;
}
ctx.fillRect(xpos-5, ypos-5, 10, 10);
});
function transformMe()
{
counter++;
var angle = (counter * 30) % 360;
$('#myCanvas').css('transform','perspective(1000px) rotate3d(5,6,7,' + angle + 'deg)');
$('input').val('counter: ' + counter + ', angle: ' + angle);
};
如果您在 Kyle S 或 Dom 的 jsfiddles 的第 3 行将视口更改为 myCanvas:
$('#myCanvas').mousedown(function _drawOnCanvas (e)
当您"在视口中单击而不是在画布上"时,它不再放置点。
Firefox 似乎有一个新问题 - 如果有转换,它只能让你在一半(对角线的左下角 - 但取决于转换(。