¿Cómo obtengo las coordenadas de un clic del mouse en un elemento del lienzo? [duplicar]

Resuelto Tom asked hace 16 años • 22 respuestas

¿Cuál es la forma más sencilla de agregar un controlador de eventos de clic a un elemento de lienzo que devolverá las coordenadas xey del clic (en relación con el elemento de lienzo)?

No se requiere compatibilidad con navegadores antiguos; Safari, Opera y Firefox son suficientes.

Tom avatar Sep 11 '08 09:09 Tom
Aceptado

Si le gusta la simplicidad pero aún desea la funcionalidad entre navegadores, encontré que esta solución funcionó mejor para mí. Esta es una simplificación de la solución de @Aldekein pero sin jQuery .

function getCursorPosition(canvas, event) {
    const rect = canvas.getBoundingClientRect()
    const x = event.clientX - rect.left
    const y = event.clientY - rect.top
    console.log("x: " + x + " y: " + y)
}

const canvas = document.querySelector('canvas')
canvas.addEventListener('mousedown', function(e) {
    getCursorPosition(canvas, e)
})
patriques avatar Aug 05 '2013 08:08 patriques

Actualización (5/5/16): en su lugar, se debe utilizar la respuesta de Patriques , ya que es más simple y confiable.


Dado que el lienzo no siempre tiene un estilo relativo a toda la página, canvas.offsetLeft/Topno siempre devuelve lo que necesita. Devolverá el número de píxeles que está desplazado en relación con su elemento offsetParent, que puede ser algo así como un divelemento que contiene el lienzo con un position: relativeestilo aplicado. Para tener en cuenta esto, debes recorrer la cadena de offsetParents, comenzando con el elemento del lienzo. Este código funciona perfectamente para mí, probado en Firefox y Safari, pero debería funcionar para todos.

function relMouseCoords(event){
    var totalOffsetX = 0;
    var totalOffsetY = 0;
    var canvasX = 0;
    var canvasY = 0;
    var currentElement = this;

    do{
        totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
        totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
    }
    while(currentElement = currentElement.offsetParent)

    canvasX = event.pageX - totalOffsetX;
    canvasY = event.pageY - totalOffsetY;

    return {x:canvasX, y:canvasY}
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;

La última línea hace que sea conveniente obtener las coordenadas del mouse en relación con un elemento del lienzo. Todo lo que se necesita para obtener las coordenadas útiles es

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;
Ryan Artecona avatar May 09 '2011 03:05 Ryan Artecona

Edición 2018: esta respuesta es bastante antigua y utiliza comprobaciones para navegadores antiguos que ya no son necesarios, ya que las propiedades clientXy clientYfuncionan en todos los navegadores actuales. Es posible que desee consultar Patriques Answer para obtener una solución más simple y reciente.

Respuesta original:
Como se describe en un artículo que encontré en ese entonces pero que ya no existe:

var x;
var y;
if (e.pageX || e.pageY) { 
  x = e.pageX;
  y = e.pageY;
}
else { 
  x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 
  y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 
} 
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;

Funcionó perfectamente bien para mí.

N4ppeL avatar Dec 13 '2010 15:12 N4ppeL

Los navegadores modernos ahora manejan esto por usted. Chrome, IE9 y Firefox admiten offsetX/Y de esta manera, pasando el evento desde el controlador de clic.

function getRelativeCoords(event) {
    return { x: event.offsetX, y: event.offsetY };
}

La mayoría de los navegadores modernos también admiten LayerX/Y, sin embargo, Chrome e IE usan LayerX/Y para el desplazamiento absoluto del clic en la página, incluido el margen, el relleno, etc. En Firefox, LayerX/Y y offsetX/Y son equivalentes, pero el desplazamiento no No existía previamente. Entonces, para compatibilidad con navegadores un poco más antiguos, puedes usar:

function getRelativeCoords(event) {
    return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}
mafafu avatar Aug 24 '2012 17:08 mafafu

Así que este es un tema simple pero un poco más complicado de lo que parece.

En primer lugar, aquí suelen haber preguntas combinadas.

  1. Cómo obtener las coordenadas relativas del mouse del elemento

  2. Cómo obtener las coordenadas del mouse de píxeles del lienzo para 2D Canvas API o WebGL

entonces, respuestas

Cómo obtener las coordenadas relativas del mouse del elemento

Si el elemento es o no un lienzo, las coordenadas relativas del mouse del elemento son las mismas para todos los elementos.

Hay 2 respuestas simples a la pregunta "Cómo obtener las coordenadas relativas del mouse en el lienzo"

Respuesta simple #1 uso offsetXyoffsetY

canvas.addEventListner('mousemove', (e) => {
  const x = e.offsetX;
  const y = e.offsetY;
});

Esta respuesta funciona en Chrome, Firefox y Safari. A diferencia de todos los demás valores de eventos offsetX, offsetYtenga en cuenta las transformaciones CSS.

El mayor problema con offsetXy offsetYes que a partir de 2019/05 no existen en eventos táctiles y, por lo tanto, no se pueden usar con iOS Safari. Existen en eventos de puntero que existen en Chrome y Firefox, pero no en Safari, aunque aparentemente Safari está trabajando en ello .

Otra cuestión es que los acontecimientos deben estar en el propio lienzo. Si los pones sobre algún otro elemento o la ventana no podrás luego elegir el lienzo como punto de referencia.

Respuesta simple #2 uso clientX, clientYycanvas.getBoundingClientRect

Si no le importan las transformaciones CSS, la siguiente respuesta más simple es llamar canvas. getBoundingClientRect()y restar la izquierda desde clientXy tophacia clientYcomo en

canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
});

Esto funcionará siempre que no haya transformaciones CSS. También funciona con eventos táctiles y también funcionará con Safari iOS.

canvas.addEventListener('touchmove', (e) => {
  const rect = canvas. getBoundingClientRect();
  const x = e.touches[0].clientX - rect.left;
  const y = e.touches[0].clientY - rect.top;
});

Cómo obtener las coordenadas del mouse del píxel del lienzo para la API 2D Canvas

Para esto, debemos tomar los valores que obtuvimos arriba y convertirlos del tamaño en que se muestra el lienzo al número de píxeles en el lienzo mismo.

con canvas.getBoundingClientRecty clientXyclientY

canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  const elementRelativeX = e.clientX - rect.left;
  const elementRelativeY = e.clientY - rect.top;
  const canvasRelativeX = elementRelativeX * canvas.width / rect.width;
  const canvasRelativeY = elementRelativeY * canvas.height / rect.height;
});

o con offsetXyoffsetY

canvas.addEventListener('mousemove', (e) => {
  const elementRelativeX = e.offsetX;
  const elementRelativeY = e.offsetY;
  const canvasRelativeX = elementRelativeX * canvas.width / canvas.clientWidth;
  const canvasRelativeY = elementRelativeY * canvas.height / canvas.clientHeight;
});

Nota: En todos los casos, no agregue relleno ni bordes al lienzo. Hacerlo complicará enormemente el código. En lugar de querer un borde o relleno, rodee el lienzo con algún otro elemento y agregue el relleno o el borde al elemento exterior.

Ejemplo de trabajo usando event.offsetX,event.offsetY

Mostrar fragmento de código

Ejemplo de trabajo usando canvas.getBoundingClientRecty event.clientXyevent.clientY

Mostrar fragmento de código

gman avatar May 19 '2019 07:05 gman