JQuery получить позицию мыши внутри элемента

165

Я надеялся создать элемент управления, в котором пользователь мог бы щелкнуть внутри элемента div, затем перетащить мышь, а затем отпустить кнопку мыши, чтобы указать, как долго они хотят, чтобы что-то было. (Это для элемента управления календаря, поэтому пользователь будет указывать длительность определенного события)

Похоже, что лучший способ сделать это - зарегистрировать событие «mousedown» в родительском div, которое, в свою очередь, регистрирует событие «mousemove» в div, пока не будет запущено событие «mouseup». События «mousedown» и «mouseup» будут определять начало и конец временного диапазона, и, следуя событиям «mousemove», я могу динамически изменять размер диапазона, чтобы пользователь мог видеть, что он делает. Я основал это на том, как события создаются в календаре Google.

Проблема, с которой я столкнулся, заключается в том, что событие jQuery, по-видимому, предоставляет только надежную информацию о координатах мыши в отношении всей страницы. Есть ли способ узнать, какие координаты относятся к родительскому элементу?

Редактировать:

Вот картина того, что я пытаюсь сделать: альтернативный текст

Крис Датроу
источник

Ответы:

305

Один из способов заключается в использовании JQuery offsetметод перевести event.pageXи event.pageYкоординаты из события в положение мыши по отношению к родителю. Вот пример для дальнейшего использования:

$("#something").click(function(e){
   var parentOffset = $(this).parent().offset(); 
   //or $(this).offset(); if you really just want the current element's offset
   var relX = e.pageX - parentOffset.left;
   var relY = e.pageY - parentOffset.top;
});
jball
источник
2
Да, это отличная идея, если макет родительского элемента не может / не должен быть изменен!
Заостренный
2
Этот ответ учитывает отступы / границы?
LeeGee
10
Согласно документам, смещение не учитывает «границы, поля или отступы, установленные для элемента body». Я не столкнулся с проблемой с моим опубликованным ответом в использовании, но, возможно, было бы хорошо проверить, какие из них установлены.
Jball
2
Это не должно работать. offset()также относительна, поэтому, если родитель является дочерним элементом другого элемента, это даст неверный результат. Используйте position()вместо этого.
Вспышка грома
1
@FlashThunder offset () не является относительным, по крайней мере, не в соответствии с документацией. Также это должно быть стандартной практикой, чтобы не иметь никаких полей или отступов на элементе тела.
Джеймс Уоткинс
18

Чтобы получить позицию клика относительно текущего щелкаемого элемента
Используйте этот код

$("#specialElement").click(function(e){
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
}); 
Саджад Ашраф
источник
2
Ваш ответ помог мне, кстати, принятый ответ не сделал. Спасибо :) Вместо этого я использовал следующее: var y = e.pageY - $(this).offset().top;но ваш ответ привел меня на правильный путь.
Соломон Клоссон
11

Я использую этот кусок кода, это довольно приятно :)

    <script language="javascript" src="http://code.jquery.com/jquery-1.4.1.js" type="text/javascript"></script>
<script language="javascript">
$(document).ready(function(){
    $(".div_container").mousemove(function(e){
        var parentOffset = $(this).parent().offset();
        var relativeXPosition = (e.pageX - parentOffset.left); //offset -> method allows you to retrieve the current position of an element 'relative' to the document
        var relativeYPosition = (e.pageY - parentOffset.top);
        $("#header2").html("<p><strong>X-Position: </strong>"+relativeXPosition+" | <strong>Y-Position: </strong>"+relativeYPosition+"</p>")
    }).mouseout(function(){
        $("#header2").html("<p><strong>X-Position: </strong>"+relativeXPosition+" | <strong>Y-Position: </strong>"+relativeYPosition+"</p>")
    });
});
</script>
Мартен Хартман
источник
9

@AbdulRahim ответ почти правильный. Но я предлагаю функцию ниже в качестве замены (для дальнейшего использования):

function getXY(evt, element) {
                var rect = element.getBoundingClientRect();
                var scrollTop = document.documentElement.scrollTop?
                                document.documentElement.scrollTop:document.body.scrollTop;
                var scrollLeft = document.documentElement.scrollLeft?                   
                                document.documentElement.scrollLeft:document.body.scrollLeft;
                var elementLeft = rect.left+scrollLeft;  
                var elementTop = rect.top+scrollTop;

                x = evt.pageX-elementLeft;
                y = evt.pageY-elementTop;

                return {x:x, y:y};
            }




            $('#main-canvas').mousemove(function(e){
                var m=getXY(e, this);
                console.log(m.x, m.y);
            });
Пауло Буэно
источник
1
Блестящее улучшение, спасло мой день.
Буд Дамьянов
почти, добавьте поля к холсту, и вы ушли на полях
Бенн
Это отличный кусок кода, большое спасибо!
Стефан
7

Это решение поддерживает все основные браузеры, включая IE. Это также заботится о прокрутке. Во-первых, он получает позицию элемента относительно страницы эффективно, без использования рекурсивной функции. Затем он получает x и y щелчка мыши относительно страницы и выполняет вычитание, чтобы получить ответ, представляющий собой позицию относительно элемента (например, элемент может быть изображением или элементом div):

function getXY(evt) {
    var element = document.getElementById('elementId');  //replace elementId with your element's Id.
    var rect = element.getBoundingClientRect();
    var scrollTop = document.documentElement.scrollTop?
                    document.documentElement.scrollTop:document.body.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft?                   
                    document.documentElement.scrollLeft:document.body.scrollLeft;
    var elementLeft = rect.left+scrollLeft;  
    var elementTop = rect.top+scrollTop;

        if (document.all){ //detects using IE   
            x = event.clientX+scrollLeft-elementLeft; //event not evt because of IE
            y = event.clientY+scrollTop-elementTop;
        }
        else{
            x = evt.pageX-elementLeft;
            y = evt.pageY-elementTop;
    }
Абдул Рахим Хаддад
источник
3

Если вы сделаете свой родительский элемент «position: относительным», то он будет «родительским смещением» для материала, по которому вы отслеживаете события мыши. Таким образом, jQuery "position ()" будет относительно этого.

Заостренный
источник
Эй, Пойнти, спасибо за твой ответ. Исходя из вашей формулировки, звучит так, как будто вы предлагаете не то, что предложил jball, но я не понимаю, как, вы можете уточнить? Еще раз спасибо
Крис Датроу
@DutrowLLC, Pointy предлагает изменить стиль родительского элемента, чтобы иметь "position:relative". Позиция jQuery будет сообщать о своих позициях относительно родительского элемента, а не страницы. Формулировка в моем ответе плохая, она подразумевает, что она напрямую связана с решением Pointy, но это способ вычисления смещения, когда вы не можете или не хотите зависеть от атрибутов стиля родительского элемента.
Jball
Так что, если я установлю «position :lative», то jQuery сообщит корректно положение позиции во всех браузерах? Причина, по которой я спрашиваю, состоит в том, что документация jQuery, по-видимому, подразумевает, что единственное надежное положение мыши во всех браузерах - это положение относительно самого окна браузера.
Крис Датроу
Поле с позицией: относительный устанавливает параметры «верх» и «левый» (и т. Д.) Для дочерних блоков относительно прямоугольника содержимого родительского блока.
Заостренный
Возможно, я что-то делаю не так, но в Firefox это не работает. У меня есть «позиция: относительная»; в родительском файле firefox одинаково сообщает о event.pageX и event.clientX (относительно верхнего левого края страницы) и сообщает об отсутствии события как event.offsetX
Крис Датроу,
2

Вот тот, который также дает вам процентное положение точки в случае, если вам это нужно. https://jsfiddle.net/Themezly/2etbhw01/

function ThzhotspotPosition(evt, el, hotspotsize, percent) {
  var left = el.offset().left;
  var top = el.offset().top;
  var hotspot = hotspotsize ? hotspotsize : 0;
  if (percent) {
    x = (evt.pageX - left - (hotspot / 2)) / el.outerWidth() * 100 + '%';
    y = (evt.pageY - top - (hotspot / 2)) / el.outerHeight() * 100 + '%';
  } else {
    x = (evt.pageX - left - (hotspot / 2));
    y = (evt.pageY - top - (hotspot / 2));
  }

  return {
    x: x,
    y: y
  };
}



$(function() {

  $('.box').click(function(e) {

    var hp = ThzhotspotPosition(e, $(this), 20, true); // true = percent | false or no attr = px

    var hotspot = $('<div class="hotspot">').css({
      left: hp.x,
      top: hp.y,
    });
    $(this).append(hotspot);
    $("span").text("X: " + hp.x + ", Y: " + hp.y);
  });


});
.box {
  width: 400px;
  height: 400px;
  background: #efefef;
  margin: 20px;
  padding: 20px;
  position: relative;
  top: 20px;
  left: 20px;
}

.hotspot {
  position: absolute;
  left: 0;
  top: 0;
  height: 20px;
  width: 20px;
  background: green;
  border-radius: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
  <p>Hotspot position is at: <span></span></p>
</div>

Бенн
источник
-1

Я бы предложил это:

e.pageX - this.getBoundingClientRect().left
Эдуард
источник