Найти положение мыши относительно элемента

244

Я хочу сделать небольшое приложение для рисования, используя холст. Поэтому мне нужно найти положение мыши на холсте.

Бен Шелок
источник
2
Полное решение: acko.net/blog/...
EDA-QA Mort-ор-й
3
Я люблю, как коротко, но объясняет все, что этот пост.
dwjohnston
Это действительно старый, но я только начал проект GitHub, который, помимо прочего, делает именно то, что вам нужно: brainlessdeveloper.com/mouse-move-interaction-spot-js
Fausto NA,

Ответы:

177

Для людей, использующих 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каждую строку.

Обновить

Ниже приведена более новая версия только для JavaScript от @anytimecoder ниже для браузеров, поддерживающих getBoundingClientRect () .

sparkyspider
источник
7
Это сработало для вас @ben, я был бы признателен за «Правильный ответ» или комментарий о том, что все еще не работает для вас. Может быть, я могу помочь дальше.
sparkyspider
8
Следует избегать использования $ ('selector') в обработчике событий, если вы не хотите очень вялый код. Предварительно выберите ваш элемент и используйте предварительно выбранную ссылку в вашем обработчике. То же самое для $ (окно) сделать это один раз и кешировать его.
Остин, Франция,
2
это не является необходимым отметить: если вы копировать вставить код выше, не забудьте исправить var y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop();доvar y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Радж Nathani
77
Как это может быть ответом, так как вопрос не имеет ничего общего с jQuery?
FlorianB
2
@ Чёрный, но некоторые люди спрашивают вещи в javascript вместо jquery, потому что jquery может быть несовместим в их среде.
dbrree
307

Поскольку я не нашел ответ без 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.
}

JSFiddle полного примера

anytimecoder
источник
2
Вы должны округлить ограничивающий прямоугольник, чтобы обеспечить целочисленные значения с помощью этого метода.
Джейк Кобб,
2
Новое редактирование должно исправить проблемы с прокруткой (используя clientX / Y)
Эрик Купманс
6
Этот ответ должен быть поставлен на голосование. Спасибо в любое время кодировщик и @ErikKoopmans.
Иван
3
PSA: комментарий @mpen устарел; Этот метод работает, даже в случаях с прокруткой. Смотрите обновленную версию своей скрипки: jsfiddle.net/6wcsovp2
Xharlie
4
Спасибо! Одно замечание: вам нужно e.currentTarget, а не e.target. Иначе на это будут влиять дочерние элементы
Максим Георгиевский
60

Далее вычисляется отношение позиции мыши к элементу 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событием.

LindaQ
источник
83
Может быть, это я, но две строки кодов, которые используют ключевое слово "это", лишены контекста?
Дератрий
9
Определенно не хватает контекста. «e» - это событие, а «this» - элемент, к которому привязано событие var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; }
Ник Бисби,
22
Это не работает, если какой-либо дочерний элемент использует относительное или абсолютное позиционирование.
edA-qa mort-ora-y
12
Вы можете переключиться thisна e.currentTarget, чтобы получить положение относительно элемента, к которому вы добавили прослушиватель событий.
Линус Уннебек
2
Похоже, что это дает отношение к видимой части элемента, а не ко всему элементу. Есть ли способ приспособиться к этому, если часть элемента не видна в области просмотра и имеются полосы прокрутки и т. Д.?
frabjous
37

В чистом 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,
  }; 

}
Atrahasis
источник
3
Я не думаю, что это принимает во внимание htmlсмещение элемента
apieceofbart
3
Прекрасно работает с прокруткой контейнеров, с небольшим изменением: заменить while(reference !== undefined)на while(reference). По крайней мере, в Chrome, offsetParent не заканчивается undefined, но null. Просто проверка, referenceявляется ли правдивым, гарантирует, что это работает с обоими undefinedи null.
blex
Я бы дал еще +1, если бы мог, потому что дал мне знать, что есть offsetParentсвойство, которое оказывается очень полезным и в других ситуациях!
FonzTech
В общем, проверка на undefined обычно плохая идея
Хуан Мендес,
Я думаю, что вы должны вычесть scrollLeftи scrollTopкомпенсировать прокрутить потомков.
Роберт
20

Хорошее описание сложности этой проблемы можно найти здесь: http://www.quirksmode.org/js/events_properties.html#position

Используя описанную там технику, вы можете найти позицию мыши в документе. Тогда вы просто проверить, если он находится внутри ограничивающей рамки вашего элемента, который вы можете найти по призванию , element.getBoundingClientRect()который будет возвращать объект со следующими свойствами: { bottom, height, left, right, top, width }. Отсюда легко понять, произошло ли событие внутри вашего элемента или нет.

Дэвид В. Кит
источник
1
К сожалению, это терпит неудачу, если происходит какое-либо вращение
Эрик
17

Я испробовал все эти решения, и из-за моей специальной настройки с контейнером с матричной трансформацией (библиотека panzoom) ни один из них не работал. Это возвращает правильное значение, даже если масштабирование и панорамирование:

mouseevent(e) {
 const x = e.offsetX,
       y = e.offsetY
}

Но только если на пути нет дочерних элементов. Это можно обойти, сделав их «невидимыми» для события, используя CSS:

.child {
   pointer-events: none;
}
Фабиан фон Эллертс
источник
3
Это определенно способ сделать это в 2019 году. Другие ответы загружены старым грубым багажом.
Колин Д.
1
@ColinD спасибо! Я забыл добавить, что это также работает в IE11.
Фабиан фон Эллертс
Это сработало для меня. Тем не менее, я подозреваю, что 1) несколько голосов "за" 2) ответы с более высоким рейтингом намного сложнее и 3) я не вижу никаких объяснений недостатков. Кто-нибудь знает какие-либо недостатки использования этого подхода?
Mark E
1
@MarkE В этом нет ничего подозрительного. Это одна из многих ошибок StackOverflow. Ответы, которые вы видите вверху, были опубликованы за много лет до этого ответа, поэтому они набрали огромный импульс при голосовании. Как только ответ набирает обороты, обойти его довольно сложно и довольно редко.
Джек Гиффин
9

Я наткнулся на этот вопрос, но для того , чтобы заставить его работать на моем случае ( с использованием DragOver на DOM-элемент (не будучи холст в моем случае)), я обнаружил , что у вас есть только использовать offsetXи offsetYна события DragOver-мыши ,

onDragOver(event){
 var x = event.offsetX;
 var y = event.offsetY;
}
Джон
источник
2
это отлично сработало для меня. почему никто не проголосовал за это? Интересно, есть ли подводные камни? Если я найду что-нибудь, я доложу!
сибас
7
Параметр event.offsetX относится к элементу, над которым в данный момент находится указатель мыши, а не к элементу, к которому подключен прослушиватель dragover. Если у вас нет структуры вложенных элементов, тогда это нормально, но если у вас есть, то это не сработает.
opsb
7

Я +1 'Марк Марк Вик ответил, так как он направил меня в правильном направлении, но не совсем решил для меня. У меня все еще было смещение при рисовании элементов, содержащихся в другом элементе.

Следующие решили это для меня:

        x = e.pageX - this.offsetLeft - $(elem).offset().left;
        y = e.pageY - this.offsetTop - $(elem).offset().top;

Другими словами - я просто сложил все смещения из всех вложенных элементов

Matt
источник
+1 для вас! Это ответ, который я искал. У меня было два холста, сложенных друг на друга, и все координаты были неправильными из-за других элементов. Я знал, что это была проблема, но не знал логики / уравнения, чтобы компенсировать это. Вы только что исправили мою проблему! = D спасибо!
Partack
5

Ни один из приведенных выше ответов не является удовлетворительным 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);
}

И если вам когда-либо понадобится узнать текущую позицию прокрутки Y страницы:

var yscroll = window.pageYOffset
        || (document.documentElement && document.documentElement.scrollTop)
        || document.body.scrollTop; // scroll Y position in page
FlorianB
источник
4

Для тех из вас, кто разрабатывает обычные веб-сайты или PWA (Progressive Web Apps) для мобильных устройств и / или ноутбуков / мониторов с сенсорными экранами, вы попали сюда, потому что вы могли бы привыкнуть к событиям мыши и плохо знакомы с иногда болезненным опытом Touch события ... ууу!

Всего 3 правила:

  1. Делайте как можно меньше во время mousemoveили touchmoveсобытия.
  2. Делайте как можно больше во время mousedownили touchstartсобытия.
  3. Отмените распространение и запретите значения по умолчанию для событий касания, чтобы предотвратить запуск событий мыши на гибридных устройствах.

Излишне говорить, что с 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">
Джон Т.
источник
3

Вы можете получить это по

var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
    var xCoor = e.clientX;
    var yCoor = e.clientY;
}
грабить ваминала
источник
Будет ли это работать в IE или IE по-прежнему будет использовать window.event вместо передачи события первому аргументу слушателя? редактировать - я думаю, что IE все еще не хватает элемента canvas до версии 9, но, вероятно, он все еще должен поддерживать IE из-за таких вещей, как excanvas ....
Dagg Nabbit
21
Это даст координаты относительно окна браузера, все равно нужно выяснить, находятся ли они в элементе, используя element.getBoundingClientRect ()
Дэвид В. Кит
спасибо, что сообщили мне о getBoundingClientRect !!!! Я никогда не осознавал, что такое было!
Гершом
@ DavidW.Keith комментарий действительно следует считать правильным ответом!
Ульрик. S
3

Взятые из этого урока , с исправлениями, сделанными благодаря верхнему комментарию:

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 );
} );
Джонатан Х
источник
3

Я понимаю, что немного опоздал, но это работает с 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 области просмотра найдено с window.pageXOffset.

FutureSci
источник
1
Спасибо за то, что вы единственный, кто задумался о прокрутке. Вы также можете изменить свой ответ, чтобы добавить ось Y.
18:30
3

Основываясь на решении @ 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;
}

Это работает как с прокруткой, так и с масштабированием (в этом случае иногда он возвращает значения с плавающей точкой).

Letokteren
источник
Я бы высказался, но разве это не должно быть знаком минус для смещений страниц? Или это, или круглые скобки вокруг второй части?
Крис Сунами поддерживает Монику
1

Координаты мыши внутри холста могут быть получены благодаря 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 накладывает холст, как сказал @opsb
Дэвид
1
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не будет представлять собой ограничивающий прямоугольником для диапазона с обернутым текстом.

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

lama12345
источник
Хотя этот фрагмент кода может решить вопрос, в том числе объяснение действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код.
Патрик
Я действительно надеюсь, что у читателей в будущем будет JS API, который рассчитывает это для них. ;-) Это, наверное, самый простой, полный, самостоятельный ответ. Комментирование понятного кода просто отвлекает.
lama12345
Я второй запрос @ PatrickHund для объяснения. Я не эксперт по CSS / JS, и знаю больше о взаимоотношениях, например, pageи offsetбыло бы очень полезно для меня. Спасибо за рассмотрение этого запроса!
cxw
@cxw Хорошо, теперь вы второй понижатель (с 1 повышением) ... Теперь я добавил длинное объяснение, это примерно в 10 раз больше, чем 4 строки кода. Добро пожаловать, приятного чтения. Я рассмотрел ваш запрос! : p
lama12345
1
@cxw Я бездельничал, добавляя дополнительный элемент с абсолютным позиционированием и заставляя сам элемент canvas за пределами экрана, так что мне пришлось прокрутить его, как влево / top 2000px за кадром. Не удалось получить этот код, чтобы сломаться.
lama12345
1

Я реализовал другое решение, которое мне кажется очень простым, поэтому я решил поделиться с вами, ребята.

Таким образом, проблема для меня заключалась в том, что перетаскиваемый div переместился бы к 0,0 для курсора мыши. Поэтому мне нужно было зафиксировать положение мышей в div, чтобы настроить div в новой позиции.

Я читаю divs 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,
            });
          }

Надеюсь, это поможет кому-то, кто пережил те же проблемы, что и я :)

Атинодорос Сгуромаллис
источник
1
function myFunction(e) {
    var x =  e.clientX - e.currentTarget.offsetLeft ; 
    var y = e.clientY - e.currentTarget.offsetTop ;
}

это работает хорошо!

M9J_cfALt
источник
0

Вы должны знать структуру своей страницы, потому что, если ваш холст является потомком div, который, в свою очередь, является потомком другого div ... тогда история становится более сложной. Вот мой код для холста, который находится внутри двух уровней 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);

});

Эли Машиах
источник
0

Оригинальный ответ сказал, чтобы поместить его в 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>
Smertrios2007
источник
0

Вот что я получил.

    $(".some-class").click(function(e) {

    var posx = 0;
    var posy = 0;

    posx = e.pageX;
    posy = e.pageY;

    alert(posx);
    alert(posy);
});
Shmoo
источник
0

Вы можете использовать getBoudingClientRect()в relativeродителе.

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)
})
BrieucKyo
источник