Desenvolvimento da Web multitoque

Introdução

Dispositivos móveis, como smartphones e tablets, geralmente têm uma tela capacitiva sensível ao toque para capturar interações feitas com os dedos do usuário. À medida que a Web para dispositivos móveis evolui para permitir aplicativos cada vez mais sofisticados, os desenvolvedores da Web precisam de uma maneira de lidar com esses eventos. Por exemplo, quase todos os jogos de ritmo mais rápido exigem que o jogador pressione vários botões de uma vez, o que, no contexto de uma tela touchscreen, implica multitoque.

A Apple introduziu sua API de eventos de toque no iOS 2.0. O Android está acompanhando esse padrão e preenchendo a lacuna. Recentemente, um grupo de trabalho do W3C se reuniu para trabalhar nessa especificação de eventos de toque.

Neste artigo, vou analisar a API de eventos de toque fornecida por dispositivos iOS e Android e o Chrome para computador em hardwares compatíveis com toque. Também conheceremos os tipos de aplicativos que você pode criar, apresentar algumas práticas recomendadas e abordar técnicas úteis que facilitam o desenvolvimento de aplicativos com toque.

Eventos de toque

Três eventos de toque básicos são descritos na especificação e implementados amplamente em dispositivos móveis:

  • touchstart: um dedo é colocado em um elemento DOM.
  • touchmove: um dedo é arrastado ao longo de um elemento DOM.
  • touchend: um dedo é removido do elemento DOM.

Cada evento de toque inclui três listas de toques:

  • touches: uma lista de todos os dedos atualmente na tela.
  • targetTouches: uma lista de dedos no elemento DOM atual.
  • changedTouches: uma lista de dedos envolvidos no evento atual. Por exemplo, em um evento touchend, será o dedo que foi removido.

Essas listas consistem em objetos que contêm informações de toque:

  • identifier: um número que identifica exclusivamente o dedo que está na sessão de toque.
  • target: o elemento DOM que foi alvo da ação.
  • coordenadas de cliente/página/tela: onde na tela a ação aconteceu.
  • coordenadas de raio e rotationAngle: descreve a elipse aproximada do formato do dedo.

Apps por toque

Os eventos touchstart, touchmove e touchend fornecem um conjunto de recursos avançado o suficiente para permitir praticamente qualquer tipo de interação por toque, incluindo todos os gestos multitoque habituais, como zoom de pinça, rotação e assim por diante.

Este snippet permite arrastar um elemento DOM usando o toque de um único 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);

Confira abaixo um exemplo que mostra todos os toques atuais na tela. É útil apenas para ter uma sensação da capacidade de resposta do dispositivo.

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

Demonstrações

Várias demonstrações interessantes com vários toques já estão disponíveis, como esta demonstração de desenhos baseados em tela de Paul Irlanda e outros profissionais.

Captura de tela do desenho

E o Browser Ninja, uma demonstração técnica que é um clone do Fruit Ninja usando transformações e transições CSS3, além do canvas:

Ninja do navegador

Práticas recomendadas

Impedir zoom

As configurações padrão não funcionam muito bem para multitoque, já que gestos de deslizar e gestos geralmente estão associados ao comportamento do navegador, como rolagem e zoom.

Para desativar o zoom, configure a janela de visualização de modo que não seja escalonável pelo usuário usando a seguinte metatag:

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

Confira este artigo sobre HTML5 para dispositivos móveis para mais informações sobre como configurar sua janela de visualização.

Impedir a rolagem

Alguns dispositivos móveis têm comportamentos padrão para a movimentação de toque, como o efeito de rolagem clássico do iOS, que faz com que a visualização seja retornada quando a rolagem excede os limites do conteúdo. Isso é confuso em muitos aplicativos multitoque e pode ser facilmente desativado:

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

Renderize com cuidado

Se você estiver criando um aplicativo multitoque que envolva gestos complexos com vários dedos, tenha cuidado com a forma como você reage a eventos de toque, já que você lida com muitos de uma só vez. Considere o exemplo na seção anterior, que desenha todos os toques na tela. Você pode desenhar assim que houver uma entrada de toque:

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

Mas essa técnica não é escalonada conforme o número de dedos na tela. Em vez disso, é possível rastrear todos os dedos e renderizar em um loop para ter um desempenho muito melhor:

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

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

Uso de targetTouches e changedTouches

Lembre-se de que event.touches é uma matriz de TODOS os dedos em contato com a tela, não apenas aqueles no destino do elemento DOM. Pode ser muito mais útil usar event.targetTouches ou event.changeTouches.

Por fim, já que você está desenvolvendo para dispositivos móveis, é importante conhecer as práticas recomendadas gerais para dispositivos móveis. Elas são abordadas no artigo de Eric Bidelman (em inglês) e neste documento do W3C (links em inglês).

Suporte do dispositivo

Infelizmente, as implementações de eventos de toque variam muito em termos de integridade e qualidade. Criei um script de diagnóstico que mostra algumas informações básicas sobre a implementação da API Touch, incluindo quais eventos são compatíveis e a resolução de disparo do touchmove. Testei o Android 2.3.3 nos hardwares Nexus One e Nexus S, o Android 3.0.1 no Xoom e o iOS 4.2 no iPad e iPhone.

Em resumo, todos os navegadores testados são compatíveis com os eventos touchstart, touchend e touchmove.

A especificação fornece três eventos de toque adicionais, mas nenhum navegador testado oferece suporte a eles:

  • touchenter: um dedo em movimento entra em um elemento DOM.
  • touchleft: um dedo em movimento sai de um elemento DOM.
  • touchcancel: um toque é interrompido (específico para implementação).

Dentro de cada lista de toques, os navegadores testados também oferecem as listas de toque touches, targetTouches e changeTouches. No entanto, nenhum navegador testado é compatível com radiusX, radiusY ou rotationAngle, que especificam o formato do dedo que toca na tela.

Durante um movimento de toque, os eventos são disparados aproximadamente 60 vezes por segundo em todos os dispositivos testados.

Android 2.3.3 (Nexus)

No navegador Gingerbread do Android (testado no Nexus One e no Nexus S), não há suporte a multitoque. Esse é um problema conhecido.

Android 3.0.1 (Xoom)

No navegador do Xoom, há suporte multitoque básico, mas ele só funciona em um único elemento DOM. O navegador não responde corretamente a dois toques simultâneos em diferentes elementos do DOM. Em outras palavras, o comando a seguir reagirá a dois 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);

No entanto, as ações a seguir não:

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)

Os dispositivos iOS são totalmente compatíveis com o multitoque, conseguem rastrear vários dedos e fornecem uma experiência de toque muito responsiva no navegador.

Ferramentas para desenvolvedores

No desenvolvimento para dispositivos móveis, geralmente é mais fácil começar a prototipagem no computador e depois lidar com as partes específicas para dispositivos móveis nos dispositivos que você pretende oferecer suporte. O multitoque é um dos recursos difíceis de testar no PC, já que a maioria dos PCs não tem entrada por toque.

A necessidade de fazer testes em dispositivos móveis pode aumentar o ciclo de desenvolvimento, já que todas as mudanças feitas precisam ser enviadas a um servidor e carregadas no dispositivo. Após a execução, não há muito o que fazer para depurar o aplicativo, já que tablets e smartphones não têm ferramentas para desenvolvedores da Web.

Uma solução para esse problema é simular eventos de toque na máquina de desenvolvimento. Para toques únicos, eventos de toque podem ser simulados com base em eventos do mouse. Eventos multitoque podem ser simulados se você tiver um dispositivo com entrada por toque, como um moderno MacBook da Apple.

Eventos de toque único

Se você quiser simular eventos de toque único no seu computador, o Chrome oferece a emulação de eventos de toque das ferramentas para desenvolvedores. Abra as ferramentas para desenvolvedores, selecione o ícone de engrenagem "Configurações" e "Substituições" ou "Emulação" e ative a opção "Emular eventos de toque".

Para outros navegadores, você pode testar o Phantom Limb, que simula eventos de toque em páginas e também ajuda na inicialização.

Há também o plug-in jQuery Touchable, que unifica os eventos de toque e mouse em todas as plataformas.

Eventos multitoque

Crie o polyfill MagicTouch.js (link em inglês) para que seu aplicativo da Web multitoque funcione no navegador no seu trackpad multitoque (como um MacBook da Apple ou o MagicPad). Ele captura eventos de toque do trackpad e os transforma em eventos de toque compatíveis com o padrão.

  1. Faça o download e instale o plug-in npTuioClient NPAPI em ~/Library/Internet Plug-Ins/.
  2. Faça o download do app TongSeng TUIO para o MagicPad do Mac e inicie o servidor.
  3. Faça o download da MagicTouch.js, uma biblioteca JavaScript para simular eventos de toque compatíveis com as especificações com base em callbacks do npTuioClient.
  4. Inclua o script magictouch.js e o plug-in npTuioClient no aplicativo da seguinte maneira:
<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>

Talvez seja necessário ativar o plug-in.

Uma demonstração ao vivo do magictouch.js está disponível em paulirish.com/demo/multi (link em inglês):

Teste essa abordagem apenas com o Chrome 10, mas ela deve funcionar em outros navegadores modernos com apenas pequenos ajustes.

Caso seu computador não tenha entrada multitoque, é possível simular eventos de toque usando outros rastreadores TUIO, como o reacTIVision. Para mais informações, consulte a página do projeto TUIO (em inglês).

Seus gestos podem ser idênticos aos gestos multitoque no nível do SO. No OS X, você pode configurar eventos do sistema acessando o painel de preferências do trackpad nas preferências do sistema.

À medida que os recursos multitoque se tornam mais compatíveis com navegadores de dispositivos móveis, estou muito animado para ver os novos aplicativos da Web aproveitarem ao máximo essa avançada API.