【问题标题】:HTML5 canvas get coordinates after zoom and translateHTML5 画布在缩放和翻译后获取坐标
【发布时间】:2014-03-10 03:11:53
【问题描述】:

背景:我有一个 HTML5 画布,并在上面绘制了一张图像。现在,当第一次加载图像时,它以 100% 的比例加载。图像是 5000 x 5000。画布大小是 600 x 600。所以在加载时,我只看到前 600 x 像素和 600 y 像素。我可以选择缩放和翻译画布上的图像。

我的问题:我正在尝试找出一种算法,该算法返回鼠标单击相对于图像的像素坐标,而不是画布,同时考虑到缩放和平移。 我知道已经有很多关于此的主题,但我所看到的没有任何效果。我的问题是当我有多个翻译和缩放时。我可以缩放一次并获得正确的坐标,然后我可以缩放并再次获得正确的坐标,但是一旦我多次缩放或缩放,坐标就会关闭。

这是我目前所拥有的。

//get pixel coordinates from canvas mousePos.x, mousePos.y
(mousePos.x - x_translation)/scale //same for mousePos.y

annotationCanvas.addEventListener('mouseup',function(evt){
                     dragStart = null;
                     if (!dragged) {
                       var mousePos = getMousePos(canvas, evt);
                       var message1 =  " mouse  x: " + (mousePos.x) + '  ' + "mouse y: " + (mousePos.y);
                       var message =  "  x: " + ((mousePos.x + accX)/currentZoom*currentZoom) + '  ' + "y: " + ((mousePos.y + accY)/currentZoom);
                       console.log(message);
                       console.log(message1);
                       console.log("zoomAcc = " + zoomAcc);
                       console.log("currentZoom = " + currentZoom);
                       ctx.fillStyle="#FF0000";
                       ctx.fillRect((mousePos.x + accX)/currentZoom, (mousePos.y + accY)/currentZoom, -5, -5);

                     }
             },true);
//accX and accY are the cumulative shift for x and y respectively, and xShift and xShift yShift are the incremental shifts of x and y respectively

其中当前缩放是累积缩放。 zoomAcc 是该点的单次缩放迭代。所以在这种情况下,当我放大时,zoomAcc 总是 1.1,currentZoom = currentZoom*zoomAcc。

为什么这是错误的?如果有人可以请告诉我如何跟踪这些转换,然后将它们应用于 mousePos.x 和 mousePos.y,我将不胜感激。

谢谢

更新:

在图像中,绿点是我单击的位置,红点是我计算该点的位置,使用 markE 的方法。 m 值是您的 markE 方法中的矩阵值。

【问题讨论】:

  • :那么你最后是怎么解决你的问题的呢?...我被同样的问题困住了:(

标签: javascript html canvas


【解决方案1】:

当您命令上下文进行平移和缩放时,这些称为画布转换。

画布变换基于一个可以由 6 个数组元素表示的矩阵:

// an array representing the canvas affine transformation matrix 
var matrix=[1,0,0,1,0,0];

如果您执行 context.translate 或 context.scale 并同时更新矩阵,那么您可以使用矩阵将未转换的 X/Y 坐标(如鼠标事件)转换为转换后的图像坐标。

context.translate:

您可以同时执行 context.translate(x,y) 并像这样在矩阵中跟踪该翻译:

// do the translate
// but also save the translate in the matrix
function translate(x,y){
    matrix[4] += matrix[0] * x + matrix[2] * y;
    matrix[5] += matrix[1] * x + matrix[3] * y;
    ctx.translate(x,y);
}

context.scale:

您可以同时执行 context.scale(x,y) 并跟踪缩放矩阵,如下所示:

// do the scale
// but also save the scale in the matrix
function scale(x,y){
    matrix[0] *= x;
    matrix[1] *= x;
    matrix[2] *= y;
    matrix[3] *= y;    
    ctx.scale(x,y);
}

将鼠标坐标转换为转换后的图像坐标

问题是浏览器不知道您已经转换了画布坐标系,并且浏览器将返回相对于浏览器窗口的鼠标坐标,而不是相对于转换后的画布。

幸运的是,转换矩阵一直在跟踪您累积的所有平移和缩放。

您可以将浏览器的窗口坐标转换为转换后的坐标,如下所示:

// convert mouseX/mouseY coordinates
// into transformed coordinates

function getXY(mouseX,mouseY){
    newX = mouseX * matrix[0] + mouseY * matrix[2] + matrix[4];
    newY = mouseX * matrix[1] + mouseY * matrix[3] + matrix[5];
    return({x:newX,y:newY});
}

【讨论】:

  • markE,感谢您提供详细的答复。我已按照您的说明进行操作,第一次缩放时我得到了正确的坐标,但是当我在缩放后移动时,它就关闭了。我在我的问题中添加了一张图片
  • 由于画布的 widthheight 属性,您缺少自动缩放。我想这应该通过添加实际宽度和高度与画布宽度和高度的比率来解决。
  • 另外,请注意某些事情会重置画布的内部转换矩阵。例如。设置canvas.widthheight 时。确保之后重置您的矩阵。
  • context.rotate() 和 context.transform() 在哪里?
  • @cuixiping。这个问题是关于缩放和翻译的。这是另一篇使用变换矩阵处理旋转的帖子:stackoverflow.com/questions/18437039/…。顺便说一句,context.transform 用于修改现有的上下文矩阵。您还可以使用context.setTransform 覆盖现有的上下文矩阵。 ;-)
猜你喜欢
  • 2016-06-27
  • 2014-08-27
  • 2016-11-19
  • 2019-08-18
  • 1970-01-01
  • 1970-01-01
  • 2011-03-24
  • 2016-11-11
  • 1970-01-01
相关资源
最近更新 更多