定位鼠标相对于变换平面的位置



我已经设置了一个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的offsetXoffsetY版本。

演示: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 SDom 的 jsfiddles 的第 3 行将视口更改为 myCanvas

$('#myCanvas').mousedown(function _drawOnCanvas (e)

当您"在视口中单击而不是在画布上"时,它不再放置点。

Firefox 似乎有一个新问题 - 如果有转换,它只能让你在一半(对角线的左下角 - 但取决于转换(。

最新更新