jQuery ruft die Mausposition innerhalb eines Elements ab

165

Ich hatte gehofft, ein Steuerelement zu erstellen, mit dem ein Benutzer in ein Div klicken, dann die Maus ziehen und dann die Maus loslassen kann, um anzuzeigen, wie lange er etwas haben möchte. (Dies ist für ein Kalendersteuerelement vorgesehen, sodass der Benutzer die zeitliche Länge eines bestimmten Ereignisses angibt.)

Es sieht so aus, als ob der beste Weg, dies zu tun, darin besteht, ein "Mousedown" -Ereignis auf dem übergeordneten Div zu registrieren, das wiederum ein "Mousemove" -Ereignis auf dem Div registriert, bis ein "Mouseup" -Ereignis ausgelöst wird. Die Ereignisse "Mousedown" und "Mouseup" definieren den Beginn und das Ende des Zeitbereichs. Wenn ich "Mousemove" -Ereignisse verfolge, kann ich die Größe des Bereichs dynamisch ändern, damit der Benutzer sehen kann, was er tut. Ich habe dies darauf basiert, wie Ereignisse in Google Kalender erstellt werden.

Das Problem, das ich habe, ist, dass das jQuery-Ereignis nur zuverlässige Mauskoordinateninformationen in Bezug auf die gesamte Seite liefert. Gibt es eine Möglichkeit zu erkennen, welche Koordinaten sich auf das übergeordnete Element beziehen?

Bearbeiten:

Hier ist ein Bild von dem, was ich versuche zu tun: Alt-Text

Chris Dutrow
quelle

Antworten:

304

Eine Möglichkeit besteht darin, die jQuery- offsetMethode zu verwenden, um die event.pageXund event.pageY-Koordinaten des Ereignisses in eine Mausposition relativ zum übergeordneten Element zu übersetzen . Hier ist ein Beispiel für zukünftige Referenz:

$("#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
quelle
2
Ja, dies ist eine großartige Idee, wenn das Layout des übergeordneten Elements nicht geändert werden kann / sollte!
Pointy
2
Berücksichtigt diese Antwort Polsterungen / Ränder?
LeeGee
10
Laut den Dokumenten berücksichtigt der Versatz nicht "Ränder, Ränder oder Auffüllungen, die auf dem Körperelement festgelegt sind". Ich habe kein Problem mit meiner veröffentlichten Antwort festgestellt, aber es kann sinnvoll sein, zu überprüfen, ob diese festgelegt wurden.
Jball
2
Das muss nicht funktionieren. offset()ist auch relativ. Wenn also der Elternteil ein Kind eines anderen Elements ist, führt dies zu einem falschen Ergebnis. Verwenden Sie position()stattdessen.
Flash Thunder
1
@FlashThunder offset () ist nicht relativ, zumindest nicht gemäß den Dokumenten. Es sollte auch Standard sein, keine Ränder oder Polster am Körperelement zu haben.
James Watkins
18

So ermitteln Sie die Position des Klicks relativ zum aktuell angeklickten Element
Verwenden Sie diesen Code

$("#specialElement").click(function(e){
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
}); 
Sajjad Ashraf
quelle
2
Ihre Antwort hat mir übrigens geholfen, die akzeptierte Antwort nicht. Danke :) Was ich tatsächlich benutzt habe, ist stattdessen Folgendes: var y = e.pageY - $(this).offset().top;Aber deine Antwort hat mich auf den richtigen Weg geführt.
Solomon Closson
11

Ich benutze diesen Code, es ist ganz nett :)

    <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
quelle
9

@AbdulRahim Antwort ist fast richtig. Aber ich schlage die folgende Funktion als Ersatz vor (als weitere Referenz):

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
quelle
1
Geniale Verbesserung, hat mir den Tag gerettet.
Bud Damyanov
fast, fügen Sie Rand zur Leinwand hinzu und Sie sind am Rand weg
Benn
Dies ist ein großartiger Code, vielen Dank!
Stefan
7

Diese Lösung unterstützt alle gängigen Browser einschließlich IE. Es kümmert sich auch um das Scrollen. Zunächst wird die Position des Elements relativ zur Seite effizient und ohne Verwendung einer rekursiven Funktion abgerufen. Dann erhält es das x und y des Mausklicks relativ zur Seite und führt die Subtraktion durch, um die Antwort zu erhalten, bei der es sich um die Position relativ zum Element handelt (das Element kann beispielsweise ein Bild oder ein Div sein):

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
quelle
3

Wenn Sie Ihr übergeordnetes Element auf "Position: relativ" setzen, ist es das "übergeordnete Element" für das Material, über das Sie Mausereignisse verfolgen. Somit ist die jQuery "position ()" relativ dazu.

Spitze
quelle
Hey Pointy, danke für deine Antwort. Aufgrund Ihrer Formulierung klingt es so, als ob das, was Sie vorschlagen, anders ist als das, was jball vorgeschlagen hat, aber ich verstehe nicht, wie, können Sie das näher erläutern?
Nochmals vielen
@DutrowLLC, Pointy schlägt vor, den Stil des übergeordneten Elements zu ändern "position:relative". Die jQuery-Position würde dann ihre Positionen relativ zum übergeordneten Element und nicht zur Seite melden. Der Wortlaut meiner Antwort ist schlecht, er impliziert, dass er in direktem Zusammenhang mit Pointys Lösung steht, aber er ist eine Methode zur Berechnung des Versatzes, wenn Sie nicht von den Stilattributen des übergeordneten Elements abhängen können oder wollen.
Jball
Wenn ich also "position: relative" setze, meldet jQuery die relatiove Position in allen Browsern korrekt? Der Grund, den ich frage, ist, dass die jQuery-Dokumentation zu implizieren schien, dass die einzige zuverlässige Mausposition in allen Browsern die in Bezug auf das Browserfenster selbst war.
Chris Dutrow
Bei einem Feld mit "Position: relativ" werden die Einstellungen "oben" und "links" (usw.) für untergeordnete Felder relativ zum Inhaltsrechteck des relativen übergeordneten Felds festgelegt.
Pointy
Ich mache vielleicht etwas falsch, aber dies scheint in Firefox nicht zu funktionieren. Ich habe "Position: relativ;" Firefox meldet event.pageX und event.clientX identisch (oben links auf der Seite) und meldet event.offsetX als undefiniert
Chris Dutrow
2

Hier ist eine, die Ihnen auch die prozentuale Position des Punktes gibt, falls Sie ihn benötigen. 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
quelle
-1

Ich würde dies vorschlagen:

e.pageX - this.getBoundingClientRect().left
Eduard
quelle