我正在尝试用鼠标在 HTML5 画布上进行绘制,但似乎效果良好的唯一方法是,如果我更改画布位置,画布位于位置 0,0(左上角),对于某些人来说原因是它没有按应有的方式绘制。这是我的代码。
function createImageOnCanvas(imageId){
document.getElementById("imgCanvas").style.display = "block";
document.getElementById("images").style.overflowY= "hidden";
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
var img = new Image(300,300);
img.src = document.getElementById(imageId).src;
context.drawImage(img, (0),(0));
}
function draw(e){
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
posx = e.clientX;
posy = e.clientY;
context.fillStyle = "#000000";
context.fillRect (posx, posy, 4, 4);
}
HTML部分
<body>
<div id="images">
</div>
<canvas onmousemove="draw(event)" style="margin:0;padding:0;" id="imgCanvas"
class="canvasView" width="250" height="250"></canvas>
我读过有一种方法可以在 JavaScript 中创建一个简单的函数来获得正确的位置,但我不知道该怎么做。
对于画布元素与位图大小为 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);
}
注意: 如果直接应用于 canvas 元素,边框和填充将会影响位置,因此需要通过
getComputedStyle()
来考虑 - 或者将这些样式应用于父 div。
当存在元素尺寸与位图本身不同的情况时,例如,使用 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 通过 mozCurrentTransform
将返回一个数组,而不是应有的 DOMMatrix
。当通过实验标志启用时,Chrome 都不会返回 DOMMatrix
,而是返回 SVGMatrix
。
但是,在大多数情况下,您必须实现自己的自定义矩阵解决方案(例如我自己的解决方案此处 – 免费/麻省理工学院项目),直到获得完全支持。
当您最终获得矩阵时,无论您采取何种路径获得矩阵,您都需要将其反转并将其应用到鼠标坐标。然后将坐标传递到画布,画布将使用其矩阵将其转换回当前所在的位置。
这样该点将处于相对于鼠标的正确位置。另外,在这里您需要调整坐标(在将逆矩阵应用于它们之前)以相对于元素。
仅显示矩阵步骤的示例:
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),将所有这些步骤嵌入到一个易于使用的对象中,可以在here找到该对象,并且还处理其他一些最容易忽略的细节。
您可以使用以下代码片段获取鼠标位置:
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: (evt.clientX - rect.left) / (rect.right - rect.left) * canvas.width,
y: (evt.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height
};
}
此代码考虑了画布空间坐标的更改 (
evt.clientX - rect.left
) 以及画布逻辑大小与其样式大小不同时的缩放(/ (rect.right - rect.left) * canvas.width
请参阅:HTML5 中的画布宽度和高度)。
示例:http://jsfiddle.net/sierawski/4xezb7nL/
来源: jerryj 评论 http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
您需要获取鼠标位置相对于画布
为此,您需要知道画布在页面上的 X/Y 位置。
这称为画布的“偏移量”,以下是获取偏移量的方法。 (我使用 jQuery 是为了简化跨浏览器兼容性,但如果你想使用原始 javascript,快速的 Google 也会得到它)。
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
然后在你的鼠标处理程序中,你可以像这样获取鼠标X/Y:
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
}
这是一个说明性代码和小提琴,展示了如何成功跟踪画布上的鼠标事件:
http://jsfiddle.net/m1erickson/WB7Zu/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
$("#downlog").html("Down: "+ mouseX + " / " + mouseY);
// Put your mousedown stuff here
}
function handleMouseUp(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
$("#uplog").html("Up: "+ mouseX + " / " + mouseY);
// Put your mouseup stuff here
}
function handleMouseOut(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
$("#outlog").html("Out: "+ mouseX + " / " + mouseY);
// Put your mouseOut stuff here
}
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
$("#movelog").html("Move: "+ mouseX + " / " + mouseY);
// Put your mousemove stuff here
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<p>Move, press and release the mouse</p>
<p id="downlog">Down</p>
<p id="movelog">Move</p>
<p id="uplog">Up</p>
<p id="outlog">Out</p>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
计算画布事件上正确的鼠标单击或鼠标移动位置的最简单方法是使用这个小方程:
canvas.addEventListener('click', event =>
{
let bound = canvas.getBoundingClientRect();
let x = event.clientX - bound.left - canvas.clientLeft;
let y = event.clientY - bound.top - canvas.clientTop;
context.fillRect(x, y, 16, 16);
});
如果画布有 padding-left 或 padding-top,则通过以下方式减去 x 和 y:
x -= parseFloat(style['padding-left'].replace('px'));
y -= parseFloat(style['padding-top'].replace('px'));
参考这个问题:我得到的 mouseEvent.offsetX 比实际画布尺寸大得多 .我在那里给出了一个完全适合您情况的功能
我用这个:
function geMousePosRelativeCanvas(event, canvas) {
var mouseX = parseInt(event.offsetX * canvas.width / canvas.offsetWidth);
var mouseY = parseInt(event.offsetY * canvas.height / canvas.offsetHeight);
return {x: mouseX, y: mouseY};
}