Sviluppo web multi-touch

Boris Smus
Boris Smus

Introduzione

I dispositivi mobili come smartphone e tablet in genere hanno uno schermo capacitivo e sensibile al tocco per acquisire le interazioni effettuate con le dita dell'utente. Con l'evoluzione del web mobile per consentire applicazioni sempre più sofisticate, gli sviluppatori web hanno bisogno di un modo per gestire questi eventi. Ad esempio, quasi tutti i giochi dal ritmo serrato richiedono di premere più pulsanti contemporaneamente, il che, nel contesto di un touchscreen, implica il multi-touch.

Apple ha introdotto la sua API di eventi tocco in iOS 2.0. Android si sta adeguando a questo standard di fatto e sta colmando il divario. Di recente, un gruppo di lavoro del W3C si è riunito per lavorare a questa specifica degli eventi tocco.

In questo articolo analizzerò l'API degli eventi tocco fornita dai dispositivi iOS e Android, nonché da Chrome desktop su hardware che supporta il tocco, e illustrerò i tipi di applicazioni che puoi creare, alcune best practice e tecniche utili che semplificano lo sviluppo di applicazioni con tocco.

Eventi touch

Le specifiche descrivono tre eventi touch di base, ampiamente implementati sui dispositivi mobili:

  • touchstart: un dito viene posizionato su un elemento DOM.
  • touchmove: un dito viene trascinato lungo un elemento DOM.
  • touchend: un dito viene rimosso da un elemento DOM.

Ogni evento tocco include tre elenchi di tocchi:

  • touches: un elenco di tutti i tocchi attualmente sullo schermo.
  • targetTouches: un elenco di dita sull'elemento DOM corrente.
  • changedTouches: un elenco di dita coinvolte nell'evento corrente. Ad esempio, in un evento di touchend, questo sarà il dito che è stato rimosso.

Questi elenchi sono costituiti da oggetti che contengono informazioni sui tocchi:

  • identifier: un numero che identifica in modo univoco il dito corrente nella sessione di tocco.
  • target: l'elemento DOM che era il target dell'azione.
  • coordinate client/pagina/schermata: la posizione sullo schermo in cui si è verificata l'azione.
  • radius coordinates e rotationAngle: descrivono l'ellisse che approssima la forma del dito.

App compatibili con il tocco

Gli eventi touchstart, touchmove e touchend offrono un set di funzionalità abbastanza completo per supportare praticamente qualsiasi tipo di interazione basata sul tocco, compresi tutti i normali gesti multi-touch come pizzicatura, zoom, rotazione e così via.

Questo snippet ti consente di trascinare un elemento DOM utilizzando un singolo dito:

var obj = document.getElementById('id');
obj.addEventListener('touchmove', function(event) {
  // If there's exactly one finger inside this element
  if (event.targetTouches.length == 1) {
    var touch = event.targetTouches[0];
    // Place element where the finger is
    obj.style.left = touch.pageX + 'px';
    obj.style.top = touch.pageY + 'px';
  }
}, false);

Di seguito è riportato un esempio che mostra tutti i tocchi correnti sullo schermo. È utile solo per farsi un'idea della reattività del dispositivo.

Rilevamento dei movimenti delle dita.
// Setup canvas and expose context via ctx variable
canvas.addEventListener('touchmove', function(event) {
  for (var i = 0; i < event.touches.length; i++) {
    var touch = event.touches[i];
    ctx.beginPath();
    ctx.arc(touch.pageX, touch.pageY, 20, 0, 2*Math.PI, true);
    ctx.fill();
    ctx.stroke();
  }
}, false);

Demo

Esistono già diverse demo multi-touch interessanti, come questa demo di disegno basato su canvas di Paul Irish e altri.

Screenshot del disegno

E Browser Ninja, una demo tecnica che è un clone di Fruit Ninja che utilizza trasformazioni e transizioni CSS3, nonché canvas:

Ninja del browser

Best practice

Impedire lo zoom

Le impostazioni predefinite non funzionano molto bene per il multi-touch, poiché i gesti e i scorrimenti sono spesso associati al comportamento del browser, come lo scorrimento e lo zoom.

Per disattivare lo zoom, configura l'area visibile in modo che non sia scalabile all'utente utilizzando il seguente meta tag:

<meta name="viewport" 
  content="width=device-width, initial-scale=1.0, user-scalable=no>

Consulta questo articolo su HTML5 per il mobile per saperne di più su come impostare il viewport.

Impedire lo scorrimento

Alcuni dispositivi mobili hanno comportamenti predefiniti per touchmove, ad esempio il classico effetto di scorrimento eccessivo di iOS, che fa tornare indietro la visualizzazione quando lo scorrimento supera i limiti dei contenuti. Ciò crea confusione in molte applicazioni multi-touch e può essere facilmente disattivato:

document.body.addEventListener('touchmove', function(event) {
  event.preventDefault();
}, false); 

Esegui il rendering con attenzione

Se stai scrivendo un'applicazione multi-touch che prevede gesti con più dita complessi, fai attenzione a come reagisci agli eventi tocco, poiché ne gestirai molti contemporaneamente. Considera l'esempio nella sezione precedente che disegna tutti i tocchi sullo schermo. Puoi disegnare non appena viene rilevato un input touch:

canvas.addEventListener('touchmove', function(event) {
  renderTouches(event.touches);
}, false);

Tuttavia, questa tecnica non è scalabile in base al numero di dita sullo schermo. In alternativa, puoi monitorare tutti i polpastrelli e eseguire il rendering in un loop per ottenere un rendimento molto migliore:

var touches = []
canvas.addEventListener('touchmove', function(event) {
  touches = event.touches;
}, false);

// Setup a 60fps timer
timer = setInterval(function() {
  renderTouches(touches);
}, 15);

Utilizza targetTouches e changedTouches

Ricorda che event.touches è un array di TUTTI i dita a contatto con lo schermo, non solo quelli sul target dell'elemento DOM. Potrebbe essere molto più utile usare invece event.targetTouches o event.changedTouches.

Infine, poiché stai sviluppando per il mobile, devi conoscere le best practice generali per i dispositivi mobili, che sono trattate nell'articolo di Eric Bidelman, nonché in questo documento del W3C.

Assistenza per i dispositivi

Purtroppo, le implementazioni degli eventi touch variano notevolmente in termini di completezza e qualità. Ho scritto uno script di diagnostica che mostra alcune informazioni di base sull'implementazione dell'API touch, inclusi gli eventi supportati e la risoluzione dell'attivazione di touchmove. Ho testato Android 2.3.3 sull'hardware Nexus One e Nexus S, Android 3.0.1 su Xoom e iOS 4.2 su iPad e iPhone.

In breve, tutti i browser testati supportano gli eventi touchstart, touchend e touchmove.

Le specifiche forniscono tre eventi touch aggiuntivi, ma nessun browser testato li supporta:

  • touchenter: un dito in movimento entra in un elemento DOM.
  • touchleave: un dito in movimento esce da un elemento DOM.
  • touchcancel: un tocco viene interrotto (specifico dell'implementazione).

All'interno di ogni elenco di tocchi, i browser testati forniscono anche gli elenchi di tocchi touches, targetTouches e changedTouches. Tuttavia, nessun browser testato supporta radiusX, radiusY o rotationAngle, che specificano la forma del dito che tocca lo schermo.

Durante un evento touchmove, gli eventi vengono attivati circa 60 volte al secondo su tutti i dispositivi testati.

Android 2.3.3 (Nexus)

Nel browser Android Gingerbread (testato su Nexus One e Nexus S), non è supportato il multi-touch. Si tratta di un problema noto.

Android 3.0.1 (Xoom)

Sul browser di Xoom è disponibile il supporto multi-touch di base, che però funziona solo su un singolo elemento DOM. Il browser non risponde correttamente a due tocchi simultanei su elementi DOM diversi. In altre parole, il seguente reagirà a due tocchi simultanei:

obj1.addEventListener('touchmove', function(event) {
  for (var i = 0; i < event.targetTouches; i++) {
    var touch = event.targetTouches[i];
    console.log('touched ' + touch.identifier);
  }
}, false);

ma non:

var objs = [obj1, obj2];
for (var i = 0; i < objs.length; i++) {
  var obj = objs[i];
  obj.addEventListener('touchmove', function(event) {
    if (event.targetTouches.length == 1) {
      console.log('touched ' + event.targetTouches[0].identifier);
    }
  }, false);
}

iOS 4.x (iPad, iPhone)

I dispositivi iOS supportano completamente il multi-touch, sono in grado di monitorare diversi dita e offrono un'esperienza touch molto reattiva nel browser.

Strumenti per sviluppatori

Nello sviluppo mobile, spesso è più facile iniziare a creare prototipi su computer per poi affrontare le parti specifiche per il mobile sui dispositivi che intendi supportare. Il multi-touch è una di quelle funzionalità difficili da testare su PC, dato che la maggior parte dei PC non ha input tocco.

Dover eseguire test su dispositivi mobili può prolungare il ciclo di sviluppo, poiché ogni modifica apportata deve essere inviata a un server e poi caricata sul dispositivo. Una volta eseguita, non puoi fare molto per eseguire il debug della tua applicazione, poiché i tablet e gli smartphone non dispongono degli strumenti per gli sviluppatori web.

Una soluzione a questo problema consiste nel simulare gli eventi tocco sulla macchina di sviluppo. Per i tocchi singoli, gli eventi touch possono essere simulati in base agli eventi del mouse. Gli eventi multi-touch possono essere simulati se hai un dispositivo con input touch, ad esempio un Apple MacBook moderno.

Eventi con un solo tocco

Se vuoi simulare eventi con un solo tocco sul computer, Chrome fornisce l'emulazione degli eventi tocco dagli strumenti per sviluppatori. Apri Strumenti per sviluppatori, seleziona l'icona a forma di ingranaggio Impostazioni, quindi "Override" o "Emulazione" e attiva l'opzione "Emula eventi tocco".

Per altri browser, ti consigliamo di provare Phantom Limb, che simula gli eventi tocco sulle pagine e offre anche una mano gigante.

Esiste anche il plug-in jQuery Touchable che unifica gli eventi touch e del mouse su più piattaforme.

Eventi multi-touch

Per consentire all'applicazione web multi-touch di funzionare nel browser sul trackpad multi-touch (ad esempio Apple MacBook o MagicPad), ho creato il polyfill MagicTouch.js. Acquisisce gli eventi touch dal trackpad e li trasforma in eventi touch compatibili con lo standard.

  1. Scarica e installa il plug-in NPAPI npTuioClient in ~/Library/Internet Plug-Ins/.
  2. Scarica l'app TongSeng TUIO per MagicPad di Mac e avvia il server.
  3. Scarica MagicTouch.js, una libreria JavaScript per simulare eventi tocco compatibili con le specifiche in base ai callback di npTuioClient.
  4. Includi lo script magictouch.js e il plug-in npTuioClient nella app come segue:
<head>
  ...
  <script src="/path/to/magictouch.js"></script>
</head>

<body>
  ...
  <object id="tuio" type="application/x-tuio" style="width: 0px; height: 0px;">
    Touch input plugin failed to load!
  </object>
</body>

Potrebbe essere necessario attivare il plug-in.

Una demo dal vivo con magictouch.js è disponibile all'indirizzo paulirish.com/demo/multi:

Ho testato questo approccio solo con Chrome 10, ma dovrebbe funzionare su altri browser moderni con solo piccole modifiche.

Se il tuo computer non dispone di input multi-touch, puoi simulare gli eventi di tocco utilizzando altri tracker TUIO, come reacTIVision. Per maggiori informazioni, consulta la pagina del progetto TUIO.

Tieni presente che i gesti potrebbero essere identici a quelli multi-touch a livello di sistema operativo. Su OS X, puoi configurare eventi a livello di sistema utilizzando il riquadro Preferenze del trackpad nelle Preferenze di Sistema.

Man mano che le funzionalità multi-touch vengono supportate sempre più ampiamente nei browser mobile, sono molto felice di vedere nuove applicazioni web sfruttare appieno questa API completa.