简单的 1:1 场景
对于画布元素与位图大小为 1:1 的情况,您可以使用以下代码段获取鼠标位置:
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
只需使用事件和画布作为参数从您的事件中调用它。它返回一个带有 x 和 y 鼠标位置的对象。
由于您获得的鼠标位置是相对于客户端窗口的,因此您必须减去画布元素的位置才能将其相对于元素本身进行转换。
代码中的集成示例:
//put this outside the event loop..
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
function draw(evt) {
var pos = getMousePos(canvas, evt);
context.fillStyle = "#000000";
context.fillRect (pos.x, pos.y, 4, 4);
}
注意:如果直接应用于画布元素,边框和填充将影响位置,因此需要通过getComputedStyle()
- 或将这些样式应用到父 div 来考虑这些。
当 Element 和 Bitmap 大小不同时
当元素的大小与位图本身不同时,例如,使用 CSS 缩放元素或存在像素纵横比等,您将不得不解决这个问题。
例子:
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect(), // abs. size of element
scaleX = canvas.width / rect.width, // relationship bitmap vs. element for X
scaleY = canvas.height / rect.height; // relationship bitmap vs. element for Y
return {
x: (evt.clientX - rect.left) * scaleX, // scale mouse coordinates after they have
y: (evt.clientY - rect.top) * scaleY // been adjusted to be relative to element
}
}
将变换应用于上下文(缩放、旋转等)
然后是更复杂的情况,您已将变换应用于上下文,例如旋转、倾斜/剪切、缩放、平移等。要处理此问题,您可以计算当前矩阵的逆矩阵。
较新的浏览器允许您通过属性读取当前矩阵,currentTransform
而 Firefox(当前 alpha)甚至通过mozCurrentTransformInverted
. 然而,Firefox 通过 viamozCurrentTransform
将返回一个 Array 而不是DOMMatrix
它应该返回的。通过实验标志启用时,Chrome 都不会返回 aDOMMatrix
但 a SVGMatrix
。
然而,在大多数情况下,您必须实现自己的自定义矩阵解决方案(例如我自己的解决方案-免费/MIT 项目),直到获得完全支持。
当您最终获得矩阵时,无论您采用何种路径来获得矩阵,您都需要将其反转并将其应用于您的鼠标坐标。然后将坐标传递给画布,画布将使用其矩阵将其转换回当前的任何位置。
这样,该点将位于相对于鼠标的正确位置。同样在这里,您需要调整坐标(在将逆矩阵应用于它们之前)以相对于元素。
仅显示矩阵步骤的示例
function draw(evt) {
var pos = getMousePos(canvas, evt); // get adjusted coordinates as above
var imatrix = matrix.inverse(); // get inverted matrix somehow
pos = imatrix.applyToPoint(pos.x, pos.y); // apply to adjusted coordinate
context.fillStyle = "#000000";
context.fillRect(pos.x-1, pos.y-1, 2, 2);
}
实施时使用的一个例子currentTransform
是:
var pos = getMousePos(canvas, e); // get adjusted coordinates as above
var matrix = ctx.currentTransform; // W3C (future)
var imatrix = matrix.invertSelf(); // invert
// apply to point:
var x = pos.x * imatrix.a + pos.y * imatrix.c + imatrix.e;
var y = pos.x * imatrix.b + pos.y * imatrix.d + imatrix.f;
更新我制作了一个免费的解决方案 (MIT),将所有这些步骤嵌入到一个易于使用的对象中,该对象可以在此处找到,并且还处理了一些大多数人忽略的其他细节问题。