Как получить значения x и y внутри определенного тега HTML? [Дубликат]

Интересно, что ни один из ответов на этой странице не упоминает два крайних случая, надеюсь, никто не возражает, если я их добавлю:

Случай с краем # 1: одновременный доступ к словарю

Родовые словари в .NET не являются потокобезопасными, а иногда могут бросать NullReference или даже (чаще) a KeyNotFoundException при попытке получить доступ к ключу из двух параллельных потоков. Исключение в этом случае является довольно ошибочным.

Случай с краем # 2: небезопасный код

Если код NullReferenceException задан кодом unsafe, вы можете посмотреть на переменные указателя , и проверьте их на IntPtr.Zero или что-то в этом роде. Это одно и то же («исключение нулевого указателя»), но в небезопасном коде переменные часто переводятся в типы значений / массивы и т. Д., И вы ударяете головой о стену, задаваясь вопросом, как тип значения может исключение.

(Еще одна причина для небезопасного использования небезопасного кода, если вам это нужно)

137
задан Ben Shelock 13 July 2010 в 05:47
поделиться

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 для каждой строки.

136
ответ дан David Riccitelli 26 August 2018 в 04:55
поделиться
  • 1
    Это сработало для вас @ben, я был бы признателен за «Правильный ответ». или комментарий о том, что еще не работает для вас. Может быть, я могу помочь дальше. – Spider 27 September 2012 в 22:28
  • 2
    Следует избегать использования $ ('selector') в обработчике событий, если вы не хотите очень вялого кода. Предварительно выберите свой элемент и используйте предварительно выбранную ссылку в вашем обработчике. То же самое для $ (window) делает это один раз и кэширует его. – Austin France 11 October 2013 в 17:35
  • 3
    это необязательно: если вы скопируете приведенный выше код, не забудьте исправить var y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop(); до var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop(); – Raj Nathani 1 January 2014 в 23:02
  • 4
    Как это может быть ответ, поскольку вопрос не имеет ничего общего с jQuery? – FlorianB 30 August 2016 в 12:57
  • 5
    Сокращенное из-за ответа jQuery – Doodlemeat 15 August 2017 в 15:14

Я задал этот вопрос в 2010 году, но никто, похоже, не удовлетворил его: в чистом javascript нет ответа, который возвращает относительные координаты, когда ссылочный элемент вложен внутри других, который может быть с абсолютным позиционированием. Вот мое решение:

var container = myReferenceElement;

function getRelativeCoordinates ( e ) {

    var pos = {}, offset = {}, ref;

    ref = container.offsetParent;

    pos.x = !! e.touches ? e.touches[ 0 ].pageX : e.pageX;
    pos.y = !! e.touches ? e.touches[ 0 ].pageY : e.pageY;

    offset.left = container.offsetLeft;
    offset.top = container.offsetTop;

    while ( ref ) {
        offset.left += ref.offsetLeft;
        offset.top += ref.offsetTop;
        ref = ref.offsetParent;
    }

    return { 
        x : pos.x - offset.left,
        y : pos.y - offset.top,
    }; 

}
13
ответ дан Atrahasis 26 August 2018 в 04:55
поделиться
  • 1
    Я не думаю, что он учитывает смещение элемента html – apieceofbart 21 October 2016 в 08:42

Вы должны знать структуру своей страницы, потому что если ваш холст является дочерним элементом 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
ответ дан Eli Mashiah 26 August 2018 в 04:55
поделиться

Поскольку я не нашел 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 полного примера

38
ответ дан Erik Koopmans 26 August 2018 в 04:55
поделиться

Ни один из вышеперечисленных ответов не является удовлетворительным 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
4
ответ дан FlorianB 26 August 2018 в 04:55
поделиться

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

2
ответ дан FutureSci 26 August 2018 в 04:55
поделиться
  • 1
    Спасибо, что являетесь единственным ответом на прокрутку. Попробуйте изменить свой ответ, чтобы добавить ось y. – frabjous 28 January 2018 в 17:30

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

onDragOver(event){
 var x = event.offsetX;
 var y = event.offsetY;
}
1
ответ дан John 26 August 2018 в 04:55
поделиться
  • 1
  • 2
    event.offsetX относится к элементу, в котором находится указатель мыши, а не к элементу, к которому прикреплен прослушиватель dragover. Если у вас нет вложенной структуры элементов, тогда это нормально, но если вы это сделаете, это не сработает. – opsb 5 August 2018 в 10:24

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

Есть только 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">
1
ответ дан John T. 26 August 2018 в 04:55
поделиться

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

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

17
ответ дан Joseph Marikle 26 August 2018 в 04:55
поделиться
  • 1
    К сожалению, это не удается, если происходит какое-то движение – Eric 22 March 2014 в 15:16
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 Developer Network:

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

1
ответ дан lama12345 26 August 2018 в 04:55
поделиться
  • 1
    Хотя этот фрагмент кода может решить вопрос, , включая объяснение , действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин вашего предложения кода. – Patrick Hund 20 August 2017 в 09:36
  • 2
    Я действительно надеюсь, что читатели в будущем будут иметь JS API, который вычисляет это для них. ;-) Это, наверное, самый простой, полный, автономный ответ. Комментирование самоочевидного кода просто отвлекает отходы. – lama12345 20 August 2017 в 09:59
  • 3
    Я второй запрос @ PatrickHund для объяснения. Я не эксперт по CSS / JS, и больше узнать о взаимоотношениях между, например, page и offset, было бы очень полезно для меня. Спасибо, что рассмотрели этот запрос! – cxw 13 September 2017 в 17:17
  • 4
    @cxw Хорошо, теперь вы являетесь вторым downvote (имеет 1 upvote) ... Я добавил длинное объяснение сейчас, это похоже на 10x до тех пор, пока 4 строки кода. Добро пожаловать, получайте удовольствие от чтения. Я рассмотрел ваш запрос! :п – lama12345 14 September 2017 в 13:17
  • 5
    @cxw Я перепутал, добавив дополнительный элемент с абсолютным позиционированием и заставив сам элемент canvas вне экрана, поэтому мне пришлось прокручивать его, например, влево / вправо 2000 пикселей на экране. Не удалось заставить этот код сломаться. – lama12345 14 September 2017 в 14:32

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

50
ответ дан LeeGee 26 August 2018 в 04:55
поделиться
  • 1
    Какие? IE9 поддерживает Canvas, что вы делаете неправильно? – Andrea 24 April 2012 в 23:00
  • 2
    Может быть, это я, но две строки кодов, которые используют ключевое слово "this & quot; отсутствие контекста? – Deratrius 24 September 2012 в 14:45
  • 3
    Определенно недостающий контекст. «e» - это событие, а «this» - это элемент, связанный с событием var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; } – Nick Bisby 20 May 2013 в 23:17
  • 4
    Это не работает, если какой-либо элемент потомка использует относительное или абсолютное позиционирование. – edA-qa mort-ora-y 15 December 2013 в 18:49
  • 5
    Вы можете отключить this до e.currentTarget, что даст вам позицию относительно элемента, к которому вы добавили прослушиватель событий. – Linus Unnebäck 31 July 2015 в 07:19

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

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

2
ответ дан Letokteren 26 August 2018 в 04:55
поделиться
  • 1
    Я бы поднял голову, но разве это не должно быть минус-знаками для смещения страницы? Либо это, либо круглые скобки вокруг второй части? – Chris Sunami 27 December 2017 в 16:20

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

FOllowing решил это для меня:

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

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

6
ответ дан Matt 26 August 2018 в 04:55
поделиться
  • 1
    +1 для вас! Это тот ответ, который я искал. У меня было два холста, наложенных друг на друга, и все координаты были неправильными из-за других div. Я знал, что это проблема, но не знает логики / уравнения, чтобы компенсировать это. Вы тоже исправили мою проблему! = D спасибо! – Partack 8 June 2013 в 10:30

Координаты мыши внутри холста могут быть получены благодаря 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>
    

1
ответ дан Nino Filiu 26 August 2018 в 04:55
поделиться

вы можете получить его с помощью

var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
    var xCoor = e.clientX;
    var yCoor = e.clientY;
}
1
ответ дан rob waminal 26 August 2018 в 04:55
поделиться
  • 1
    Будет ли это работать в IE или IE все еще использует window.event вместо передачи события первому аргументу слушателя? edit - Я думаю, IE не имеет элемент canvas в любом случае до версии 9, но это все равно, вероятно, будет поддерживать IE из-за таких вещей, как excanvas .... – Dagg Nabbit 13 July 2010 в 06:12
  • 2
    Это даст координаты относительно окна браузера, все равно нужно выяснить, находятся ли они в элементе, используя element.getBoundingClientRect () – David W. Keith 13 July 2010 в 06:13
  • 3
    спасибо, что заставило меня узнать о getBoundingClientRect !!!! Я никогда не понимал, что есть такая вещь! – Gershom Maes 23 June 2014 в 18:13

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

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 );
} );
2
ответ дан Sheljohn 26 August 2018 в 04:55
поделиться

Оригинальный ответ сказал, чтобы положить его в 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>
0
ответ дан Smertrios2007 26 August 2018 в 04:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: