jQuery ottiene la posizione del mouse all'interno di un elemento


165

Speravo di creare un controllo in cui un utente potesse fare clic all'interno di un div, quindi trascinare il mouse, quindi rilasciare il mouse per indicare per quanto tempo vogliono qualcosa. (Questo è per un controllo del calendario, quindi l'utente indicherà la lunghezza, nel tempo, di un determinato evento)

Sembra che il modo migliore per farlo sia quello di registrare un evento "mousedown" sul div parent che a sua volta registra un evento "mousemove" sul div fino a quando non viene attivato un evento "mouseup". Gli eventi "mousedown" e "mouseup" definiranno l'inizio e la fine dell'intervallo di tempo e mentre seguo gli eventi "mousemove", posso cambiare dinamicamente le dimensioni dell'intervallo in modo che l'utente possa vedere cosa stanno facendo. Ho basato questo su come gli eventi vengono creati nel calendario di Google.

Il problema che sto riscontrando è che l'evento jQuery sembra fornire solo informazioni affidabili sulle coordinate del mouse in riferimento all'intera pagina. C'è un modo per discernere quali sono le coordinate in riferimento all'elemento genitore?

Modificare:

Ecco una foto di quello che sto cercando di fare: testo alternativo

Risposte:


305

Un modo è utilizzare il offsetmetodo jQuery per tradurre le coordinate event.pageXe event.pageYdall'evento in una posizione del mouse rispetto al genitore. Ecco un esempio per riferimento futuro:

$("#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;
});

2
Sì, questa è un'ottima idea se il layout dell'elemento genitore non può / non deve essere modificato!
Punta il

2
Questa risposta tiene conto dell'imbottitura / dei bordi?
LeeGee,

10
Secondo i documenti, l' offset non tiene conto di "bordi, margini o imbottitura impostati sull'elemento body". Non ho riscontrato un problema con la mia risposta pubblicata in uso, ma potrebbe essere utile verificare se sono stati impostati.
jball,

2
Questo non deve funzionare. offset()è anche relativo, quindi se il genitore è figlio di un altro elemento, questo darà risultati errati. Usa position()invece.
Flash Thunder,

1
@FlashThunder offset () non è relativo, almeno non secondo i documenti. Inoltre, dovrebbe essere prassi normale non avere margini o imbottiture sull'elemento del corpo.
James Watkins,

18

Per ottenere la posizione del clic rispetto all'elemento attualmente selezionato Fare clic su
questo codice

$("#specialElement").click(function(e){
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
}); 

2
La tua risposta mi ha aiutato BTW, la risposta accettata no. Grazie :) Quello che ho effettivamente usato è questo, invece: var y = e.pageY - $(this).offset().top;Ma la tua risposta mi ha portato sulla strada giusta.
Solomon Closson,

11

Uso questo pezzo di codice, è abbastanza carino :)

    <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

La risposta di @AbdulRahim è quasi corretta. Ma suggerisco la seguente funzione come sostituto (per ulteriori riferimenti):

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
Miglioramento brillante, mi ha salvato la giornata.
Bud Damyanov,

quasi, aggiungi margine alla tela e sei fuori dal margine
Benn,

Questo è un ottimo pezzo di codice, grazie mille!
Stefan,

7

Questa soluzione supporta tutti i principali browser, incluso IE. Si occupa anche dello scorrimento. Innanzitutto, recupera la posizione dell'elemento rispetto alla pagina in modo efficiente e senza utilizzare una funzione ricorsiva. Quindi ottiene la xey del clic del mouse rispetto alla pagina e fa la sottrazione per ottenere la risposta che è la posizione relativa all'elemento (l'elemento può essere ad esempio un'immagine o 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

Se rendi il tuo elemento genitore "posizione: relativo", sarà il "genitore compensato" per le cose su cui stai monitorando gli eventi del mouse. Pertanto, jQuery "position ()" sarà relativo a quello.


Ehi a punta, grazie per la tua risposta. Sulla base della tua formulazione, sembra che ciò che stai suggerendo sia diverso da quello che Jball ha suggerito, ma non capisco come, puoi elaborare? Grazie ancora
Chris Dutrow il

@DutrowLLC, Pointy suggerisce di cambiare lo stile dell'elemento genitore da avere "position:relative". La posizione jQuery segnalerà quindi le sue posizioni relative all'elemento principale, non alla pagina. La formulazione sulla mia risposta è scarsa, implica che è direttamente correlata alla soluzione di Pointy, ma è un modo per calcolare l'offset quando non puoi o non vuoi dipendere dagli attributi di stile dell'elemento genitore.
Jball

Quindi se imposto "position: relative" jQuery riporterà correttamente la posizione relativa in tutti i browser? Il motivo per cui lo chiedo è perché la documentazione di jQuery sembrava implicare che l'unica posizione affidabile del mouse in tutti i browser fosse quella relativa alla finestra del browser stesso.
Chris Dutrow,

Una casella con "position: relative" eseguirà le impostazioni "top" e "left" (ecc.) Per le caselle figlio in relazione al rettangolo del contenuto della relativa casella genitore.
Pointy,

Potrei fare qualcosa di sbagliato, ma questo non sembra funzionare in Firefox. Ho "position: relative;" impostato nel genitore, firefox riporta event.pageX ed event.clientX in modo identico (rispetto alla parte superiore, a sinistra della pagina) e segnala event.offsetX come non definito
Chris Dutrow,

2

Eccone uno che fornisce anche la posizione percentuale del punto nel caso in cui ne abbiate bisogno. 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

Vorrei suggerire questo:

e.pageX - this.getBoundingClientRect().left
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.