Categorie
Javascript Programmazione

{JS} API Device Mobile: Touch

Cos’è l’API Touch?

Con l’avvento dei device mobile e più nello specifico dei touchscreen è stato necessario implementare un sistema di interazione con esso;
Il sistemi di interazione classici con il browser attraverso tastiere e mouse come: click, over, mousenter, mouseleave ecc. non erano più sufficienti.
I touchscreen forniscono molteplici possibilità di interazione con gli elementi di un app/sito.
L’interazione touch “del tocco” possono prevedere un tocco prolungato, un tocco senza sollevare il dito dallo schermo o  gesture tipo swipe, zoom, pinch e la rotazione di elementi.

Allo stato attuale esistono due API standardizzate per la gestione dell’interazione touch:

  • Touch Events, nata da Apple, prevede la gestione di una serie di eventi specifici per l’interazione touch;
  • Pointer Events, nata da Microsoft, che tende ad unificare le modalità di interazione proponendo un’API unica per mouse, dita, penne ed eventuali altri dispositivi di puntamento.

Prima di cominciare è doveroso precisare che la tessa gestione delle interazioni è valida per il trackpad dei laptop.

Interazioni touch

Nelle interazioni touch agiscono due componenti:

  • La superficie sensibile al tocco (potrebbe trattarsi di uno schermo o di un trackpad)
  • Il punto di contatto con la superficie. Questo può essere un dito (o gomito, orecchio, naso, qualunque cosa, ma in genere un dito) o uno stilo.

Esistono due tipi di interazioni:

  • Touch singolo
  • Multi-touch

Un’interazione multi-touch inizia quando un dito tocca per la prima volta la superficie di contatto. Altre dita possono successivamente toccare la superficie e, facoltativamente, spostarsi sulla superficie tattile. L’interazione termina quando le dita vengono rimosse dalla superficie. Durante questa interazione, un’applicazione riceve eventi di tocco durante le fasi di inizio, spostamento e fine.

Un interazione è composta da:

  • Evento touch, rappresenta l’evento che si verifica quando viene toccata una superfice tattile
  • Tocco, rappresenta un unico punto di contatto tra l’utente e la superficie
  • Lista dei tocchi, rappresenta un gruppo di tocchi; questo viene utilizzato quando l’utente ha, ad esempio, più dita sulla superficie contemporaneamente.

API Touch events

L’API in questione si concentra sulle interazioni possibili tramite il tocco introducendo 4 eventi.

Eventi

 Gli eventi touch offrono la possibilità di interpretare l’attività del dito sulla superficie touchscreen.

EventoDescrizione
touchstartSi verifica al primo contatto del dito con un elemento del DOM
touchendSi verifica quando il dito non è più in contatto con l’elemento del DOM
touchmoveSi verifica quando il dito si sposta sullo schermo mantenendo il contatto
touchcancelSi verifica in presenza di una condizione per cui è necessario annullare l’evento touch, ad esempio quando sullo schermo sono presenti più punti di contatto di quanti il dispositivo è in grado di supportare

Al verificarsi dell’evento, il gestore riceve alcune informazioni supplementari tramite l’oggetto event, che chiameremo “touchEvent”, che consentono di definire il contesto dell’interazione.

element.addEventListener('touchstart', function(touchEvent){
...
});

TouchEvent Object

L’oggetto restituito event alias “TouchEvent” contiene numerose proprietà che immagazzinano informazioni sui tocchi; le elenchiamo in ordine di importanza:

ProprietàDescrizioneRitorno
touchEvent.touchesrestituisce una TouchList
ovvia un array contenente una serie di oggetti “Touch" che rappresentano tutti i punti di contatto correnti con la superficie, indipendentemente dal target; più semplicemente fa riferimento all’intera superficie dello schermo
Array di oggetti
(generico)
touchEvent.targetTouchesrestituisce una TouchList di tutti gli 
oggetti Touch che sono attualmente a contatto con la superficie touch 
e che sono stati avviati sullo stesso elemento che è il target dell’evento.
Array di oggetti
(specifico)
touchEvent.changedTouchesrestituisce una TouchList di tutti gli 
oggetti Touch che rappresentano i singoli punti di contatto i cui stati sono cambiati tra l’evento touch precedente e questo.
Array di oggetti
touchEvent.rotationrestituisce valore che indica il cambio di rotazione (in gradi) dall’inizio dell’evento. 
I valori positivi indicano la rotazione in senso orario; 
i valori negativi indicano la rotazione in senso antiorario. 
Valore iniziale:
0.0
valore
touchEvent.scalerestituisce valore che indica la distanza tra due cifre dall’inizio dell’evento. 
I valori inferiori a 1,0 indicano un pizzico verso l’interno (rimpicciolimento). 
I valori superiori a 1,0 indicano un’apertura verso l’esterno (zoom avanti). 
Valore iniziale:
1.0
valore
touchEvent.altKeyrestituisce un valore booleano che indica se il tasto alt era premuto o meno quando è stato attivato l’evento touch.valore boolean
touchEvent.ctrlKeyrestituisce un valore booleano che indica se il tasto Ctrl era premuto o meno quando è stato attivato l’evento tocco.valore boolean
touchEvent.metaKeyrestituisce un valore booleano che indica se la meta chiave era inattiva o meno quando è stato attivato l’evento touch.valore boolean
touchEvent.shiftKeyrestituisce un valore booleano che indica se il tasto Maiusc era premuto o meno quando è stato attivato l’evento tocco.valore boolean

L’evento “touchstart”

Con l’evento “touchstart” monitoriamo il contatto dell’utente con il touchscreen;
Con la proprietà touchEvent.targetTouches possiamo rilevare i punti di contatto, tocchi, effettuati dall’utente.
La proprietà restituisce un array di oggetti che contiene tanti oggetti quanti sono i tocchi dell’utente all’interno di un elemento specifico

var box = document.getElementById("box");
var mostraTocco = document.getElementById("cerchio");

box.addEventListener("touchstart", function(touchEvent) {
	var tocco;
	if (touchEvent.targetTouches.length == 1) {
	tocco = touchEvent.targetTouches[0];
        mostraTocco.style.visibility="visible";
        mostraTocco.setAttribute('cy', `${Math.floor(tocco.clientY/2)}px`);
        mostraTocco.setAttribute('cx', `${Math.floor(tocco.clientX)}px`);
	}
});

Nel codice qui sopra utilizziamo l’evento “touchstart” che monitora l’evento tocco su di un elemento del DOM, nel nostro caso si tratta del <div> che contiene una SVG Canvas <svg>.
Nell’istruzione “if” verifichiamo che, nella TouchList (array di oggetti tocco), ci sia un unico valore e che esista; ricordiamo che l’evento si verifica e ripete ad ogni tocco e monitora il tocco su l’elemento del DOM.
A questo punto agganciamo l’oggetto-tocco con indice “0”, il primo, presente nella TouchList mediante la proprietà “.tragetTouches” e ne manipoliamo la visualizzazione.

La differenza sostanziale tra le proprietà “.touches” e “.targetTouches” è che la prima monitora i tocchi su tutto lo schermo, mentre la seconda monitora i tocchi su di un elemento specifico.

L’esempio qui sopra non funziona alla perfezione; il motivo è semplice dobbiamo vedere l’elemento a cui associamo l’evento “touchstart” come ad un pad-di-rivelamento tocchi; se fosse stato a piena pagina le coordinate clientY e clientX del tocco, recuperate da tutta la schermata del browser sarebbero coincise con il box pad-di-rilevamento.
Questo chiaramente non avviene perché il box pad-di-rilevamento è un blocco contenuto nella pagina e quindi sarà posizionato in posizioni diverse rispetto al client in base allo scroll dell’utente;
Nell’esempio abbiamo diviso il valore rilevato per 2, per l’asse Y, in modo da poter mostrare un pseudo risultato accettabile.
Ho deciso di lasciare questo errore in quanto lo ritengo utile per comprendere a pieno l’argomento.

Mostriamo ora il risultato corretto in una pagina dedicata esterna a questo blog, rimuovendo anche la divisione applicata.
CLICCA QUI

touchmove Event

In questo esempio utilizzeremo l’evento “touchmove” e sempre la proprietà “targetTouches”. L’evento monitora quando trasciniamo, senza sollevarlo, il dito sullo schermo, mentre la proprietà restituisce una TouchList di tocchi rilevati nell’elemento.
Per realizzare questo esempio, una sorta di lavagna per disegnare, utilizzeremo <canvas> anziché <svg>, ed sfrutteremo i relativi metodi per la creazione di disegni

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

canvas.addEventListener("touchmove", function(touchEvent) {
	var tocco;
	for (var i = 0; i < touchEvent.targetTouches.length; i++) {
		tocco = touchEvent.targetTouches[i];
		context.beginPath();
		context.arc(tocco.pageX, tocco.pageY, 4, 0, 2*Math.PI, true);
		context.strokeStyle = "green";
		context.fillStyle = "green";
		context.fill();
		context.stroke();
	}
});
L’immagine è un link ad una pagina esterna al blog

API Pointer Events

L’approccio dell’API Pointer Events risulta molto più semplificato.
L’API mette a disposizione una serie di eventi che possono essere generati indifferentemente da qualsiasi dispositivo di puntamento: mouse, dita, penna ed in sostanza lo sviluppatore dovrà gestire sempre lo stesso evento indipendentemente dal dispositivo.

Eventi

EventoDescrizione
pointerdownsi verifica quando viene avviata l’interazione con lo schermo mediante un dispositivo di puntamento
pointerentersi verifica quando un dispositivo di puntamento entra nell’area occupata da un elemento della pagina (l’evento non prevede la fase di bubbling)
pointerleavesi verifica quando un dispositivo di puntamento lascia l’area occupata da un elemento ( l’evento non prevede la fase di bubbling)
pointermovesi verifica quando un dispositivo di puntamento si sposta
pointeroutsi verifica quando un dispositivo di puntamento entra nell’area occupata da un elemento della pagina; è analogo a pointerleave, ma prevede la fase di bubbling
pointeroversi verifica quando un dispositivo di puntamento entra nell’area occupata da un elemento della pagina; è analogo a pointerenter, ma prevede la fase di bubbling
pointerupsi verifica quando viene interrotta l’interazione, cioè quando viene rilasciato il pulsante del mouse o quando non c’è più contatto tra schermo e dispositivo di puntamento

L’utilizzo rimane il medesimo, sarà restituito sempre un oggetto “event” che chiameremo “pointerEvent”

element.addEventListener('pointerdown',function(pointerEvent){
...
});

Oltre alla gestione unificata dei dispositivi di puntamento questa API ci agevola sotto molti altri aspetti.

A differenza dell’API TouchEvent con l’API PointerEvent, non dovremo preoccuparci di iterare l’elenco dei punti di contatto associati all’evento questo perchè in questo caso ciascun punto di contatto è indipendente dall’altro nella generazione degli eventi.

Si tratta di un approccio del tutto differente, anziché preoccuparci di gestire i casi di più punti di contatto dovremo occuparci dei singoli punti di contatto e come vedremo più avanti avremo a disposizione la proprietà “.isPrimary” per farlo.

Inoltre come l’oggetto “PointerEvent” passato come argomento al gestore di evento contiene direttamente le informazioni sul punto di contatto.

Punti di contattoAPI TouchEventAPI PointerEvent
gestione dei differenti dispositivisino
iterare punti di contattosino
identificare singolo puntonosi (facilitato)
recuperare coordinate del punto sino

PointerEvent Object

L’oggetto event alias “PointerEvent” passato al gestore dell’evento prevede, oltre alle proprietà “clientX” e “clientY” che consentono di individuare le coordinate del punto di contatto ulteriori proprietà che consentono di avere maggiori informazioni sul dispositivo di puntamento e sul punto di contatto.

ProprietàDescrizione
heightaltezza in pixel del punto di contatto
widthlargezza in pixel del punto di contatto
isPrimaryconsente di individuare un punto di contatto come primario in un contesto multi-touch
pointerIdè l’identificatore univoco del punto di contatto
pointerTypeindica se il punto di contatto è stato generato da un mouse (“mouse”), una penna (“pen”) o un dito (“touch”)
pressureesprime il grado di pressione del punto di contatto sullo schermo tramite un valore decimale che va da zero (pressione minima) a uno (pressione massima)

L’evento pointerdown

Sfruttando i numerosi vantaggi proposti da quest’API potremo realizzare i precedenti esempi generati con l’API TouchEvent

var box2 = document.getElementById("box2");
var mostraTocco2 = document.getElementById("cerchio2");

box2.addEventListener("pointerdown", function(pointerEvent) {
	if (pointerEvent.isPrimary){
        mostraTocco2.style.visibility="visible";
        mostraTocco2.setAttribute('cy', `${Math.floor(pointerEvent.clientY/2)}px`);
        mostraTocco2.setAttribute('cx', `${Math.floor(pointerEvent.clientX)}px`);
	}
});

Nell’esempio abbiamo sfruttato la proprietà “.isPrimary” che ne verifica l’esistenza e prende in considerazione il primo tocco anche se proviamo a trascinare il dito senza sollevarlo.
Essendo incapsulato tutti all’interno di un istruzione “if” potremo richiamare il tocco-singolo richiamando direttamente l’oggetto “pointerEvent”.

L’evento pointermove

var canvas2 = document.getElementById("canvas2");
var context2 = canvas2.getContext("2d");

canvas2.addEventListener("pointermove",function(pointerEvent){
		context2.beginPath();
		context2.arc(pointerEvent.pageX, pointerEvent.pageY, 4, 0, 2*Math.PI, true);
		context2.strokeStyle = "green";
		context2.fillStyle = "green";
		context2.fill();
		context2.stroke();
	});

In questo esempio abbiamo utilizzato l’evento “pointermove” e non abbiamo avuto bisogno di iterare i punti di contatto.
Tutto questo restituisce notevoli vantaggi per la rapidità di sviluppo.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *