Alexander A. E.Django developer

Posición absoluta y Relativa de un click en javascript

Mientras intentaba desarrollar un plugin para jquery tuve un inconveniente, el cómo hacer para obtener la posición relativa de un evento click hacia su contenedor.

Realizando algunas búsquedas en google y leyendo los diversos artículos pude obtener una idea del cómo estaba el panorama. Por ejemplo, revisando el tutorial de jquery que versa sobre el cálculo de la posición del mouse podemos destacar algunos puntos:

  • pageX1 y pageY son dos propiedades de todos los eventos javascript que nos indican la posición absoluta del puntero respecto a la esquina izquierda de todo documento (no solo de la parte visible de la página).

  • Para realizar el cálculo de la posición relativa de un click nos muestran el siguiente ejemplo:

$("#special").click(function(e){

    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;

    $('#status2').html(x +', '+ y);
});

lo que consiste en el cálculo de la posición absoluta del click menos la posición absoluta del contenedor.

stackoverflow

En mi búsqueda del como poder realizar esto, di con algunos enfoques interesantes en stackoverflow:

Por ejemplo, había quien recomendaba realizar un cálculo iterativo de las distancias relativas de cada contenedor con su padre:

function absolutePos(obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
    }
    return [curleft,curtop];
}

Note que offsetLeft2 calcula la distancia del elemento actual en relación a su contenedor o padre.

Y también quien sugería una mejora introduciendo los valores del margin, padding y border:

function getNumericStyleProperty(style, prop){
  return parseInt(style.getPropertyValue(prop),10) ;
}

function element_position(e) {
    var x = 0, y = 0;
    var inner = true ;
    do {
        x += e.offsetLeft;
        y += e.offsetTop;
        var style = getComputedStyle(e,null) ;
        var borderTop = getNumericStyleProperty(style,"border-top-width") ;
        var borderLeft = getNumericStyleProperty(style,"border-left-width") ;
        y += borderTop ;
        x += borderLeft ;
        if (inner){
            var paddingTop = getNumericStyleProperty(style,"padding-top") ;
            var paddingLeft = getNumericStyleProperty(style,"padding-left") ;
            y += paddingTop ;
            x += paddingLeft ;

            var marginTop = getNumericStyleProperty(style,"margin-top") ;
            var marginLeft = getNumericStyleProperty(style,"margin-left") ;
            y += marginTop ;
            x += marginLeft ;
        }
        inner = false ;
    } while (e = e.offsetParent);
    return { x: x, y: y };
}

Y por último, la solución a mi problema. Al parecer existen un par de propiedades de los eventos que indican la posición relativa al contenedor en el que fueron realizados: offsetX3 y offsetY. Por lo que para nuestros propósitos, bastaría con algo como:

$('selector').click(function(ev){
    x = ev.offsetX;
    y = ev.offsetY;
}

y todo parecería perfecto .. exceptuando por un 'insignificante' problema, offsetX no está definido4 en Firefox. Pero menos mal que si revisamos en stackoverflow nuevamente, podremos encontrar alguna solución, como por ejemplo:

if(ev.offsetX == undefined){ // para firefox
    x = ev.pageX - $(this).offset().left;
    y = ev.pageY - $(this).offset().top;
}
else{ // chrome
    x = ev.offsetX;
    y = ev.offsetY;
}

demo

A modo de ejemplo, armé una demo en la que se trata de dibujar un punto de 2x2 en la posición en la que se realiza un click tal y como muestra la siguiente captura:

demo

Notas:

  • En el ejemplo se comparan el método encontrado en la documentación de jquery así como la solución que utilicé, imprimiendo ambos resultados en la consola.
  • Observando que si bien en chrome ambos cálculos coinciden, en firefox hay una diferencia de 4px posiblemente al margin que le di al body (requeriría un mayor análisis).
  • Para dibujar el punto solo se utilizó la solución que expuse como final.

consola del firebug en firefox

Código en bitbucket del ejemplo: demo (el directorio es: posicion-relativa-de-un-click)


  1. Mozilla developers: pageX 

  2. Mozilla developers: offsetLeft 

  3. Especificación de la propiedad: offsetX 

  4. reporte del bug en bugzilla 

Comentarios !

comments powered byDisqus