jQuery pobiera pozycję myszy w elemencie

165

Miałem nadzieję, że uda mi się stworzyć kontrolę, w której użytkownik mógłby kliknąć wewnątrz elementu div, a następnie przeciągnąć myszą, a następnie zwolnić przycisk myszy, aby wskazać, jak długo chce, aby coś było. (To jest dla kontrolki kalendarza, więc użytkownik będzie wskazywał długość w czasie określonego zdarzenia)

Wygląda na to, że najlepszym sposobem na zrobienie tego byłoby zarejestrowanie zdarzenia „mousedown” w nadrzędnym elemencie div, który z kolei rejestruje zdarzenie „mousemove” w elemencie div do momentu wywołania zdarzenia „mouseup”. Zdarzenia „mousedown” i „mouseup” definiują początek i koniec zakresu czasowego, a śledząc zdarzenia „mousemove”, mogę dynamicznie zmieniać rozmiar zakresu, aby użytkownik mógł zobaczyć, co robi. Oparłem to na tym, jak wydarzenia są tworzone w kalendarzu Google.

Problem polega na tym, że zdarzenie jQuery wydaje się dostarczać wiarygodnych informacji o współrzędnych myszy tylko w odniesieniu do całej strony. Czy istnieje sposób, aby rozpoznać, jakie współrzędne odnoszą się do elementu nadrzędnego?

Edytować:

Oto zdjęcie tego, co próbuję zrobić: tekst alternatywny

Chris Dutrow
źródło

Odpowiedzi:

305

Jednym ze sposobów jest użycie offsetmetody jQuery do przetłumaczenia współrzędnych event.pageXi event.pageYze zdarzenia na pozycję myszy względem elementu nadrzędnego. Oto przykład do wykorzystania w przyszłości:

$("#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
źródło
2
Tak, to świetny pomysł, jeśli układ elementu nadrzędnego nie może / nie powinien zostać zmieniony!
Pointy
2
Czy ta odpowiedź uwzględnia dopełnienie / obramowanie?
LeeGee
10
Zgodnie z dokumentacją, przesunięcie nie uwzględnia „obramowań, marginesów ani dopełnienia ustawionych w elemencie body”. Nie napotkałem problemu z moją opublikowaną odpowiedzią w użyciu, ale warto sprawdzić, czy są one ustawione.
jball
2
To nie musi działać. offset()jest również względna, więc jeśli rodzic jest dzieckiem innego elementu, da to zły wynik. Użyj position()zamiast tego.
Flash Thunder
1
@FlashThunder offset () nie jest względne, przynajmniej nie zgodnie z dokumentacją. Standardową praktyką powinno być również brak marginesów lub wyściółki na elemencie body.
James Watkins
18

Aby uzyskać pozycję kliknięcia względem aktualnie klikniętego elementu
Użyj tego kodu

$("#specialElement").click(function(e){
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
}); 
Sajjad Ashraf
źródło
2
Twoja odpowiedź pomogła mi przy okazji, przyjęta odpowiedź nie. Dzięki :) Właściwie to zamiast tego użyłem: var y = e.pageY - $(this).offset().top;Ale twoja odpowiedź poprowadziła mnie na właściwą ścieżkę.
Solomon Closson,
11

Używam tego fragmentu kodu, jest całkiem fajny :)

    <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>
Maarten Hartman
źródło
9

@AbdulRahim odpowiedź jest prawie poprawna. Ale proponuję poniższą funkcję jako substytut (dla dalszego odniesienia):

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);
            });
Paulo Bueno
źródło
1
Genialna poprawa, uratowała mi dzień.
Bud Damyanov
prawie, dodaj margines do płótna i jesteś poza marginesem
Benn
To świetny fragment kodu, bardzo dziękuję!
Stefan
7

To rozwiązanie obsługuje wszystkie główne przeglądarki, w tym IE. Dba również o przewijanie. Po pierwsze, wydajnie pobiera pozycję elementu względem strony i bez użycia funkcji rekurencyjnej. Następnie pobiera x i y kliknięcia myszą względem strony i wykonuje odejmowanie, aby uzyskać odpowiedź, która jest pozycją względem elementu (element może być na przykład obrazem lub 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;
    }
Abdul Rahim Haddad
źródło
3

Jeśli ustawisz swój element nadrzędny na „position: relative”, będzie to „offsetowy element nadrzędny” dla rzeczy, nad którymi śledzisz zdarzenia myszy. Zatem jQuery „position ()” będzie do tego odniesiona.

Spiczasty
źródło
Hej Pointy, dziękuję za odpowiedź. W oparciu o twoje sformułowanie brzmi, że to, co sugerujesz, różni się od tego, co zasugerował jball, ale nie rozumiem, jak możesz to rozwinąć?
Jeszcze
@DutrowLLC, Pointy sugeruje zmianę stylu elementu nadrzędnego "position:relative". Pozycja jQuery zgłosiłaby wówczas swoje pozycje względem elementu nadrzędnego, a nie strony. Sformułowanie mojej odpowiedzi jest słabe, sugeruje, że jest bezpośrednio związane z rozwiązaniem Pointy'ego, ale jest to sposób obliczania przesunięcia, gdy nie możesz lub nie chcesz polegać na atrybutach stylu elementu nadrzędnego.
jball
Więc jeśli ustawię „position: względna”, jQuery będzie poprawnie raportować relatywną pozycję we wszystkich przeglądarkach? Pytam o to, ponieważ dokumentacja jQuery zdawała się sugerować, że jedyną niezawodną pozycją myszy we wszystkich przeglądarkach była ta w odniesieniu do samego okna przeglądarki.
Chris Dutrow
Ramka z opcją „pozycja: względna” spowoduje ustawienie „góry” i „lewej” (itp.) Dla pól podrzędnych w odniesieniu do prostokąta zawartości względnego pola nadrzędnego.
Pointy
Być może robię coś nie tak, ale to nie działa w przeglądarce Firefox. Mam "stanowisko: względne;" ustawiony w nadrzędnym, firefox raportuje event.pageX i event.clientX identycznie (w odniesieniu do góry, po lewej stronie) i raportuje event.offsetX jako niezdefiniowane
Chris Dutrow
2

Oto taki, który podaje również procentową pozycję punktu, na wypadek, gdybyś jej potrzebował. 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>

Benn
źródło
-1

Sugerowałbym to:

e.pageX - this.getBoundingClientRect().left
Eduard
źródło