HTML Canvas,缩放后的鼠标位置和翻译

时间:2016-01-04 18:08:33

标签: canvas html5-canvas

我在画布中实现了一个缩放功能,就像这样:Zoom in on a point (using scale and translate)

现在我需要计算鼠标相对于画布的位置,我首先尝试这样:

var rect = this._canvas.getBoundingClientRect();
var x = ((event.clientX  - rect.left) / (rect.right - rect.left) * this._canvas.width);
var y = ((event.clientY  - rect.top) / (rect.bottom  - rect.top) * this._canvas.height);

这一点非常有效,直到我缩放......我试着这样做:

var x = ((event.clientX  - rect.left) / (rect.right - rect.left) * this._canvas.width) - this._canvas.offsetLeft ;
var y = ((event.clientY  - rect.top) / (rect.bottom  - rect.top) * this._canvas.height) - offset.top this._canvas.offSetTop ;

任何提示?或者我应该更好地使用JS库与canvas元素进行交互?如果是这样,你有经验吗?

3 个答案:

答案 0 :(得分:6)

反向矩阵

这个答案也包括旋转,因为刻度是矩阵中旋转的一部分,你不能真正排除其中一个。但你可以忽略旋转(将其设置为零),只需设置比例和平移,它就可以实现你想要的效果。

逆变换。它基本上与标准2D变换相反。它需要您跟踪转换,以便您可以创建逆转换,如果您希望使用ctx.rotationctx.scalectx.translate或{{{}},这可能会在复杂转换中出现问题1}}。由于您的要求很简单,我创建了一个简单的函数来进行最小化转换。

以下将变换矩阵和逆变换创建为两个名为matrix和invMatrix的数组。参数是平移x,y(在画布坐标中),缩放和旋转。

ctx.transform

使用功能

使用该功能很简单。只需使用所需的位置,比例和旋转值进行调用。

应用反向

要从像素空间(屏幕x,y)获取世界坐标(变换后的坐标),您需要应用逆变换

var matrix = [1,0,0,1,0,0];
var invMatrix = [1,0,0,1];
function createMatrix(x, y, scale, rotate){
    var m = matrix; // just to make it easier to type and read
    var im = invMatrix; // just to make it easier to type and read

    // create the rotation and scale parts of the matrix
    m[3] =   m[0] = Math.cos(rotate) * scale;
    m[2] = -(m[1] = Math.sin(rotate) * scale);

    // add the translation
    m[4] = x;
    m[5] = y;

    // calculate the inverse transformation

    // first get the cross product of x axis and y axis
    cross = m[0] * m[3] - m[1] * m[2];

    // now get the inverted axis
    im[0] =  m[3] / cross;
    im[1] = -m[1] / cross;
    im[2] = -m[2] / cross;
    im[3] =  m[0] / cross;
 }  

因此,如果您希望鼠标在世界空间中的位置

function toWorld(x,y){        
    var xx, yy, m, result;
    m = invMatrix;
    xx = x - matrix[4];     // remove the translation 
    yy = y - matrix[5];     // by subtracting the origin
    // return the point {x:?,y:?} by multiplying xx,yy by the inverse matrix
    return {
       x:   xx * m[0] + yy * m[2],
       y:   xx * m[1] + yy * m[3]
    }
}

该函数会将屏幕空间中的任何坐标转换为世界空间中的正确坐标。

设置2D上下文转换

要使用变换,您可以使用

直接设置2D上下文转换
var mouseWorldSpace = toWorld(mouse.x,mouse.y);  // get the world space coordinates of the mouse

<强>演示

并展示了它的使用情况。很多额外的代码,但我相信你可以找到你需要的部分。 Demo使用var m = matrix; ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5]); 旋转,缩放和翻译动画转换,然后使用createMatrix将鼠标坐标转换为世界空间。

&#13;
&#13;
toWorld
&#13;
&#13;
&#13;

答案 1 :(得分:2)

一步一步走:

在画布上找到鼠标的坐标:

var rect   =  canvas.getBoundingClientRect();
var xMouse =  event.clientX  - rect.left;
var yMouse =  event.clientY  - rect.top;

将这些坐标标准化,使它们在[0; 1]中:

var relX = xMouse / canvas.width;
var relY = yMouse / canvas.height;

现在说你的视图是由一个叫做...的直接定义的......好吧... viewRect,鼠标在视图中的位置是:

var viewX = viewRect.left + relX*(viewRect.right-viewRect.left);
var viewY = viewRect.top + relY*(viewRect.bottom-viewRect.top);

启动应用程序时,你的rect是0,0,canvasWidth,canvasHeight 单击时,您必须调整矩形。

如果点击意味着在viewX,viewY上按zFactor缩放,代码将如下所示:

var newWidth = viewRect.width/zFactor;
var newHeight = viewRect.height/zFactor;
viewRect.left = viewX - newWidth/2;
viewRect.right = viewX + newWidth/2;
viewRect.top  = viewY - newHeight/2;
viewRect.bottom = viewY + newHeight/2;

你的绘制方法应如下所示:

context.save();
context.translate((viewRect.left+viewRect.right )/ 2, ...) ;
var scaleFactor = (viewRect.right+viewRect.left ) / canvasWidth;
context.scale(scaleFactor, scaleFactor);

... draw

context.restore();

答案 2 :(得分:0)

我没有跟踪各种转换,而是询问了当前转换的画布:

    function mouseUp(canvas, event) {
        const rect = canvas.getBoundingClientRect();
        const transform = graphics.getTransform();
        const canvasX = (event.clientX - rect.left - transform.e) / transform.a;
        const canvasY = (event.clientY - rect.top - transform.f) / transform.d;

该方法不会处理偏斜,但是可以大致了解我使用的方法。