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

时间:2014-09-27 00:43:50

标签: javascript css canvas css-transforms

我已经设置了一个说明我情况的小说:http://jsfiddle.net/j5o0w5qc/1/

基本上,我有三个嵌套的HTML元素:外部的视口div,中间的舞台div和内部的画布。 stage div为应用于画布的3d变换提供透视设置。视口有overflow: hidden;,因此我们无法在视口外看到任何内容。它还附加了一个监听器,监听mousedown

在我构建的实际应用中,画布可能会转换为任意三维变换,涉及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);
};

2 个答案:

答案 0 :(得分:2)

对于Firefox,您可以使用event.layerXevent.layerY。将它们视为Firefox的offsetX和&amp; offsetY

DEMO: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);
};

答案 1 :(得分:0)

如果您将 Kyle S Dom&#39>的第3行中的视口更改为 myCanvas > jsfiddles:

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

当你在视口中点击不在画布上时,它不再放置一个点。&#34;

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