[英]Find mouse position relative to element
我想使用 canvas 制作一个小绘画应用程序。 所以需要在canvas上找到鼠标的position。
由于我没有找到可以复制/粘贴的无 jQuery 答案,因此这是我使用的解决方案:
document.getElementById('clickme').onclick = function clickEvent(e) { // e = Mouse click event. var rect = e.target.getBoundingClientRect(); var x = e.clientX - rect.left; //x position within the element. var y = e.clientY - rect.top; //y position within the element. console.log("Left? : " + x + " ; Top? : " + y + "."); }
#clickme { margin-top: 20px; margin-left: 100px; border: 1px solid black; cursor: pointer; }
<div id="clickme">Click Me -<br> (this box has margin-left: 100px; margin-top: 20px;)</div>
对于使用 JQuery 的人:
有时,当您有嵌套元素时,其中一个带有附加的事件,可能会让人难以理解您的浏览器将什么视为父元素。 在这里,您可以指定哪个父级。
您获取鼠标位置,然后从父元素的偏移位置中减去它。
var x = evt.pageX - $('#element').offset().left;
var y = evt.pageY - $('#element').offset().top;
如果您试图在滚动窗格内的页面上获取鼠标位置:
var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop();
或者相对于页面的位置:
var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
请注意以下性能优化:
var offset = $('#element').offset();
// Then refer to
var x = evt.pageX - offset.left;
这样,JQuery 就不必为每一行查找#element
。
@anytimecoder的答案中有一个更新的纯 JavaScript 版本 - 另请参阅浏览器对 getBoundingClientRect() 的支持。
下面计算鼠标与画布元素的位置关系:
const example = document.getElementById('example');
example.onmousemove = function(e) {
const x = e.pageX - e.currentTarget.offsetLeft;
const y = e.pageY - e.currentTarget.offsetTop;
}
当参考元素嵌套在其他可以使用绝对定位的元素中时,纯javascript中没有返回相对坐标的答案。 这是此场景的解决方案:
function getRelativeCoordinates (event, referenceElement) {
const position = {
x: event.pageX,
y: event.pageY
};
const offset = {
left: referenceElement.offsetLeft,
top: referenceElement.offsetTop
};
let reference = referenceElement.offsetParent;
while(reference){
offset.left += reference.offsetLeft;
offset.top += reference.offsetTop;
reference = reference.offsetParent;
}
return {
x: position.x - offset.left,
y: position.y - offset.top,
};
}
我尝试了所有这些解决方案,但由于我使用矩阵转换容器(panzoom 库)的特殊设置,都没有奏效。 即使缩放和平移,这也会返回正确的值:
mouseevent(e) {
const x = e.offsetX,
y = e.offsetY
}
但前提是方式中没有子元素。 这可以通过使用 CSS 使它们对事件“不可见”来规避:
.child {
pointer-events: none;
}
可以在此处找到有关此问题难度的详细说明: http ://www.quirksmode.org/js/events_properties.html#position
使用那里描述的技术,您可以在文档中找到鼠标位置。 然后您只需检查它是否在元素的边界框内,您可以通过调用element.getBoundingClientRect()
找到它,这将返回一个具有以下属性的对象: { bottom, height, left, right, top, width }
。 从那里找出是否甚至发生在您的元素内部是微不足道的。
我遇到了这个问题,但为了使它适用于我的情况(在 DOM 元素上使用 dragover(在我的情况下不是画布)),我发现你只需要在 dragover 上使用offsetX
和offsetY
-鼠标事件。
onDragOver(event){
var x = event.offsetX;
var y = event.offsetY;
}
如果你想得到一个元素相关的layerX和layerY,也许你可以试试:
let bbox_rect = document.getElementById("dom-ID").getBoundingClientRect()
let layerX = e.clientX-bbox_rect.left
let layerY = e.clientY-bbox_rect.top
我 +1' Mark van Wyk 的回答,因为它让我朝着正确的方向前进,但并没有完全解决我的问题。 在另一个元素中包含的元素中,我仍然有一个偏移量。
以下为我解决了它:
x = e.pageX - this.offsetLeft - $(elem).offset().left;
y = e.pageY - this.offsetTop - $(elem).offset().top;
换句话说 - 我只是堆叠了所有嵌套元素的所有偏移量
对于那些为移动设备和/或带触摸屏的笔记本电脑/显示器开发常规网站或 PWA(渐进式 Web 应用程序)的人来说,您来到这里是因为您可能习惯于鼠标事件,并且对有时痛苦的 Touch 体验不熟悉事件...耶!
只有3条规则:
mousemove
或touchmove
事件期间尽可能少做。mousedown
或touchstart
事件期间尽可能多地执行。 不用说, touch
事件会使事情变得更复杂,因为可能不止一个,而且它们比鼠标事件更灵活(复杂)。 我在这里只介绍一次触摸。 是的,我很懒,但这是最常见的触摸方式,所以就在那里。
var posTop; var posLeft; function handleMouseDown(evt) { var e = evt || window.event; // Because Firefox, etc. posTop = e.target.offsetTop; posLeft = e.target.offsetLeft; e.target.style.background = "red"; // The statement above would be better handled by CSS // but it's just an example of a generic visible indicator. } function handleMouseMove(evt) { var e = evt || window.event; var x = e.offsetX; // Wonderfully var y = e.offsetY; // Simple! e.target.innerHTML = "Mouse: " + x + ", " + y; if (posTop) e.target.innerHTML += "<br>" + (x + posLeft) + ", " + (y + posTop); } function handleMouseOut(evt) { var e = evt || window.event; e.target.innerHTML = ""; } function handleMouseUp(evt) { var e = evt || window.event; e.target.style.background = "yellow"; } function handleTouchStart(evt) { var e = evt || window.event; var rect = e.target.getBoundingClientRect(); posTop = rect.top; posLeft = rect.left; e.target.style.background = "green"; e.preventDefault(); // Unnecessary if using Vue.js e.stopPropagation(); // Same deal here } function handleTouchMove(evt) { var e = evt || window.event; var pageX = e.touches[0].clientX; // Touches are page-relative var pageY = e.touches[0].clientY; // not target-relative var x = pageX - posLeft; var y = pageY - posTop; e.target.innerHTML = "Touch: " + x + ", " + y; e.target.innerHTML += "<br>" + pageX + ", " + pageY; e.preventDefault(); e.stopPropagation(); } function handleTouchEnd(evt) { var e = evt || window.event; e.target.style.background = "yellow"; // Yes, I'm being lazy and doing the same as mouseout here // but obviously you could do something different if needed. e.preventDefault(); e.stopPropagation(); }
div { background: yellow; height: 100px; left: 50px; position: absolute; top: 80px; user-select: none; /* Disable text selection */ -ms-user-select: none; width: 100px; }
<div onmousedown="handleMouseDown()" onmousemove="handleMouseMove()" onmouseout="handleMouseOut()" onmouseup="handleMouseUp()" ontouchstart="handleTouchStart()" ontouchmove="handleTouchMove()" ontouchend="handleTouchEnd()"> </div> Move over box for coordinates relative to top left of box.<br> Hold mouse down or touch to change color.<br> Drag to turn on coordinates relative to top left of page.
更喜欢使用Vue.js吗? 我愿意! 然后您的 HTML 将如下所示:
<div @mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@touchstart.stop.prevent="handleTouchStart"
@touchmove.stop.prevent="handleTouchMove"
@touchend.stop.prevent="handleTouchEnd">
上述答案都不是令人满意的IMO,所以这就是我使用的:
// Cross-browser AddEventListener
function ael(e, n, h){
if( e.addEventListener ){
e.addEventListener(n, h, true);
}else{
e.attachEvent('on'+n, h);
}
}
var touch = 'ontouchstart' in document.documentElement; // true if touch device
var mx, my; // always has current mouse position IN WINDOW
if(touch){
ael(document, 'touchmove', function(e){var ori=e;mx=ori.changedTouches[0].pageX;my=ori.changedTouches[0].pageY} );
}else{
ael(document, 'mousemove', function(e){mx=e.clientX;my=e.clientY} );
}
// local mouse X,Y position in element
function showLocalPos(e){
document.title = (mx - e.getBoundingClientRect().left)
+ 'x'
+ Math.round(my - e.getBoundingClientRect().top);
}
如果您需要知道 page 的当前 Y 滚动位置:
var yscroll = window.pageYOffset
|| (document.documentElement && document.documentElement.scrollTop)
|| document.body.scrollTop; // scroll Y position in page
摘自本教程,感谢顶评论进行了更正:
function getMousePos( canvas, evt ) {
var rect = canvas.getBoundingClientRect();
return {
x: Math.floor( ( evt.clientX - rect.left ) / ( rect.right - rect.left ) * canvas.width ),
y: Math.floor( ( evt.clientY - rect.top ) / ( rect.bottom - rect.top ) * canvas.height )
};
}
在画布上使用如下:
var canvas = document.getElementById( 'myCanvas' );
canvas.addEventListener( 'mousemove', function( evt ) {
var mousePos = getMousePos( canvas, evt );
} );
canvas.onmousedown = function(e) {
pos_left = e.pageX - e.currentTarget.offsetLeft;
pos_top = e.pageY - e.currentTarget.offsetTop;
console.log(pos_left, pos_top)
}
HTMLElement.offsetLeft
HTMLElement.offsetLeft
只读属性返回当前元素左上角在HTMLElement.offsetParent
节点内向左偏移的像素数。
对于块级元素, offsetTop
、 offsetLeft
、 offsetWidth
和offsetHeight
描述了元素相对于offsetParent
的边框框。
但是,对于可以从一行换行到下一行的内联元素(例如span
), offsetTop
和offsetLeft
描述了第一个边框框的位置(使用Element.getClientRects()
获取其宽度和高度),而offsetWidth
和offsetHeight
描述边界框的尺寸(使用Element.getBoundingClientRect()
来获取它的位置)。 因此,具有offsetLeft
、 offsetTop
、 offsetWidth
和offsetHeight
的 left、top、width 和 height 的框将不会是带有换行文本的 span 的边界框。
HTMLElement.offsetTop
HTMLElement.offsetTop
只读属性返回当前元素相对于offsetParent
节点顶部的距离。
MouseEvent.pageX
pageX
只读属性返回事件相对于整个文档的 X(水平)坐标(以像素为单位)。 该属性考虑了页面的任何水平滚动。
MouseEvent.pageY
MouseEvent.pageY
只读属性返回事件相对于整个文档的 Y(垂直)坐标(以像素为单位)。 该属性考虑了页面的任何垂直滚动。
进一步的解释,请参见 Mozilla 开发者网络:
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageY https:// developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop
const findMousePositionRelativeToElement = (e) => {
const xClick = e.clientX - e.currentTarget.offsetLeft;
const yClick = e.clientY - e.currentTarget.offsetTop;
console.log(`x: ${xClick}`);
console.log(`y: ${yClick}`);
// or
const rect = e.currentTarget.getBoundingClientRect();
const xClick2 = e.clientX - rect.left;
const yClick2 = e.clientY - rect.top;
console.log(`x2: ${xClick2}`);
console.log(`y2: ${yClick2}`);
}
我意识到我有点晚了,但这适用于 PURE javascript,如果元素大于视口并且用户已滚动,它甚至会为您提供元素内指针的坐标。
var element_offset_x ; // The distance from the left side of the element to the left of the content area
....// some code here (function declaration or element lookup )
element_offset_x = element.getBoundingClientRect().left - document.getElementsByTagName("html")[0].getBoundingClientRect().left ;
....// code here
function mouseMoveEvent(event)
{
var pointer_location = (event.clientX + window.pageXOffset) - element_offset_x ;
}
这个怎么运作。
我们要做的第一件事是获取 HTML 元素(内容区域)相对于当前视口的位置。 如果页面有滚动条并且被滚动,那么getBoundingClientRect().left
为 html 标签返回的数字将为负数。 然后我们使用这个数字来计算元素与内容区域左侧之间的距离。 与element_offset_x = element.getBoundingClientRect().left......;
知道元素与内容区域的距离。 event.clientX
为我们提供了指针与视口的距离。 重要的是要了解视口和内容区域是两个不同的实体,如果页面滚动,视口可以移动。 因此,即使页面滚动,clientX 也会返回相同的数字。
为了弥补这一点,我们需要将指针的 x 位置(相对于视口)添加到视口的 x 位置(相对于内容区域)。 视口的 X 位置通过window.pageXOffset.
基于@Spider的解决方案,我的非JQuery版本是这样的:
// Get the container element's bounding box
var sides = document.getElementById("container").getBoundingClientRect();
// Apply the mouse event listener
document.getElementById("canvas").onmousemove = (e) => {
// Here 'self' is simply the current window's context
var x = (e.clientX - sides.left) + self.pageXOffset;
var y = (e.clientY - sides.top) + self.pageYOffset;
}
这适用于滚动和缩放(在这种情况下,有时它会返回浮动)。
您可以使用relative
父级的getBoudingClientRect()
。
document.addEventListener("mousemove", (e) => {
let xCoord = e.clientX - e.target.getBoundingClientRect().left + e.offsetX
let yCoord = e.clientY - e.target.getBoundingClientRect().top + e.offsetY
console.log("xCoord", xCoord, "yCoord", yCoord)
})
你可以通过
var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
var xCoor = e.clientX;
var yCoor = e.clientY;
}
可以通过 event.offsetX 和 event.offsetY 获得画布内的鼠标坐标。 这里有一个小片段来证明我的观点:
c=document.getElementById("c"); ctx=c.getContext("2d"); ctx.fillStyle="black"; ctx.fillRect(0,0,100,100); c.addEventListener("mousemove",function(mouseEvt){ // the mouse's coordinates on the canvas are just below x=mouseEvt.offsetX; y=mouseEvt.offsetY; // the following lines draw a red square around the mouse to prove it ctx.fillStyle="black"; ctx.fillRect(0,0,100,100); ctx.fillStyle="red"; ctx.fillRect(x-5,y-5,10,10); });
body { background-color: blue; } canvas { position: absolute; top: 50px; left: 100px; }
<canvas id="c" width="100" height="100"></canvas>
我实现了另一个我认为非常简单的解决方案,所以我想与你们分享。
所以,对我来说,问题是拖动的 div 会跳转到鼠标光标的0,0 。 所以我需要捕捉鼠标在 div 上的位置来调整 div 的新位置。
我阅读了 div PageX 和 PageY 并根据它设置顶部和左侧,然后获取值以调整坐标以将光标保持在 div 中的初始位置我使用 onDragStart 侦听器并存储e.nativeEvent .layerX和e.nativeEvent.layerY仅在初始触发器中为您提供鼠标在可拖动 div 中的位置。
示例代码:
onDrag={(e) => {
let newCoords;
newCoords = { x: e.pageX - this.state.correctionX, y: e.pageY - this.state.correctionY };
this.props.onDrag(newCoords, e, item.id);
}}
onDragStart={
(e) => {
this.setState({
correctionX: e.nativeEvent.layerX,
correctionY: e.nativeEvent.layerY,
});
}
我希望这会帮助遇到我遇到的同样问题的人:)
function myFunction(e) {
var x = e.clientX - e.currentTarget.offsetLeft ;
var y = e.clientY - e.currentTarget.offsetTop ;
}
这行得通!
您可以简单地使用 jQuery 的event.pageX和event.pageY以及 jQuery 的offset()方法来获取鼠标相对于元素的位置。
$(document).ready(function() {
$("#myDiv").mousemove(function(event){
var X = event.pageX - $(this).offset().left;
var Y = event.pageY - $(this).offset().top;
$(".cordn").text("(" + X + "," + Y + ")");
});
});
你可以在这里看到一个例子: How to find mouse position relative to element
您必须知道页面的结构,因为如果您的画布是一个 div 的子级,而后者又是另一个 div 的子级......那么故事就会变得更加复杂。 这是我在 div 的 2 个级别内的画布的代码:
canvas.addEventListener("click", function(event) {
var x = event.pageX - (this.offsetLeft + this.parentElement.offsetLeft);
var y = event.pageY - (this.offsetTop + this.parentElement.offsetTop);
console.log("relative x=" + x, "relative y" + y);
});
原来的答案说把它放在一个 iframe 中。 更好的解决方案是在填充设置为 0px 的画布上使用事件 offsetX 和 offsetY。
<html>
<body>
<script>
var main=document.createElement('canvas');
main.width="200";
main.height="300";
main.style="padding:0px;margin:30px;border:thick dashed red";
document.body.appendChild(main);
// adding event listener
main.addEventListener('mousemove',function(e){
var ctx=e.target.getContext('2d');
var c=Math.floor(Math.random()*0xFFFFFF);
c=c.toString(16); for(;c.length<6;) c='0'+c;
ctx.strokeStyle='#'+c;
ctx.beginPath();
ctx.arc(e.offsetX,e.offsetY,3,0,2*Math.PI);
ctx.stroke();
e.target.title=e.offsetX+' '+e.offsetY;
});
// it worked! move mouse over window
</script>
</body>
</html>
基于@Patrick Boos 解决方案,但修复了中间滚动条的潜在问题。
export function getRelativeCoordinates(event: MouseEvent, referenceElement: HTMLElement) {
const position = {
x: event.pageX,
y: event.pageY,
};
const offset = {
left: referenceElement.offsetLeft,
top: referenceElement.offsetTop,
};
let reference = referenceElement.offsetParent as HTMLElement;
while (reference) {
offset.left += reference.offsetLeft;
offset.top += reference.offsetTop;
reference = reference.offsetParent as HTMLElement;
}
const scrolls = {
left: 0,
top: 0,
};
reference = event.target as HTMLElement;
while (reference) {
scrolls.left += reference.scrollLeft;
scrolls.top += reference.scrollTop;
reference = reference.parentElement as HTMLElement;
}
return {
x: position.x + scrolls.left - offset.left,
y: position.y + scrolls.top - offset.top,
};
}
我必须在带有滚动条的非常宽的 div 中获取光标位置。 目标是将元素拖到 div 的任何位置。
将鼠标位置放在滚动深处的较远位置。
$('.canvas').on('mousemove', function(e){
$(dragElement).parent().css('top', e.currentTarget.scrollTop + e.originalEvent.clientY );
$(dragElement).parent().css('left', e.currentTarget.scrollLeft + e.originalEvent.clientX )
});
使用此方法快速获取鼠标位置:
Object.defineProperty(MouseEvent.prototype, "mouseX", {
get() {
return this.clientX - this.currentTarget.getBoundingClientRect().left;
}
});
Object.defineProperty(MouseEvent.prototype, "mouseY", {
get() {
return this.clientY - this.currentTarget.getBoundingClientRect().top;
}
});
例子:
document.body.onmousemove=function(e){console.log(e.mouseX,e.mouseY)}
因为如果您将 append 放入您有例如选择的父元素中,我没有找到可以帮助您获得它的解决方案。
这就是我所做的:
let positions = {
x: event.pageX,
y: event.pageY - event.currentTarget.getBoundingClientRect().top + event.currentTarget.offsetTop
}
这是我得到的。
$(".some-class").click(function(e) {
var posx = 0;
var posy = 0;
posx = e.pageX;
posy = e.pageY;
alert(posx);
alert(posy);
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.