Detección indiferente de eventos tocar/halar
Refiero aquí como indiferente (o agnóstico, un anglicismo usado como término similar) cuando un sistema no excluye una tecnología. En este caso, no excluye la acción táctil de un dedo sobre pantalla o de un puntero de mouse. Es decir, cada uno de esos elementos de toque activarán de igual manera los eventos interactivos desde una API.
Si la API drag/drop solo detecta el puntero del mouse, y la API TouchEvents solo detecta los dedos sobre la pantalla, a la API que revisaremos le da igual 'con qué se toca'. Sea con del dedo o con el puntero del mouse detectará eventos de halar, soltar o tocar elementos en una página web.
Sin embargo, siempre se debe tomar en cuenta la disponibilidad de toda API según navegadores y versiones de navegadores. Un recurso útil para eso es el amigable caniuse.com. En otras palabras, se debe tener atención en qué navegadores de escritorio y de móviles acepta cada tecnología nueva.
API Pointer events
Para mdn web docs_ la API Pointer events asume cualquier elemento táctil como un puntero válido. Su interface (conjunto de propiedades y métodos) es PointerEvent con sus respectivas propiedades de lectura de magnitudes, presión táctil y coordenadas.
Propiedades de la interface API PointerEvent
Estas 10 propiedades agregan datos al elemento usado para crear acción táctil (indiferente al elemento táctil) sobre la pantalla.
- pointerId :: Determina un identificador de puntero único para activar mediante interacción táctil un evento
- width :: dimensión horizontal en pixeles de un elemento táctill
- height :: dimensión vertival en pixeles de un elemento táctill
- pressure :: valor de presión percibida por el soporte táctil. 0-1 (de menor a mayor presión)
- tangentialPressure :: presión táctil inclinada de un puntero táctil sobre el soporte.
- tiltX :: ángulo del plano (-90 a 90grados) de un puntero táctil, entre los planos de profundidad y altura (Y-Z).
- tiltY :: ángulo del plano (-90 a 90grados) de un puntero táctil, entre los planos de profundidad y horizontal (X-Z).
- twist :: torsión del puntero en grados. De 0 a 359 grados.
- pointerType :: define el tipo de puntero que activa evento. Sea este puntero de mouse, lápiz óptico, dedo.
- isPrimary :: define el puntero principal que activa evento.
Luego de identificar las propiedades de la API PointerEvent, las repasaremos:
Propiedad pointerId
Abajo, asigna un número a un exclusivo (o un incremento exclusivo) a puntero único sobre pantalla. Eso permite agregar e identificar más de un puntero (incluso, identificar cada toque táctil, al ser enumerado del 1 en adelante) para interacción. Hay que tener en cuenta que esa numeración puede variar según navegadores en donde se aplique.
En el caso de abajo, el puntero de mouse es identificado únicamente con el número 1, mientras que cada contacto táctil sobre pantalla es identificado desde el número 2, y a cada toque táctil ese valor se incrementa.
Identificar el número del 'toque' ayuda, por ejemplo, a darle órdenes de cambio de color del botón desde un rango de incremento numérico en cada toque táctil, no de mouse
Sin embargo, ¿por qué al tocar con puntero de mouse, el botón no cambia de color? puesto que el puntero del mouse siempre se identificará con el valor 1, y NO incrementará; la condicional no lo tomará en cuenta.
En Javascript
// Aloja y apunta a activador. Solo esto SELECCIONA
var apuntaAelemActx = document.getElementById("elemActx");
/* En cambio, pointerId solo nombra al puntero (no lo selecciona)
y le da un número exclusivo. */
// Vincula activador con evento click
/* Recordar: el 'objetoEvento' lleva datos
del evento hacia dentro del código */
apuntaAelemActx.addEventListener('pointerdown', function(objetoEvento){
/* Recordar: toque táctil con dedo inicia en 2 */
/* Si el número identificador del toque está entre 3 y 5...altere color */
if (objetoEvento.pointerId >= 3 && objetoEvento.pointerId <= 5){
apuntaAelemActx.style.backgroundColor = "red";
/* Si el número identificador del toque está entre 6 y 8...altere color */
} else if (objetoEvento.pointerId >= 6 && objetoEvento.pointerId <= 8){
apuntaAelemActx.style.backgroundColor = "green";
// Si no es ninguno de esos, mantener gris
} else {
apuntaAelemActx.style.backgroundColor = "";
}
/* Dice desde qué está tocando */
// Si es menor a 2..
if (objetoEvento.pointerId < 2){
elemActx.textContent = "Tocas con mouse y el pointerId de eso es : " +
objetoEvento.pointerId ;
// Si esa condición es FALSA
} else {
elemActx.textContent = "Tocas con dedo y el pointerId
de eso se incrementa a : " +
objetoEvento.pointerId ;
}
});
Activado con mouse y táctil
Es así que según la condición dada, el botón tendrá un color diferente si los taps en pantalla se cuentan desde el toque número 3 al 5; y otro color entre el toque 6 y 8. Eso facilita tener identificado mediante un número cada toque táctil.
Propiedades 'width' y 'height'
Abajo, representa la 'geometría de contacto' del ancho (width) y del alto (height) resultante del uso de un puntero mouse o de un dedo (pero no del ancho del elemento activador) y se expresará en pixeles. Un puntero de dispositivo estándart dará un valor de ancho o alto de contacto de 1px como referencia inicial. En otras palabras, las propiedades width y height responderá a la pregunta de '¿Cuánto mide el área de contacto que resulta de tocar con mi puntero sobre la pantalla?'.
En Javascript
// Se apunta a elemento activador
var elemActivador = document.getElementById("elemento");
// Se vincula con eventListener
elemActivador.addEventListener('pointerdown', function(evento) {
// Da ancho
console.log(evento.width);
// Da alto
console.log(evento.height);
// Da área total de puntero
console.log(evento.width * evento.height );
});
Activado con mouse y táctil
Propiedades 'pressure'
Abajo, representa un valor entre 0 a 1 de presión táctil disponible por el dispositivo puntero (y por el nivel de sensibilidad de la pantalla). El valor promedio será de 0.5 si el dispositivo no mide sensibilidad a presión táctil alguna.
Recordar que cada soporte y puntero dará unos valores diferentes, por lo que vale hacer pruebas para conocer esos datos.
Activado con mouse y táctil pero en evento no está leyendo valores de presión
Propiedad tangentialPressure
Abajo, representa valores de -1 a 1, como datos generados por la presión y deslizamiento rotatoria de un puntero en un mismo eje vertical y sobre un soporte con capacidad sensible de detectar rotación táctil. Por ejemplo, desde un lápiz digital de gama alta.
En soportes y punteros que no tengan esa sensibilidad el valor siempre será cero, que representa una presión tangencial neutra. Es decir, solo hay toque táctil.
Activado con mouse y táctil pero en evento no está leyendo valores de presión
Propiedad tiltX, tiltY
Sin ejemplo. Mide el ángulo de inclinación de un puntero sobre la pantalla. Similar a dibujar con un lápiz casi recostado, donde el trazo será más grueso y difuminado. Las propiedadas tiltX y tiltY se aplican cuando el puntero es un lápiz digital con sensibilidad para ese tipo de trazo inclinado. Por ahora no se dará ejemplo práctico de esto por no tener un soporte sensible a ese tipo de evento.
Propiedad twist
Abajo, representa la rotación en grados (de 0 a 359 grados), desde un mismo eje vertical, de un puntero. En punteros y soportes no sensibles a esa rotación el valor constante será de cero.
Propiedad pointerType
Abajo, esta propiedad reconoce el tipo de puntero (mouse, lápiz o dedo) que activó un elemento interactivo vinculado a un eventListener. La propiedad pointerType
devuelve un mensaje por cada puntero reconocido. Si no se lo reconoce, el mensaje es 0, false o vacío (" ").
Activado con mouse y táctil: el evento sí diferencia entre toque táctil y de mouse
Propiedad isPrimary
Abajo, indica (mediante booleano true) qué puntero es el principal por sobre otras entradas de puntero que se realicen, por ejemplo, durante gestos táctiles de más de un dedo y en donde se requiera definir a un solo dedo como activador de solo algunos tipos de eventos. Un puntero definido como secundario evalúa como false.
Sin embargo, ¿Quién decide si un puntero es primario o no?:
Activado con mouse y táctil:
En este caso (abajo) es el propio algoritmo quién, según el primer evento de puntero que ocurra, decidirá cuál es primario y cual secundario.
Activado con mouse y táctil: el evento sí diferencia entre toque táctil y de mouse
Hasta aquí las 10 propiedades de PointerEvents API. Siguen los tipos de eventos.
10 tipos de eventos y manejadores de eventos
Son los eventos asignados a cada interacción táctil en pantalla. Si la interacción coincide con el evento (ejemplo, halar un elemento web) entonces un código ejecutará una acción. Se denominará 'puntero' a cualquier elemento con potencial acción táctil (dedo, puntero mouse o lápiz digital).
Se aclara que los 'button states' o estados de botón significa que pueden existir más de una actividad táctil que active un evento, por ejemplo, presionar dos botones del mouse al mismo tiempo. Los estados de botón están disponibles solo para puntero de mouse o lápiz óptico sobre pantalla táctil.
La captura de puntero o 'Capturing the pointer' redefine un nuevo elemento interactivo mientras otro elemento ya ha recibido otro evento; como por ejemplo al deslizar la página web mediante la rueda del mouse.
- pointerover :: código se ejecuta cuando el puntero está sobre un elemento interactivo
- pointerenter :: código se ejecuta cuando el puntero se mueve dentro de uno o más elementos interactivos
- pointerdown :: código se ejecuta cuando uno de los estados
button
- pointermove :: código se ejecuta cuando el puntero cambia de sitio.
- pointerup :: código se ejecuta cuando el puntero ya no está activo
- pointercancel :: código se ejecuta cuando el puntero está desconectado o apagado.
- pointerout :: código se ejecuta en diversos estados: cuando el puntero se aleja del elemento interactivo, o cuando el dispositivo no admite ese tipo de puntero, o después de activar el evento pointercancel,
- pointerleave :: código se ejecuta cuando el puntero se mueve fuera de los límites del elemento interactivo
- gotpointercapture :: código se ejecuta cuando el elemento interactivo recibe la captura del puntero.
- lostpointercapture :: código se ejecuta cuando la captura del puntero es soltado.
Evento pointerover
Es un símil del 'mouseover' para la API PointerEvents (mouse o dedo). Activa evento una sola vez al posar el cursor sobre el elemento activador, y activa cada vez cliquear o tocar el elemento activador. Además, el evento puede ser propagado hacia sus descendientes. Esa reactivación de evento y la propagación NO ocurre con el evento pointerenter
, revisado más abajo.
Activado con mouse y táctil: evento mouse sí activa el 'sobrevuelo', pero el evento táctil solo lo activa al tocarlo.
Evento pointerenter
Abajo. Para mdn web docs_ el evento pointerenter
activa un evento una sola vez al posar el puntero sobre el elemento activador. Las diferencias con pointerover y con mouseover son:
- pointerenter no activa el evento desde descendientes hacia elemento padre. El evento solo se activa una sola vez en el elemento que recibió la acción de puntero y sin propagar (bubbling) a ningún otro elemento.
- pointerenter solo ejecuta una sola vez cuando el puntero entre en el área del elemento activador.
- pointerenter no recibe click ni toque táctil.
Activado con mouse y táctil: evento mouse sí activa la 'entrada', pero el evento táctil solo lo activa al tocarlo.
Evento pointerdown
Abajo. Activa evento cada vez que el puntero 'presiona', o cuando el dedo toca un elemento activador, o cuando el puntero del lápiz digital toca la pantalla sensible al toque.
Activado con mouse y táctil
Evento pointermove
Abajo. Activa evento cuando el puntero es desplazado en su posición sobre el elemento activador. En otras palabras, cuando el puntero se mueve, pointermove
puede activar un evento explícitamente dado.
Activado con mouse y táctil: evento mouse sí activa el 'sobrevuelo en movimiento', pero el evento táctil solo lo activa al tocarlo.
Evento pointerup
Se activa un evento cuando el puntero ya no está activo o dejó su función de 'tocar algo'. Y el evento que se ejecute puede ocurrir luego de desactivar el puntero.
Activado con mouse y táctil: ambos eventos (mouse o táctil) activan la interacción pero solo cuando el elemento es soltado.
Uso de PointerEvent API (Actualización junio 21 del 2024)
Se probaron todos los ejemplos con toque táctil o de mouse. Casi todos los eventos de la API PointerEvent sí identifican el puntero (mouse o táctil).
Para los eventos pressure
o twist
, es posible que se requiera de un tipo diferente de puntero (hardware). Ambos métodos sí reaccionan a táctil y a mouse, pero no dan datos de presión o de interacción con esos punteros.
Evento pointercancel
Abajo, es un evento que se ejecuta luego de una interrupción no vinculada al contexto del código en el que se halla. Es decir, pointercancel se activa cuando una acción externa interrumpe un evento táctil ya activado antes, o cuando el navegador bloquea eventos táctiles para iniciar otra interacción fuera del eventListener (como cambiar la orientación de la pantalla o recibir una llamada de teléfono). Ojo, pointercancel es un evento tan específico que no funciona solo, y no siempre será requerido.
Activado con táctil: Solo un toque táctil + deslizamiento + interrupción de deslizamiento activa el evento pointercancel
. El mouse deslizado no lo activa.
En el ejemplo de arriba: pointercancel
es un evento solitario, por eso no dispara un mensaje contenido en pointercancel
cuando se cliquea la caja gris con el mouse. Solo sucede si se toca y se desliza con el dedo. ¿Por qué? al combinar esas acciones el sistema considera que el evento táctil ha sido interrumpido por el deslizamiento.
Para que se muestre un mensaje luego de eventos táctiles agnósticos (es decir, que funcione por igual desde toque táctil y click de mouse) pointercancel
no debería ser un evento único. Debería estar inserto en un eventListener y activado cuando otros eventos presentes ya han dejado de ejecutarse por una causa externa a lo contenido en el eventListener.
Activado con mouse y táctil Un toque (táctil o de mouse) y un soltado (táctil o de mouse) sí lo activa. Pero la activación del deslizado solo es activado por el evento táctil.
Evento pointerout
Abajo. Similar al evento de puntero de ratón 'mouseout'. Este evento pointerout
se activa cuando el puntero (mouse) abandona el área del elemento táctil; y cuando un puntero táctil una vez tocado el botón, se desliza (sin soltarlo) hacia afuera del botón.
Activado con mouse y táctil: El evento táctil lo activa cuando el elemento deja de ser tocado. El evento de mouse lo activa cuando entra en el área del elemento y luego se aleja del elemento.
También (en el ejemplo de abajo) pointerout
se activa cuando el puntero se mueve HACIA un subelemento del padre. Lo que permite una propagación de dentro hacia afuera (bubbling). Es decir, que el evento se activa desde el elemento hijo hacia el padre.
Hay que tener en cuenta que pointerout
NO se activa al tocar o entrar al elemento táctil; sino al entrar y salir del elemento (con puntero mouse), o al tocarlo y luego dejar de tocarlo (con puntero táctil).
Evento pointerleave
Este es otro evento que se activa simplemente cuando el puntero se ha alejado únicamente del área táctil definida. Con pointerleave
NO es posible propagar el evento con pointerleave
. Se omitirá el ejemplo.
Evento gotpointercapture
Aquí es cuando un elemento (como un botón) 'atrapa' a un evento click o táctil. En este contexto, 'atrapar' significa mantener al puntero creando y comunicando datos de posición en tiempo real desde el momento de tocar el botón.
Es decir, cuando un área táctil (como un botón) atrapa un puntero mediante un click, el puntero activará el evento pointermove
para que ejecute código cada vez que el puntero se mueva incluso hacia fuera del botón. Pero cuando el botón es soltado se ejecutará el evento pointerup
.
Un evento captura un puntero mediante el método setPointerCapture()
. En cambio, cuando el puntero es soltado, se invoca al método releasePointerCapture().
Activado con mouse y táctil Evento táctil y evento mouse activan el método tanto al tocarlo como al soltarlo.
Abajo. En otro ejemplo de gotpointercapture
se tiene que
Evento lostpointercapture
Hasta aquí los 10 eventos de PointerEvents API.
3 extensiones de elemento
Son propiedades adicionales añadidos a los elementos del DOM para agregar más datos que sirvan para la funcionalidad de los eventos interactivos.
- setPointerCapture() :: Determina un elemento individual y único que recibe el evento táctil; es decir, el elemento 'diana' o blanco.
- releasePointerCapture():: elimina el estado de elemento interactivo
- Navigator.maxTouchPoints:: determina la máxima cantidad de toques en tiempo real que está disponible a la vez.
Ojo con algunas cuestiones a tomar en cuenta según mdn web docs_
No exceder la cantidad de proceso de los event handlers. Es decir, reducir su trabajo al ejecutar varias acciones por cada evento activado.
No ampliar la cantidad de elementos interactivos vinculados al event handler. Agregar demasiados elementos de la web podría generar retrasos en la respuesta interactiva.
Ajustar el/los tamaño/s del/los elemento/s interactivos que recibirá la acción táctil. Por ejemplo, un elemento táctil cualquiera debería tener mínimo un ancho disponible para ser 'tocado' por un dedo humano promedio (entre 40px a 60px ancho/alto).
Ojo hay que revisar clientX, clientY