Si necesitamos trabajar con acciones realizadas por el usuario con el ratón, generalmente optamos por MouseEvent
. Sin embargo, esta API es más antigua y quizás nos pueda venir mejor otra API como TouchEvent
o PointerEvent
, esta última la que trataremos en este artículo.
Tipo de evento | Descripción |
---|---|
MouseEvent | Detecta acciones realizadas con un ratón o similar. |
TouchEvent | Detecta acciones realizadas en una pantalla táctil o similar. |
PointerEvent | Detecta acciones realizadas por un dispositivo apuntador (engloba los anteriores). |
Aunque solemos generalizar y cuando trabajamos con Javascript hablamos de ratón, generalmente existen muchos tipos de dispositivos apuntadores: ratones, trackballs, lapiz óptico, touchpad, multitouch, etc...
A partir de ahora, en este artículo, hablaremos de puntero o apuntador para simplificar y referirnos a dichos dispositivos de forma generalizada.
El objeto PointerEvent
Veamos las propiedades principales que podemos tratar cuando estamos escuchando un evento de dispositivos apuntadores:
Propiedades | Descripción |
---|---|
type | Devuelve el tipo de evento, para identificarlo. En este caso: PointerEvent . |
pointerId | Devuelve un número, para identificar el dispositivo apuntador. |
pointerType | Identifica el tipo de puntero que estás utilizando: mouse , pen o touch . |
width / height | Ancho y alto (en píxeles) de la región pulsada. |
isPrimary | Indica si el dispositivo apuntador es el principal del sistema. |
sourceCapabilities | Indica las capacidades que tiene el dispositivo apuntador. |
detail | Generalmente, indica el número de clicks realizados. |
En el siguiente apartado veremos un pequeño ejemplo utilizando alguna información de esta tabla.
Eventos genéricos
Eventos genéricos que hoy en día devuelven un PointerEvent
serían los eventos click
, auxclick
y contextmenu
. Aunque más adelante veremos otros eventos mucho más específicos para acciones del dispositivo apuntador, estos suelen ser bastante frecuentes para acciones sobre elementos de la UI de una página:
Evento | Descripción |
---|---|
click | Se ha activado el botón principal del dispositivo apuntador. |
auxclick | Se ha activado el botón secundario del dispositivo apuntador. |
contextmenu | Se ha desplegado el menú contextual (generalmente, con botón auxiliar). |
Veamos un ejemplo simple:
const button = document.querySelector("button");
const status = document.querySelector(".status");
button.addEventListener("click", (ev) => {
status.textContent =
`Se ha disparado un evento ${ev.constructor.name} de tipo ${ev.pointerType}.`;
});
<div class="status"></div>
<button>Click me</button>
Valores especiales
La siguiente tabla de propiedades son valores numéricos
Propiedades | Descripción |
---|---|
Valores de pen/stylus | |
altitudeAngle | Altitud (en radianes) del apuntador en el rango [0, PI/2] . Devuelve 0 si es paralelo a la superficie y PI/2 si es perpendicular o no tiene capacidad de detectar ángulo. |
azimuthAngle | Azimut (en radianes) del apuntador en el rango [0, PI/2] . Devuelve 0 si no se puede detectar ángulo. |
twist | La rotación [0, 359] del apuntador (pen, stylus). Devuelve 0 si no se puede detectar. |
Valores de presión | |
pressure | Presión del puntero entre [0, 1] . Si no soporta presión, devuelve 0.5 . |
tangentialPressure | Presión del "barrel" entre [-1, 1] . Si no soporta, devuelve 0 . |
¿Qué botón se ha pulsado?
Una de las cosas que nos podría interesar saber es saber que botón ha sido pulsado. Esto se puede conocer facilmente con la propiedad button
, que nos devuelve un valor numérico con el botón concreto con el que se ha pulsado y disparado el evento (por ejemplo, el evento pointerdown
):
Propiedades | Descripción | |
---|---|---|
button | Valor para indicar el estado del botón. | |
-1 | Ningún botón/touch/pen ha cambiado desde el último evento. | |
0 | Botón izquierdo de ratón o contacto con touch/pen | |
1 | Botón medio del ratón | |
2 | Botón derecho del ratón o "barrel" del pen | |
3 | Botón X1 (atrás) del ratón | |
4 | Botón X2 (adelante) del ratón | |
5 | Botón de borrado del pen |
Puedes comprobarlo en acción en este ejemplo. Prueba a pulsar sobre el área de color y te mostrará los valores de la propiedad button
y la propiedad buttons
:
const box = document.querySelector(".box");
document.body.addEventListener("pointerdown", (ev) => {
const { button, buttons } = ev;
box.innerHTML = `
Valor de button: <code>${button}</code><br>
Máscara de buttons: <code>${buttons}</code>
`;
});
.box {
width: 500px;
height: 100px;
background: indigo;
font-family: Jost, sans-serif;
font-size: 1.25rem;
color: #fff;
padding: 0.5rem;
& code {
color: gold;
}
}
<div class="box">Pulsa aquí con diferentes botones</div>
Por otro lado, la propiedad buttons
nos devuelve una máscara de bits. Esto puede ser más interesante si queremos saber si se han pulsado varios botones a la vez. Para ello, podemos hacer uso simplemento de operaciones de tipo ev.buttons & 4
, para saber si se ha pulsado el botón del medio del apuntador de tipo ratón.
Los valores de la máscara son los siguientes:
Propiedades | Descripción | |
---|---|---|
buttons | Máscara de bits para indicar el estado de los botones. | |
0 | Mouse/pen movido sin presionar botones | |
1 | Botón izquierdo de ratón o contacto con touch/pen | |
2 | Botón derecho de ratón o "barrel" del pen | |
4 | Botón medio del ratón | |
8 | Botón X1 (atrás) del ratón | |
16 | Botón X2 (adelante) del ratón | |
32 | Botón de borrado del pen |
La propiedad
which
que se usaba en el pasado para saber que botón ha sido pulsado ya es obsoleta y no debe utilizarse. En su lugar, lo recomendable es usarbutton
obuttons
.
Propiedades de posición
En algún caso, nos podría interesar obtener las posiciones o hacer cálculos con las distancias del apuntador respecto a otros elementos. Para ello, podemos utilizar las siguientes propiedades, que nos dan la posición donde se ha hecho click, touch o contacto.
Por ejemplo, clientX
nos devuelve la posición horizontal en la parte visible del navegador, mientras que screenX
nos devuelve la posición horizontal en el tamaño completo de pantalla. Así pues, tenemos algunas otras variaciones que podemos utilizar:
Propiedad | Descripción |
---|---|
clientX / clientY | Posición del apuntador en la región visible del navegador. |
x / y | Es un alias de las anteriores, clientX y clientY . |
movementX / movementY | Distancia recorrida por el apuntador desde el último evento. |
offsetX / offsetY | Posición del apuntador dentro del elemento target . |
pageX / pageY | Posición del apuntador en relación al documento. |
screenX / screenY | Posición del apuntado en relación a la pantalla del dispositivo. |
tiltX / tiltY | Inclinación del apuntador (si lo soporta). |
layerX / layerY |
Eventos de puntero
En el caso que necesitemos operaciones mucho más específicas del dispositivo apuntador, podemos utilizar los siguientes eventos:
Evento | Descripción |
---|---|
pointerdown | Se ha pulsado un botón del dispositivo apuntador en un elemento. |
pointerup | Se ha soltado un botón del dispositivo apuntador en un elemento. |
pointermove | Se ha movido un dispositivo apuntador sobre un elemento. |
pointerover | Igual al anterior, pero se propaga también a elementos secundarios. |
pointerenter | El dispositivo apuntador ha entrado en un elemento. |
pointerleave | El dispositivo apuntador ha salido de un elemento. |
pointerout | Igual al anterior, pero se propaga también a elementos secundarios. |
pointerrawupdate | Si necesitas alto nivel de refinado de eventos, puedes usar este evento. |
pointercancel | Se activa cuando es poco probable que hayan más eventos de puntero. |
Eventos de captura de puntero
Existen algunos eventos muy interesantes mediante los cuales podemos capturar un puntero para realizar operaciones especiales. Por ejemplo, arrastrar un elemento de un lugar a otro:
Evento | Descripción |
---|---|
gotpointercapture | Se activa cuando se captura un puntero con .setPointerCapture() . |
lostpointercapture | Se activa cuando se libera un puntero con .releasePointerCapture() . |
Para ello, podemos utilizar los métodos .setPointerCapture()
y .releasePointerCapture()
sobre un elemento del DOM en cuestión y escuchar los siguientes eventos de la tabla anterior.
const ball = document.querySelector(".ball");
let isDrag = false;
ball.addEventListener("pointerdown", ({ pointerId }) => {
ball.setPointerCapture(pointerId);
isDrag = true;
});
ball.addEventListener("pointerup", ({ pointerId }) => {
ball.setReleaseCapture(pointerId);
isDrag = false;
});
ball.addEventListener("pointermove", () => {
if (isDrag) {
/* ... */
}
});