17 ответов:
для людей, использующих 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для каждой строки.
следующее вычисляет отношение положения мыши к элементу canvas:
var example = document.getElementById('example'); example.onmousemove = function(e) { var x = e.pageX - this.offsetLeft; var y = e.pageY - this.offsetTop; }в этом примере
thisотносится кexampleэлемент иe- этоonmousemoveсобытие.
поскольку я не нашел ответа без jQuery, который я мог бы скопировать / вставить, вот решение, которое я использовал:
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. }
хорошее описание сложности этой проблемы можно найти здесь:http://www.quirksmode.org/js/events_properties.html#position
используя метод, описанный там, вы можете найти положение мыши в документе. Затем вы просто проверяете, находится ли он внутри ограничивающего поля вашего элемента, который вы можете найти, вызвав элемент.getBoundingClientRect (), который возвращает объект со следующими свойствами: { bottom, height, left, right, сверху, по ширине }. Оттуда тривиально выяснить, произошло ли это даже внутри вашего элемента или нет.
Я нашел этот вопрос, заданный в 2010 году, но никто, похоже, не удовлетворил его : в чистом javascript нет ответа, который возвращает относительные координаты, когда ссылочный элемент вложен в другие, которые могут быть с абсолютным позиционированием. Вот мое решение :
function getRelativeCoordinates (event, element){ const position = { x: event.pageX, y: event.pageY }; const offset = { left: element.offsetLeft, top: element.offsetTop; }; let reference = element.offsetParent; while(reference !== undefined){ offset.left += reference.offsetLeft; offset.top += reference.offsetTop; reference = reference.offsetParent; } return { x: position.x - offset.left, y: position.y - offset.top, }; }
I +1 ' Ответ Марка ван Вика, поскольку он получил меня в правильном направлении, но не совсем решил его для меня. У меня все еще было смещение при рисовании в элементах, содержащихся в другом элементе.
следующий решил это для меня:
x = e.pageX - this.offsetLeft - $(elem).offset().left; y = e.pageY - this.offsetTop - $(elem).offset().top;другими словами-Я просто сложил все смещения из всех вложенных элементов
ни один из приведенных выше ответов не является удовлетворительным ИМО, поэтому вот что я использую:
// 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); }и если вам когда-нибудь понадобится узнать текущую позицию прокрутки страницы Y :
var yscroll = window.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; // scroll Y position in page
Я понимаю , что немного опоздал, но это работает с чистым 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.
я столкнулся с этим вопросом, но для того, чтобы он работал для моего случая (используя dragover на DOM-элементе (не будучи холстом в моем случае)), я обнаружил, что вам нужно только использовать
offsetXиoffsetYна событие dragover-mouse.onDragOver(event){ var x = event.offsetX; var y = event.offsetY; }
принято от в этом уроке, с исправлениями, сделанными благодаря верхнему комментарию:
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 ); } );
координаты мыши внутри холста могут быть получены благодаря событию.смещение и событие.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>
основываясь на решении @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; }это работает как с прокруткой, так и с масштабированием (в этом случае иногда он возвращает поплавки).
для тех из вас, кто разрабатывает обычные веб-сайты или PWAs (прогрессивные веб-приложения) для мобильных устройств и/или ноутбуков/мониторов с сенсорными экранами, тогда вы приземлились здесь, потому что вы можете использовать события мыши и новичок в Иногда болезненном опыте сенсорных событий... ура!
есть только 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">
вы можете сделать это с помощью
var element = document.getElementById(canvasId); element.onmousemove = function(e) { var xCoor = e.clientX; var yCoor = e.clientY; }
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
The
HTMLElement.offsetLeftсвойство только для чтения возвращает количество пикселей, что верхний левый угол текущего элемента смещено влево в пределахHTMLElement.offsetParentузел.для элементов уровня блока,
offsetTop,offsetLeft,offsetWidthиoffsetHeightопишите поле границы элемента относительноoffsetParent.однако, для элементов встроенного уровня (таких как
span) который может обернуть от одной линии к следующий,offsetTopиoffsetLeftопишите положение первого поля границы (используйтеElement.getClientRects()чтобы получить его ширину и высоту), в то время какoffsetWidthиoffsetHeightопишите размеры ограничительной рамки (используйтеElement.getBoundingClientRect()чтобы получить свои позиции). Поэтому ящик с левой, верхней, шириной и высотойoffsetLeft,offsetTop,offsetWidthиoffsetHeightне будет ограничивающим прямоугольником для диапазона с обернутым текстом.HTMLElement.offsetTop
The
HTMLElement.offsetTopтолько для чтения свойство возвращает расстояние текущего элемента относительно вершиныoffsetParentузел.MouseEvent.pageX
The
pageXсвойство только для чтения возвращает координату X (горизонтальную) в пикселях события относительно всего документа. Это свойство учитывает любую горизонтальную прокрутку страницы.MouseEvent.pageY
The
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
вы должны знать структуру своей страницы, потому что если ваш холст является дочерним элементом div, который, в свою очередь, является дочерним элементом другого div... тогда история становится более сложной. Вот мой код для холста, который находится внутри 2 уровней div s:
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. Лучшим решением является использование событий offsetX и offsetY на холсте, который имеет заполнение, установленное в 0px.
<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>
Comments