duduromeroa.com

#Javascript, #APIPointerEvents, #webinteractiva, #Interfaces, #duduromeroa, #Guayaquil

Javascript | DOM | API

Programación para web: estudio de API Pointer Events para eventos indiferentes de tocar, halar o soltar


JS, eventos, escuchas de eventos, DOM. www.duduromeroa.com

Por Eduardo J. Romero Andrade
| Guayaquil

Contacto duduromeroa@gmail.com


#Javascript #API

Aclaraciones
Contenido para quienes ya comprenden y practican HTML, CSS y JS. Adjunto bibliografía al final de esta página.


En algunos ejemplos de código añadí espacios entre los caracteres para resaltar la sintaxis. La original NO usa esos espacios.


En casi todos los ejercicios expongo código y comentarios. Puedes revisarlo en: (click derecho en esta página desde mouse > Inspect Element > sources ).



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 ;
}
});

Tocar aquí

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 );
});

Tocar aquí

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.

Tocar aquí

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.

Tocar aquí

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.

Tocar aquí

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 (" ").

Tocar aquí

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?:

Tocar aquí

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.

Tocar aquí

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.

Tocar aquí

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.
Tocar aquí

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.

Tocar aquí

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.

Tocar o deslizar encima

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.

Tocar aquí

Uso de PointerEvent API

Se probaron todos los ejemplos mencionados arriba en dos tipos de pantallas táctiles (dedo en móvil y mouse en escritorio). La API PointerEvent permite identificar el objeto de puntero y ejecuta código según esa detección.


No se comprobó aún la ejecución de otras propiedades que detectan presión o sensibilidad; por ejemplo pressure, o twist.


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.

Toca y desliza con dedo

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.

Tocar aquí

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.

Acerca puntero aquí o toque y luego aléjese de esta área

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 salir o dejar de tocarlo.

Padre
Hijo

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().

Botón

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


BIBLIOGRAFÍA:
[1] Eloquent JavaScript 3ra edición. 2018. Marijn Haverbeke. No starch press.
[2] MDN Web Docs, Javascript. Mozilla Foundation.
[3] JavaScript: The Definitive Guide. David Flanagan (2020). Editorial O'Reilly.
[4] Object-Oriented JavaScript Ved Antani, Stoyan Stefanov (2017). Packt Publishing.
[5] Laurence Lars Svekis, Maaike van Putten. JavaScript from Beginner to Professional: Learn JavaScript quickly by building fun, interactive, and dynamic web apps, games, and pages (2021). Editorial Packt.
[6] Black, A. P. (2013) Object-oriented programming: Some history, and challenges for the next fifty years. Information and Computation. Elsevier.
[7] John R. Pugh, Wilf R. LaLonde, David A. Thomas (1987) Introducing object-oriented programming into the computer science curriculum. ACM SIGCSE BulletinVolume 19Issue 1Feb
[8] W3C. JavaScript HTML DOM Navigation