Desarrollo web con múltiples puntos de contacto

Introducción

Los dispositivos móviles, como los smartphones y las tablets, suelen tener una pantalla capacitiva sensible al tacto 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 rápido requiere que el jugador presione varios botones a la vez, lo que, en el contexto de una pantalla táctil, implica la función de varios toques.

Apple presentó su API de eventos táctiles en iOS 2.0. Android se ha estado poniendo al día con este estándar de facto y está reduciendo la brecha. Recientemente, un grupo de trabajo del W3C se reunió para trabajar en esta especificación de eventos táctiles.

En este artículo, analizaremos la API de eventos táctiles que proporcionan los dispositivos iOS y Android, así como la versión de Chrome para computadoras de escritorio en hardware compatible con pantallas táctiles. También 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 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 DOM.

Cada evento táctil incluye tres listas de toques:

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

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

  • identifier: Es un número que identifica de forma única el dedo actual en la sesión táctil.
  • target: Es el elemento DOM que fue el objetivo de la acción.
  • Coordenadas del cliente, la página o la pantalla: Indican dónde se produjo la acción en la pantalla.
  • radio de coordenadas y ángulo de rotación: Describen la elipse que se aproxima a la forma del dedo.

Apps compatibles con el modo táctil

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

Este fragmento te permite arrastrar un elemento DOM con 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 que muestra todos los toques actuales en la pantalla. Es útil solo para hacerse una idea de la capacidad de respuesta del dispositivo.

Seguimiento 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 hay varias demostraciones interesantes de la función multitáctil, como esta de dibujo basado en lienzo de Paul Irish y otros.

Captura de pantalla de dibujo

Y Browser Ninja, una demostración tecnológica que es un clon de Fruit Ninja que usa transformaciones y transiciones de CSS3, así como lienzo:

Ninja de navegador

Prácticas recomendadas

Evitar el zoom

La configuración predeterminada no funciona muy bien para la función de varios toques, ya que los deslizamientos y los gestos suelen asociarse con el comportamiento del navegador, como el desplazamiento y el zoom.

Para inhabilitar el zoom, configura la ventana de visualización para que no sea escalable por el usuario con la siguiente metaetiqueta:

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

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

Cómo evitar el desplazamiento

Algunos dispositivos móviles tienen comportamientos predeterminados para el gesto de desplazamiento táctil, como el efecto de desplazamiento excesivo clásico de iOS, que hace que la vista rebote cuando el desplazamiento supera los límites del contenido. Esto es confuso en muchas aplicaciones de varios toques y se puede inhabilitar fácilmente:

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

Procesa 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 estarás controlando muchos a la vez. Considera la muestra de la sección anterior que dibuja 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 se ajusta a la cantidad de dedos en la pantalla. En su lugar, puedes hacer un seguimiento de todos los dedos y renderizar 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);

Usa los atributos targetTouches y changedTouches.

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

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

Dispositivos compatibles

Lamentablemente, las implementaciones de eventos táctiles varían mucho en cuanto a su finalización y calidad. Escribí una secuencia de comandos de diagnóstico que muestra información básica sobre la implementación de la API de toque, incluidos los eventos compatibles y la resolución de activación de touchmove. Probé Android 2.3.3 en hardware Nexus One y Nexus S, Android 3.0.1 en Xoom y 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 de toque adicionales, pero ningún navegador probado los admite:

  • touchenter: Un dedo en movimiento ingresa a un elemento DOM.
  • touchleave: Un dedo en movimiento 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 toques, targetTouches y changedTouches. Sin embargo, ninguno de los navegadores probados admite radiusX, radiusY o rotationAngle, que especifican la forma del dedo que toca la pantalla.

Durante un evento de desplazamiento táctil, los eventos se activan aproximadamente 60 veces por segundo en todos los dispositivos probados.

Android 2.3.3 (Nexus)

En el navegador Android Gingerbread (probado en Nexus One y Nexus S), no hay compatibilidad con varios toques. Este es un problema conocido.

Android 3.0.1 (Xoom)

En el navegador Xoom, se ofrece compatibilidad básica con varios toques, pero solo funciona en un único elemento del DOM. El navegador no responde correctamente a dos toques simultáneos en diferentes elementos 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 se hará 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 admiten completamente la función de varios toques, pueden hacer un seguimiento de varios dedos y proporcionan una experiencia táctil muy responsiva en el navegador.

Herramientas para desarrolladores

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

Tener que realizar pruebas en dispositivos móviles puede alargar tu 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 puedes hacer mucho para depurar tu aplicación, ya que las tablets y los smartphones carecen de herramientas para desarrolladores web.

Una solución a este problema es simular eventos táctiles en tu máquina de desarrollo. En el caso de los toques individuales, los eventos táctiles se pueden simular en función de los 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 proporciona emulación de eventos táctiles desde las herramientas para desarrolladores. Abre las Herramientas para desarrolladores, selecciona el ícono de Configuración, luego "Anulaciones" o "Emulación" y activa "Emulación de eventos táctiles".

En otros navegadores, te recomendamos que pruebes Phantom Limb, que simula eventos táctiles en las páginas y también muestra una mano gigante.

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

Eventos de varios toques

Para permitir que tu aplicación web multitáctil funcione en tu navegador en el panel táctil multitáctil (como un Apple MacBook o MagicPad), creé el polyfill MagicTouch.js. Captura eventos táctiles del panel táctil y los convierte en eventos táctiles compatibles con estándares.

  1. Descarga e instala el complemento NPAPI npTuioClient en ~/Library/Internet Plug-Ins/.
  2. Descarga la app de TongSeng TUIO para MagicPad de Mac e inicia el servidor.
  3. Descarga MagicTouch.js, una biblioteca de JavaScript que simula eventos táctiles compatibles con las especificaciones basadas en devoluciones de llamada de npTuioClient.
  4. Incluye la secuencia de comandos magictouch.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.

Hay una demostración en vivo con magictouch.js disponible en paulirish.com/demo/multi:

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

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

Ten en cuenta que tus gestos pueden ser idénticos a los gestos de varios toques del nivel del SO. En OS X, puedes configurar eventos en todo el sistema. Para ello, ve al 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 ver que las nuevas aplicaciones web aprovechen al máximo esta API enriquecida.