Desarrollo web con múltiples puntos de contacto

Introducción

Los dispositivos móviles, como smartphones y tablets, suelen tener una pantalla capacitiva táctil para capturar las interacciones que realiza el usuario con los dedos. A medida que la Web móvil evoluciona para permitir aplicaciones cada vez más sofisticadas, los desarrolladores web necesitan una forma de controlar estos eventos. Por ejemplo, casi cualquier juego de ritmo acelerado requiere que el jugador presione varios botones a la vez, lo que, en el contexto de una pantalla táctil, implica la función multitáctil.

Apple presentó su API de eventos táctiles en iOS 2.0. Android se pone al día con este estándar de facto y reduce las diferencias. Recientemente, un grupo de trabajo de W3C se unió para trabajar en esta especificación de eventos táctiles.

En este artículo, profundizaremos en la API de eventos táctiles que proporcionan los dispositivos iOS y Android, así como en Chrome para computadoras de escritorio en hardware compatible con el tacto, y exploraremos qué tipos de aplicaciones puedes compilar, presentaremos algunas prácticas recomendadas y abordaremos técnicas útiles que facilitan el desarrollo de aplicaciones táctiles.

Eventos táctiles

En la especificación, se describen tres eventos táctiles básicos que se implementan de forma amplia en los dispositivos móviles:

  • touchstart: Se coloca un dedo en un elemento del DOM.
  • touchmove: Se arrastra un dedo a lo largo de un elemento DOM.
  • touchend: Se quita un dedo de un elemento del DOM.

Cada evento táctil incluye tres listas de toques:

  • touches: Una lista de todos los dedos actualmente en la pantalla
  • targetTouches: lista de dedos sobre el elemento actual del DOM.
  • changedTouches: lista de dedos involucrados en el evento actual. Por ejemplo, en un evento de touchend, este será el dedo que se quitó.

Estas listas consisten en objetos que contienen información táctil:

  • Identificador: Un número que identifica de forma inequívoca el dedo actual en la sesión táctil.
  • target: Es el elemento del DOM que era el objetivo de la acción.
  • coordenadas de cliente/página/pantalla: Indica el lugar de la pantalla en el que se realizó la acción.
  • coordenadas de radio y rotationAngle: Describe la elipse que se aproxima a la forma del dedo.

Apps táctiles

Los eventos touchstart, touchmove y touchend proporcionan un conjunto de atributos lo suficientemente amplio como para admitir prácticamente cualquier tipo de interacción táctil, incluidos todos los gestos multitáctiles habituales, como pellizcar el zoom, rotar, etcétera.

Este fragmento te permite arrastrar un elemento del DOM mediante el toque de un solo dedo:

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

A continuación, se muestra un ejemplo en el que se muestran todos los toques actuales en la pantalla. Es útil solo para conocer la capacidad de respuesta del dispositivo.

Rastreo de dedos.
// 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);

Demostraciones

Ya existen varias demostraciones interesantes de múltiples puntos de contacto, como esta demostración de dibujo basado en lienzos de Paul Ireland y otros.

Captura de pantalla de dibujo

Y Browser Ninja, una demostración de tecnología que es una clonación de Fruit Ninja con transformaciones y transiciones CSS3, así como un lienzo:

navegador ninja

Prácticas recomendadas

Evitar el zoom

La configuración predeterminada no funciona muy bien para la función multitáctil, ya que los deslizamientos y gestos suelen estar asociados con el comportamiento del navegador, como el desplazamiento y el zoom.

Para inhabilitar el zoom, configura el viewport a fin de que no sea escalable para el usuario mediante la siguiente metaetiqueta:

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

Consulta este artículo HTML5 para dispositivos móviles a fin de obtener más información sobre cómo configurar tu viewport.

Evitar el desplazamiento

Algunos dispositivos móviles tienen comportamientos predeterminados para touchmove, como el efecto de sobredesplazamiento clásico de iOS, que hace que la vista rebote cuando el desplazamiento excede los límites del contenido. Esto es confuso en muchas aplicaciones multitáctiles y se puede inhabilitar con facilidad:

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

Renderiza con cuidado

Si escribes una aplicación multitáctil que involucra gestos complejos de varios dedos, ten cuidado con la forma en que reaccionas a los eventos táctiles, ya que controlarás muchos a la vez. Considera la muestra de la sección anterior, en la que se dibujan todos los toques en la pantalla. Puedes dibujar en cuanto haya una entrada táctil:

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

Sin embargo, esta técnica no escala con el número de dedos en la pantalla. En cambio, puedes realizar un seguimiento de todos los dedos y renderizarlos en un bucle para obtener un rendimiento mucho mejor:

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

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

Utiliza targetTouches y changedTouches

Recuerda que event.touches es un array de TODOS los dedos en contacto con la pantalla, no solo los del destino del elemento del DOM. Quizás te resulte mucho más útil usar event.targetTouches o event.changedTouches en su lugar.

Por último, dado que estás desarrollando contenido para dispositivos móviles, debes conocer las prácticas recomendadas generales para este tipo de dispositivos, que se abordan en el artículo de Eric Bidelman, así como en este documento de W3C.

Asistencia para dispositivos

Lamentablemente, las implementaciones de eventos táctiles varían considerablemente en términos de integridad y calidad. Escribí una secuencia de comandos de diagnóstico que muestra información básica sobre la implementación de la API táctil, incluidos los eventos compatibles y la resolución de la activación de touchmove. Probé Android 2.3.3 en hardware de Nexus One y Nexus S, Android 3.0.1 en Xoom e iOS 4.2 en iPad y iPhone.

En resumen, todos los navegadores probados admiten los eventos touchstart, touchend y touchmove.

La especificación proporciona tres eventos táctiles adicionales, pero ningún navegador probado es compatible con ellos:

  • touchenter: Un dedo en movimiento ingresa a un elemento DOM.
  • touchleave: un dedo que se mueve sale de un elemento DOM.
  • touchcancel: Se interrumpe un toque (específico de la implementación).

Dentro de cada lista táctil, los navegadores probados también proporcionan las listas táctiles táctiles, targetTouches y changedTouches. Sin embargo, ninguno de los navegadores probados admite buenaX, RadioY o rotationAngle, que especifican la forma del dedo que toca la pantalla.

Durante un touchmove, los eventos se activan aproximadamente 60 veces por segundo en todos los dispositivos probados.

Android 2.3.3 (Nexus)

En el navegador Gingerbread de Android (que se probó en Nexus One y Nexus S), no hay compatibilidad con la función multitáctil. Este es un problema conocido.

Android 3.0.1 (Xoom)

En el navegador de Xoom, hay compatibilidad básica con la función multitáctil, pero solo funciona en un único elemento del DOM. El navegador no responde correctamente a dos toques simultáneos en diferentes elementos del DOM. En otras palabras, lo siguiente reaccionará a dos toques simultáneos:

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

Sin embargo, no ocurrirá lo siguiente:

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)

Los dispositivos iOS son totalmente compatibles con la función multitáctil, son capaces de rastrear varios dedos y proporcionan una experiencia táctil muy responsiva en el navegador.

Herramientas para desarrolladores

En el desarrollo para dispositivos móviles, suele ser más fácil comenzar a crear prototipos en la computadora de escritorio y, luego, abordar las partes específicas de los dispositivos móviles en los dispositivos que deseas admitir. La función multitáctil es una de esas funciones difíciles de probar en la PC, ya que la mayoría de las PC no tienen entrada táctil.

Tener que realizar pruebas en dispositivos móviles puede prolongar el ciclo de desarrollo, ya que cada cambio que realices debe enviarse a un servidor y, luego, cargarse en el dispositivo. Luego, una vez que se ejecuta, no hay mucho que puedas hacer para depurar tu aplicación, ya que las tablets y los smartphones no cuentan con herramientas para desarrolladores web.

Una solución a este problema es simular los eventos táctiles en la máquina de desarrollo. Para los toques únicos, los eventos táctiles se pueden simular en función de eventos del mouse. Los eventos de varios toques se pueden simular si tienes un dispositivo con entrada táctil, como una Apple MacBook moderna.

Eventos de un solo toque

Si deseas simular eventos de un solo toque en tu computadora de escritorio, Chrome ofrece la emulación de eventos táctiles desde las herramientas para desarrolladores. Abre las Herramientas para desarrolladores, selecciona el ícono de Configuración, elige "Anulaciones" o "Emulación" y activa "Emular eventos táctiles".

En el caso de otros navegadores, tal vez sea buena idea probar Phantom Limb, que simula eventos táctiles en páginas y también permite iniciar aplicaciones con un gran poder.

También existe el complemento de jQuery Touchable que unifica los eventos táctiles y del mouse en todas las plataformas.

Eventos de varios puntos de contacto

Creé el polyfill MagicTouch.js para que la aplicación web multitáctil funcione en el navegador del panel táctil multitáctil (como Apple MacBook o MagicPad). Captura eventos táctiles del panel táctil y los convierte en eventos táctiles compatibles con el estándar.

  1. Descarga y, luego, instala el complemento npTuioClient NPAPI en ~/Library/Internet Plug-Ins/.
  2. Descarga la app de TongSeng TUIO para el MagicPad de Mac y, luego, inicia el servidor.
  3. Descarga MagicTouch.js, una biblioteca de JavaScript que permite simular eventos táctiles compatibles con las especificaciones según las devoluciones de llamada de npTuioClient.
  4. Incluye la secuencia de comandos cleartouch.js y el complemento npTuioClient en tu aplicación de la siguiente manera:
<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>

Es posible que debas habilitar el complemento.

En paulirish.com/demo/multi, encontrará una demostración en vivo con currenttouch.js:

Probé este enfoque solo con Chrome 10, pero debería funcionar en otros navegadores modernos con solo pequeños ajustes.

Si tu computadora no tiene entrada multitáctil, puedes simular eventos táctiles con otros segmentos TUIO, como reacTIVision. Para obtener más información, consulta la página del proyecto de TUIO.

Ten en cuenta que tus gestos pueden ser idénticos a los gestos multitáctiles a nivel del SO. En OS X, puedes configurar eventos de todo el sistema en el panel de preferencias del panel táctil en Preferencias del sistema.

A medida que las funciones de varios toques se vuelven más compatibles con los navegadores para dispositivos móviles, me entusiasma mucho ver que las nuevas aplicaciones web aprovechan al máximo esta API enriquecida.