Tom*_*Tom 263 javascript canvas
将单击事件处理程序添加到将返回单击的x和y坐标(相对于canvas元素)的canvas元素的最简单方法是什么?
不需要传统的浏览器兼容性,Safari,Opera和Firefox都可以.
Rya*_*ona 175
更新(5/5/16):应该使用patriques的答案,因为它既简单又可靠.
由于画布并不总是相对于整个页面设置样式,因此canvas.offsetLeft/Top并不总是返回您需要的内容.它将返回相对于其offsetParent元素偏移的像素数,这可能类似于div包含position: relative应用了样式的画布的元素.为了解释这一点,你需要循环遍历offsetParents 链,从canvas元素本身开始.这段代码非常适合我,在Firefox和Safari中测试,但应该适用于所有人.
function relMouseCoords(event){
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasX = 0;
var canvasY = 0;
var currentElement = this;
do{
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
}
while(currentElement = currentElement.offsetParent)
canvasX = event.pageX - totalOffsetX;
canvasY = event.pageY - totalOffsetY;
return {x:canvasX, y:canvasY}
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
Run Code Online (Sandbox Code Playgroud)
最后一行使得相对于canvas元素获取鼠标坐标变得方便.获得有用坐标所需的只是
coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;
Run Code Online (Sandbox Code Playgroud)
pat*_*ues 167
如果您喜欢简单但仍想要跨浏览器功能,我发现这个解决方案最适合我.这是@Aldekein解决方案的简化,但没有jQuery.
function getCursorPosition(canvas, event) {
const rect = canvas.getBoundingClientRect()
const x = event.clientX - rect.left
const y = event.clientY - rect.top
console.log("x: " + x + " y: " + y)
}
const canvas = document.querySelector('canvas')
canvas.addEventListener('mousedown', function(e) {
getCursorPosition(canvas, e)
})
Run Code Online (Sandbox Code Playgroud)
N4p*_*peL 71
编辑2018:这个答案非常陈旧,它使用了对不再需要的旧浏览器的检查,因为clientX和clientY属性适用于所有当前浏览器.您可能需要查看Patriques Answer以获得更简单,更新的解决方案.
原始答案:
正如我在当时发现的一篇文章所述,但不再存在:
var x;
var y;
if (e.pageX || e.pageY) {
x = e.pageX;
y = e.pageY;
}
else {
x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;
Run Code Online (Sandbox Code Playgroud)
对我来说工作得很好.
maf*_*afu 29
现代浏览器现在可以为您处理.Chrome,IE9和Firefox支持offsetX/Y,从点击处理程序传递事件.
function getRelativeCoords(event) {
return { x: event.offsetX, y: event.offsetY };
}
Run Code Online (Sandbox Code Playgroud)
大多数现代浏览器也支持layerX/Y,但Chrome和IE使用layerX/Y作为页面上点击的绝对偏移量,包括边距,填充等.在Firefox中,layerX/Y和offsetX/Y是等效的,但是偏移量没有以前存在过.因此,为了与较旧的浏览器兼容,您可以使用:
function getRelativeCoords(event) {
return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}
Run Code Online (Sandbox Code Playgroud)
Ald*_*ein 17
根据新鲜怪异模式将clientX和clientY方法,在所有主要的浏览器都支持.所以,在这里它是 - 在带有滚动条的页面上的滚动div中工作的好的,有效的代码:
function getCursorPosition(canvas, event) {
var x, y;
canoffset = $(canvas).offset();
x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - Math.floor(canoffset.left);
y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop - Math.floor(canoffset.top) + 1;
return [x,y];
}
Run Code Online (Sandbox Code Playgroud)
这也需要的jQuery的$(canvas).offset().
Man*_*ero 13
我做了一个完整的演示,可以在每个浏览器中使用此问题的解决方案的完整源代码:鼠标在Javascript中单击Canvas的坐标.要尝试演示,请复制代码并将其粘贴到文本编辑器中.然后将其保存为example.html,最后,使用浏览器打开该文件.
Cry*_*rus 10
以下是对Ryan Artecona对宽度可变(%)的画布的回答的一个小修改:
HTMLCanvasElement.prototype.relMouseCoords = function (event) {
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasX = 0;
var canvasY = 0;
var currentElement = this;
do {
totalOffsetX += currentElement.offsetLeft;
totalOffsetY += currentElement.offsetTop;
}
while (currentElement = currentElement.offsetParent)
canvasX = event.pageX - totalOffsetX;
canvasY = event.pageY - totalOffsetY;
// Fix for variable canvas width
canvasX = Math.round( canvasX * (this.width / this.offsetWidth) );
canvasY = Math.round( canvasY * (this.height / this.offsetHeight) );
return {x:canvasX, y:canvasY}
}
Run Code Online (Sandbox Code Playgroud)
gma*_*man 10
So this is both simple but a slightly more complicated topic than it seems.
First off there are usually to conflated questions here
How to get element relative mouse coordinates
How to get canvas pixel mouse coordinates for the 2D Canvas API or WebGL
so, answers
Whether or not the element is a canvas getting element relative mouse coordinates is the same for all elements.
There are 2 simple answers to the question "How to get canvas relative mouse coordinates"
offsetX and offsetYcanvas.addEventListner('mousemove', (e) => {
const x = e.offsetX;
const y = e.offsetY;
});
Run Code Online (Sandbox Code Playgroud)
This answer works in Chrome, Firefox, and Safari. Unlike all the other event values offsetX and offsetY take CSS transforms into account.
The biggest problem with offsetX and offsetY is as of 2019/05 they don't exist on touch events and so can't be used with iOS Safari. They do exist on Pointer Events which exist in Chrome and Firefox but not Safari although apparently Safari is working on it.
Another issue is the events must be on the canvas itself. If you put them on some other element or the window you can not later choose the canvas to be your point of reference.
clientX, clientY and canvas.getBoundingClientRectIf you don't care about CSS transforms the next simplest answer is to call canvas. getBoundingClientRect() and subtract the left from clientX and top from clientY as in
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
});
Run Code Online (Sandbox Code Playgroud)
This will work as long as there are no CSS transforms. It also works with touch events and so will work with Safari iOS
canvas.addEventListener('touchmove', (e) => {
const rect = canvas. getBoundingClientRect();
const x = e.touches[0].clientX - rect.left;
const y = e.touches[0].clientY - rect.top;
});
Run Code Online (Sandbox Code Playgroud)
For this we need to take the values we got above and convert from the size the canvas is displayed to the number of pixels in the canvas itself
with canvas.getBoundingClientRect and clientX and clientY
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const elementRelativeX = e.clientX - rect.left;
const elementRelativeY = e.clientY - rect.top;
const canvasRelativeX = elementRelativeX * canvas.width / rect.width;
const canvasRelativeY = elementRelativeY * canvas.height / rect.height;
});
Run Code Online (Sandbox Code Playgroud)
or with offsetX and offsetY
canvas.addEventListener('mousemove', (e) => {
const elementRelativeX = e.offsetX;
const elementRelativeY = e.offsetY;
const canvasRelativeX = elementRelativeX * canvas.width / canvas.clientWidth;
const canvasRelativeY = elementRelativeY * canvas.height / canvas.clientHeight;
});
Run Code Online (Sandbox Code Playgroud)
使用的工作示例event.offsetX,event.offsetY
canvas.addEventListner('mousemove', (e) => {
const x = e.offsetX;
const y = e.offsetY;
});
Run Code Online (Sandbox Code Playgroud)
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
});
Run Code Online (Sandbox Code Playgroud)
canvas.addEventListener('touchmove', (e) => {
const rect = canvas. getBoundingClientRect();
const x = e.touches[0].clientX - rect.left;
const y = e.touches[0].clientY - rect.top;
});
Run Code Online (Sandbox Code Playgroud)
用工作实例canvas.getBoundingClientRect,并event.clientX与event.clientY
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const elementRelativeX = e.clientX - rect.left;
const elementRelativeY = e.clientY - rect.top;
const canvasRelativeX = elementRelativeX * canvas.width / rect.width;
const canvasRelativeY = elementRelativeY * canvas.height / rect.height;
});
Run Code Online (Sandbox Code Playgroud)
canvas.addEventListener('mousemove', (e) => {
const elementRelativeX = e.offsetX;
const elementRelativeY = e.offsetY;
const canvasRelativeX = elementRelativeX * canvas.width / canvas.clientWidth;
const canvasRelativeY = elementRelativeY * canvas.height / canvas.clientHeight;
});
Run Code Online (Sandbox Code Playgroud)
[...document.querySelectorAll('canvas')].forEach((canvas) => {
const ctx = canvas.getContext('2d');
ctx.canvas.width = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
let count = 0;
function draw(e, radius = 1) {
const pos = {
x: e.offsetX * canvas.width / canvas.clientWidth,
y: e.offsetY * canvas.height / canvas.clientHeight,
};
document.querySelector('#debug').textContent = count;
ctx.beginPath();
ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
ctx.fillStyle = hsl((count++ % 100) / 100, 1, 0.5);
ctx.fill();
}
function preventDefault(e) {
e.preventDefault();
}
if (window.PointerEvent) {
canvas.addEventListener('pointermove', (e) => {
draw(e, Math.max(Math.max(e.width, e.height) / 2, 1));
});
canvas.addEventListener('touchstart', preventDefault, {passive: false});
canvas.addEventListener('touchmove', preventDefault, {passive: false});
} else {
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mousedown', preventDefault);
}
});
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}Run Code Online (Sandbox Code Playgroud)
在进行坐标转换时要小心; 在单击事件中返回了多个非跨浏览器值.如果滚动浏览器窗口(在Firefox 3.5和Chrome 3.0中验证),仅使用clientX和clientY是不够的.
这个怪癖模式文章提供了一个更正确的函数,可以使用pageX或pageY或clientX与document.body.scrollLeft和clientY与document.body.scrollTop的组合来计算相对于文档原点的单击坐标.
更新:此外,offsetLeft和offsetTop是相对于元素的填充大小,而不是内部大小.应用了padding:style的画布不会将其内容区域的左上角报告为offsetLeft.这个问题有各种解决方案; 最简单的可能是清除画布本身上的所有边框,填充等样式,而是将它们应用到包含画布的框中.
我不确定所有这些答案的重点在于循环通过父元素并做各种奇怪的事情.
该HTMLElement.getBoundingClientRect方法旨在处理任何元素的实际屏幕位置.这包括滚动,所以scrollTop不需要的东西:
(来自MDN)在计算边界矩形时,会考虑视口区域(或 任何其他可滚动元素)的滚动量
在非常简单的方法已经张贴在这里.只要不涉及任何野生CSS规则,这是正确的.
当图像像素宽度与其CSS宽度不匹配时,您需要对像素值应用一些比率:
/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
var x,y;
//This is the current screen rectangle of canvas
var rect = this.getBoundingClientRect();
var top = rect.top;
var bottom = rect.bottom;
var left = rect.left;
var right = rect.right;
//Recalculate mouse offsets to relative offsets
x = event.clientX - left;
y = event.clientY - top;
//Also recalculate offsets of canvas is stretched
var width = right - left;
//I use this to reduce number of calculations for images that have normal size
if(this.width!=width) {
var height = bottom - top;
//changes coordinates by ratio
x = x*(this.width/width);
y = y*(this.height/height);
}
//Return as an array
return [x,y];
}
Run Code Online (Sandbox Code Playgroud)
只要画布没有边框,它就适用于拉伸图像(jsFiddle).
如果画布边框很粗,那么事情就会变得复杂.你真的需要从边界矩形中减去边界.这可以使用.getComputedStyle完成.这个答案描述了这个过程.
然后功能增长了一点:
/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
var x,y;
//This is the current screen rectangle of canvas
var rect = this.getBoundingClientRect();
var top = rect.top;
var bottom = rect.bottom;
var left = rect.left;
var right = rect.right;
//Subtract border size
// Get computed style
var styling=getComputedStyle(this,null);
// Turn the border widths in integers
var topBorder=parseInt(styling.getPropertyValue('border-top-width'),10);
var rightBorder=parseInt(styling.getPropertyValue('border-right-width'),10);
var bottomBorder=parseInt(styling.getPropertyValue('border-bottom-width'),10);
var leftBorder=parseInt(styling.getPropertyValue('border-left-width'),10);
//Subtract border from rectangle
left+=leftBorder;
right-=rightBorder;
top+=topBorder;
bottom-=bottomBorder;
//Proceed as usual
...
}
Run Code Online (Sandbox Code Playgroud)
我想不出任何会混淆这个最终功能的东西.在JsFiddle看到自己.
如果你不喜欢修改本机prototypes,只需更改函数并调用它(canvas, event)(并替换为thiswith canvas).
小智 6
这是一个非常好的教程 -
http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
function writeMessage(canvas, message) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
context.font = '18pt Calibri';
context.fillStyle = 'black';
context.fillText(message, 10, 25);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
writeMessage(canvas, message);
}, false);
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
255572 次 |
| 最近记录: |