jQuery obtiene la posición del mouse dentro de un elemento


165

Esperaba crear un control en el que un usuario pudiera hacer clic dentro de un div, luego arrastrar el mouse y luego soltar el mouse para indicar cuánto tiempo quieren que sea algo. (Esto es para un control de calendario, por lo que el usuario indicará la duración, a tiempo, de un determinado evento)

Parece que la mejor manera de hacer esto sería registrar un evento "mousedown" en el div padre que a su vez registra un evento "mousemove" en el div hasta que se active un evento "mouseup". Los eventos "mousedown" y "mouseup" definirán el inicio y el final del rango de tiempo y, a medida que sigo los eventos de "mousemove", puedo cambiar dinámicamente el tamaño del rango para que el usuario pueda ver lo que está haciendo. Basé esto en cómo se crean los eventos en Google Calendar.

El problema que tengo es que el evento jQuery parece proporcionar solo información confiable de coordenadas del mouse en referencia a toda la página. ¿Hay alguna manera de discernir cuáles son las coordenadas en referencia al elemento padre?

Editar:

Aquí hay una foto de lo que estoy tratando de hacer: texto alternativo

Respuestas:


305

Una forma es usar el offsetmétodo jQuery para traducir las coordenadas event.pageXy event.pageYdel evento a la posición del mouse en relación con el padre. Aquí hay un ejemplo para referencia futura:

$("#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í, esta es una gran idea si el diseño del elemento padre no puede / no debe cambiarse.
Puntiagudo

2
¿Esta respuesta tiene en cuenta el relleno / bordes?
LeeGee

10
Según los documentos, el desplazamiento no tiene en cuenta "los bordes, los márgenes o el relleno del conjunto de elementos". No he encontrado un problema con mi respuesta publicada en uso, pero podría ser bueno verificar si están configuradas.
jball

2
Esto no tiene que funcionar. offset()también es relativo, por lo que si el padre es hijo de otro elemento, esto dará un resultado incorrecto. Usar en su position()lugar.
Flash Thunder

1
@FlashThunder offset () no es relativo, al menos no según los documentos. También debería ser una práctica estándar no tener márgenes o relleno en el elemento del cuerpo.
James Watkins el

18

Para obtener la posición del clic en relación con el elemento seleccionado actual
Use este código

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

2
Su respuesta me ayudó, por cierto, la respuesta aceptada no. Gracias :) Lo que realmente usé es esto, en cambio: var y = e.pageY - $(this).offset().top;pero tu respuesta me llevó por el camino correcto.
Solomon Closson

11

Yo uso este código, es bastante agradable :)

    <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 respuesta de @AbdulRahim es casi correcta. Pero sugiero la siguiente función como sustituto (para referencia adicional):

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
Mejora brillante, me salvó el día.
Bud Damyanov

casi, agregue margen al lienzo y estará fuera por el margen
Benn

Este es un gran fragmento de código, ¡muchas gracias!
Stefan

7

Esta solución es compatible con todos los principales navegadores, incluido IE. También se encarga del desplazamiento. Primero, recupera la posición del elemento en relación con la página de manera eficiente y sin utilizar una función recursiva. Luego obtiene la x e y del clic del mouse con relación a la página y hace la resta para obtener la respuesta, que es la posición relativa al elemento (el elemento puede ser una imagen o div, por ejemplo):

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

Si hace que su elemento padre sea "position: relative", será el "desplazamiento padre" para las cosas sobre las que rastrea los eventos del mouse. Por lo tanto, la "posición ()" de jQuery será relativa a eso.


Hola Pointy, gracias por tu respuesta. Según su redacción, parece que lo que sugiere es diferente de lo que sugirió jball, pero no entiendo cómo, ¿puede explicarlo? Gracias de nuevo
Chris Dutrow

@DutrowLLC, Pointy sugiere cambiar el estilo del elemento principal que debe tener "position:relative". La posición de jQuery informaría sus posiciones relativas al elemento padre, no a la página. La redacción de mi respuesta es deficiente, implica que está directamente relacionada con la solución de Pointy, pero es una forma de calcular el desplazamiento cuando no puede o no quiere depender de los atributos de estilo del elemento padre.
jball

Entonces, si configuro "position: relative", jQuery informará la posición de la relación correctamente en todos los navegadores? La razón por la que pregunto es porque la documentación de jQuery parecía implicar que la única posición confiable del mouse en todos los navegadores era la relacionada con la ventana del navegador.
Chris Dutrow

Un cuadro con "posición: relativo" establecerá la configuración "superior" e "izquierda" (etc.) para los cuadros secundarios en relación con el rectángulo de contenido del cuadro primario relativo.
Puntiagudo

Puede que esté haciendo algo mal, pero esto no parece funcionar en Firefox. Tengo "posición: relativa"; establecido en el padre, firefox informa event.pageX y event.clientX de forma idéntica (con respecto a la parte superior, izquierda de la página) e informa event.offsetX como indefinido
Chris Dutrow

2

Aquí hay uno que también le da el porcentaje de posición del punto en caso de que lo necesite. 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

Sugeriría esto:

e.pageX - this.getBoundingClientRect().left
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.