Desenvolvimento Web multitoque

HTML5 Rocks

Introdução

Dispositivos móveis como smartphones e tablets costumam ter uma tela capacitiva sensível ao toque para capturar interações geradas pelos dedos dos usuários. Conforme a web móvel se desenvolve para possibilitar aplicativos cada vez mais sofisticados, os desenvolvedores da web necessitam de uma forma de gerenciar esses eventos. Por exemplo, quase todos os jogos dinâmicos requerem que o jogador pressione vários botões de uma vez, o que, no contexto de uma tela sensível ao toque, implica a função multitouch.

A Apple introduziu sua API de eventos de toque (link em inglês) no iOS 2.0. O Android está trabalhando para acompanhar esse padrão de-facto e fechar a lacuna. Recentemente, um grupo de trabalho do W3C foi formado para trabalhar nesta especificação de eventos de toque (link em inglês).

Neste artigo, pretendo fazer uma análise minuciosa da API de eventos de toque fornecida pelos dispositivos iOS e Android, explorar que tipos de aplicativos você pode construir, apresentar algumas práticas recomendadas e tratar de técnicas úteis que facilitam o desenvolvimento de aplicativos habilitados para o toque.

Eventos de toque

Três eventos básicos de toque são descritos nas especificações e implementados em grande escala em dispositivos móveis.

  • touchstart: um dedo é colocado em um elemento DOM.
  • touchmove: um dedo é arrastado sobre 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 todos os dedos no atual elemento DOM.
  • changedTouches: uma lista de dedos envolvidos no evento atual. Em um evento touchend, por exemplo, este será o dedo que foi removido.
Essas listas consistem de objetos que contêm informações de toque:
  • identifier: o número que identifica exclusivamente o dedo que participa atualmente 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.

Aplicativos habilitados para toque

Os eventos touchstart, touchmove e touchend fornecem um conjunto de recursos suficientemente avançados para dar suporte virtualmente a qualquer tipo de interação baseada no toque, incluindo todos os gestos multi-touch usuais, como zoom em movimento de pinça, rotação, etc.

Este snippet possibilita que você arraste o elemento DOM pela tela utilizando o toque com um só 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);

Abaixo você encontra uma amostra (link em inglês) que exibe todos os toques atualmente na tela. Ela é útil para termos uma ideia da capacidade de resposta do dispositivo.

(link em inglês)
// 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

Algumas demonstrações interessantes em multi-touch já estão disponíveis, como esta demonstração de desenho baseado em canvas (link em inglês), de Paul Irish e outros autores.

(link em inglês)

E Browser Ninja (link em inglês), uma demonstração tecnológica que é um clone do Fruit Ninja usando transformações e transições CSS3 além do canvas:

(link em inglês)

Melhores práticas

Impedir o zoom

As configurações padrão não funcionam muito bem para o multi-touch, já que os movimentos de deslizar e gestos são com frequência associados ao comportamento do navegador, como rolagem e zoom.

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

<meta name="viewport" 
  content="width=device-width, initial-scale=1.0, user-scalable=no">
Consulte este artigo sobre HTML5 para dispositivos móveis para obter mais informações sobre a configuração da janela de visualização.

Impedir rolagem

Alguns dispositivos móveis têm comportamento padrão para movimentos de toque, como o efeito clássico overscroll do iOS, que faz com que a visualização retorne quando a rolagem excede os limites do conteúdo. Isso pode gerar confusão em aplicativos multi-touch e pode facilmente ser desativado:

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

Renderizar com cuidado

Se estiver construindo um aplicativo multi-touch que envolva gestos complexos com vários dedos, tenha cuidado com as reações a eventos de toque, já que você terá de administrar muitos deles de uma só vez. Considere o exemplo na seção anterior que desenha todos os toques na tela. Você pode desenhar assim que haja entrada de toque:

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

No entanto, a técnica não é escalonada conforme o número de dedos na tela. Em vez disso, você pode rastrear todos os dedos e renderizar um loop para ter desempenho ainda melhor:

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

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

Dica: setInterval não é a opção ideal para animações, pois não considera o loop de renderização do navegador. Navegadores modernos de computadores fornecem requestAnimationFrame, uma opção muito melhor com relação a desempenho e preservação de bateria. Quando compatível com navegadores para dispositivos móveis, esta será a forma preferencial para estes fins.

Use targetTouches e changedTouches

Lembre-se de que event.touches é uma matriz que contém TODOS os dedos em contato com a tela, não apenas aqueles no alvo do elemento DOM. Em vez dela, pode ser muito mais útil usar event.targetTouches ou event.changedTouches.

Por fim, já que desenvolve para interfaces para dispositivos móveis, você deve conhecer as melhores práticas para dispositivos móveis, disponíveis neste artigo do Eric Bidelman (link em inglês) e neste documento do W3C (link em inglês).

Compatibilidade de dispositivos

Infelizmente, a implementação de eventos de toque tem grande variação em completude e qualidade. Escrevi um script de diagnóstico (link em inglês) que exibe informações básicas sobre a implementação da API de toque, incluindo quais eventos são compatíveis e a resolução de acionamento de movimentos touch. Testei o Android 2.3.3 em hardware Nexus One e Nexus S, o Android 3.0.1 no Xoom e o iOS 4.2 no iPad e no iPhone.

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

As especificações oferecem três eventos de toque adicionais, mas nenhum navegador testado é compatível com eles:

  • touchenter: um dedo em movimento entra em um elemento DOM.
  • touchleave: 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 changedTouches. No entanto, nenhum navegador testado oferece suporte para radiusX, radiusY ou rotationAngle, que especificam a forma do toque do dedo na tela.

Durante um movimento de toque, os eventos são acionados em média 60 vezes por segundo em todos os dispositivos testados.

Android 2.3.3 (Nexus)

No navegador Android Gingerbread, testado no Nexus One e no Nexus S, não existe suporte multi-touch. Este é um problema conhecido.

Android 3.0.1 (Xoom)

No navegador Xoom, existe suporte multi-touch 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 DOM. Em outras palavras, isto 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);

Mas isto 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 têm suporte total a multi-touch e são capazes de acompanhar vários dedos e fornecer uma experiência de toque com boa responsividade no navegador.

Ferramentas para desenvolvedores

No desenvolvimento para dispositivos móveis, costuma ser mais fácil criar os protótipos no computador e depois tratar das partes específicas para dispositivos móveis nos dispositivos para os quais você pretende oferecer compatibilidade. O multi-touch é um dos recursos difíceis de testar no PC, já que a maioria dos PCs não tem entrada de toque.

A necessidade de testar em dispositivos móveis pode tornar o ciclo de desenvolvimento mais longo, já que cada mudança feita deve ser enviada a um servidor e carregada no dispositivo. Depois de sua execução, existe pouco que você possa fazer para depurar o aplicativo, já que tablets e smartphones não possuem ferramentas para desenvolvedores da web.

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

Eventos de toque único

Se quiser simular eventos de toque único em seu computador, experimente o Phantom Limb (link em inglês), que simula eventos de toque em páginas e também oferece grande ajuda na inicialização.

Existe também o Touchable (link em inglês), um plug-in jQuery que unifica eventos de toque e de mouse em diferentes plataformas.

Eventos multi-touch

Para possibilitar que seu aplicativo da web multi-touch funcione no navegador com touchpad multi-touch (como o MacBook da Apple ou o MagicPad), eu criei o polyfill MagicTouch.js (link em inglês). Ele captura eventos de toque de seu touchpad e os transforma em eventos de toque compatíveis com o padrão.

  1. Faça download e instale o plug-in npTuioClient da NPAPI (link em inglês) em ~/Library/Internet Plug-Ins/.
  2. Faça download do aplicativo TongSeng em TUIO para o MagicPad da Apple e inicie o servidor.
  3. Faça download de MagicTouch.js, uma biblioteca javascript para a simulação de eventos de toque compatíveis com a especificação baseados em retorno de chamada npTuioClient.
  4. Inclua o script magictouch.js e o plug-in npTuioClient no aplicativo da seguinte forma:
<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>

Testei essa abordagem apenas com o Google Chrome 10, mas ela deve funcionar em outros navegadores modernos com apenas alguns ajustes.

Se seu computador não tiver entrada multi-touch, você pode simular eventos de toque utilizando outros rastreadores TUIO, como o reacTIVision (link em inglês). Para obter mais informações, consulte a página do projeto TUIO (link em inglês).

Seus gestos devem ser idênticos aos gestos multi-touch no nível de sistema operacional. No OS X, você pode configurar eventos para todo o sistema acessando o painel de preferências do touchpad nas Preferências de sistema.

A compatibilidade de recursos multi-touch com diferentes navegadores é cada vez maior, e estou ansiosa por ver novos aplicativos da web que tirem total proveito da complexidade dessa API.

Comments

0