Développement Web pour écran tactile multipoint

HTML5 Rocks

Introduction

Les terminaux mobiles comme les smartphones et les tablettes ont, pour la plupart, un écran tactile capacitif qui capture les interactions faites avec les doigts de l'utilisateur. Alors que le web mobile évolue pour permettre des applications toujours plus sophistiquées, les développeurs web ont besoin de prendre en charge ces évènements. Par exemple, un jeu peut exiger de presser plusieurs boutons simultanément, ce qui, dans le contexte d'un écran tactile, implique d'utiliser le multi-touch.

Apple a dévoilé son API tactile dans iOS 2.0. Android a suivi ce standard, et a rattrapé son retard. Le groupe de travail du W3C s'est mis à travailler récemment sur cette spécification des évènements tactiles.

Dans cet article, nous plongerons dans l'API tactile fournie par iOS et Android, en explorant quel genre d'applications vous pouvez développer, en détaillant les bonnes pratiques, et en expliquant quelques techniques utiles qui facilitent le développement d'applications tactiles.

Évènements tactiles

Trois évènements tactiles sont définis dans la spécification et largement implémentés sur les terminaux mobiles :

  • touchstart : le doigt est placé sur un élément du DOM.
  • touchmove : le doigt est déplacé sur un élément du DOM.
  • touchend : le doigt est retiré d'un élément du DOM.

Chaque évènement tactile inclue trois listes de touches :

  • touches: une liste de tous les doigts actuellement sur l'écran.
  • targetTouches : une liste des doigts sur l'élement du DOM actuel.
  • changedTouches : une liste des doigts impliqués dans l'évènement courant. Par exemple, sur un évènement touchend, il s'agira du doigt qui a été retiré.

Ces listes sont constituées d'objets qui contiennent des informations tactiles :

  • identifier : un numéro qui identifie de façon unique le doigt courant dans la session tactile.
  • target : l'élément DOM qui est ciblé par l'action.
  • client/page/screen coordinates : l'emplacement de l'action sur l'écran.
  • radius coordinates and rotationAngle : décrit l'ellipse correspondant à la forme approximative du doigt.

Applications tactiles

Les évènements touchstart, touchmove, et touchend fournissent un ensemble de fonctionnalités suffisamment riche pour supporter n'importe quel type d'interactions tactiles – y compris toutes les manipulations multi-touch, comme le pinch-to-zoom, les rotations, etc.

Cet exemple de code permet de déplacer un élément du DOM en utilisant le doigt :

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

L'exemple ci-dessous affiche tous les doigts actuellement en contact avec l'écran. Cela peut être utile pour mesurer la réactivité du terminal mobile.

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

Démos

Bon nombre de démos multi-touch sont déjà disponibles, comme cet outil de dessin développé entre autres par Paul Irish :

et Browser Ninja, un clone de Fruit Ninja qui utilise les transformations et transitions CSS3, ainsi que canvas :

Bonnes pratiques

Empêcher le zoom

Les options par défaut ne fonctionnent pas très bien avec le multi-touch, puisque les mouvements sont souvent associés à des actions du navigateur, comme le scroll et le zoom.

Pour désactiver le zoom, définissez votre viewport pour qu'il ne soit pas mis à l'échelle par l'utilisateur, en utilisant la balise meta suivante :

<meta name="viewport" 
  content="width=device-width, initial-scale=1.0, user-scalable=no">
Jetez un œil à cet article HTML5 mobile pour plus d'informations sur les paramètres du viewport.

Empêcher le scroll

Certains terminaux mobiles ont des comportements par défaut pour touchmove, comme l'effet de scroll sur iOS, qui fait rebondir la page lorsque le scroll va au-delà du contenu. Cela porte à confusion dans beaucoup d'applications multi-touch, et peut être facilement désactivé :

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

Générer le rendu avec précaution

Si vous développez une application qui gère des manipulations multi-touch complexes, faites attention à la façon dont vous réagissez aux évènements, sachant que vous allez en gérer une multitude à la fois. Reprenons l'exemple dans la section précédente qui affiche tous les doigts sur l'écran. On pourrait l'afficher dès que le doigt entre en contact avec l'écran :

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

Mais cette solution devient d'autant plus lourde qu'il y a de doigts sur l'écran. A la place, on pourrait référencer tous les doigts, et les afficher dans une boucle pour obtenir des performances bien meilleures :

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

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

Remarque: setInterval n'est pas idéal pour les animations, parce qu'il ne prend pas en compte la boucle de rendu du navigateur lui-même. Les navigateurs modernes fournissent requestAnimationFrame, qui est une bien meilleure option, à la fois pour les performances et la consommation de batterie. Lorsqu'elle sera supportée par les navigateurs mobiles, elle deviendra la solution privilégiée pour les boucles de rendu.

Utiliser targetTouches et changedTouches

Souvenez-vous que event.touches est une liste de TOUS les doigts en contact avec l'écran, pas seulement sur l'élément DOM cible. Il peut être plus utile d'utiliser event.targetTouches ou event.changedTouches à la place.

Enfin, puisque vous développez sur mobile, vous devriez prendre en compte les bonnes pratiques générales en matière de mobile, qui sont détaillées dans l'article de Eric Bidelman, ainsi que dans ce document du W3C.

Terminaux supportés

Malheureusement, les implémentations des évènements tactiles varient en exhaustivité et en qualité. J'ai écrit un script de diagnostics qui affiche des informations de base sur l'implémentation de l'API tactile, y compris quels évènements sont supportés, et la précision du touchmove. J'ai effectué des tests sur Android 2.3.3 avec un Nexus One et un Nexus S, Android 3.0.1 avec une Xoom, et iOS 4.2 sur iPad et iPhone

En bref, tous les navigateurs testés supportent les évènements touchstart, touchend, et touchmove.

La spécification fournit trois évènements tactiles supplémentaires, mais aucun des navigateurs testés ne les supporte :

  • touchenter : un doigt en mouvement pénètre dans un élément du DOM.
  • touchleave : un doigt en mouvement sort d'un élément du DOM.
  • touchcancel : une touche est interrompue (dépend de l'implémentation).

Les navigateurs testés fournissent également les listes touches, targetTouches et changedTouches. En revanche, aucun navigateur testé ne supporte radiusX, radiusY ou rotationAngle, qui décrivent la forme du doigt en contact avec l'écran.

Pendant un touchmove, les évènements sont déclenchés quasiment 60 fois par seconde sur tous les terminaux testés.

Android 2.3.3 (Nexus)

Sur le navigateur d'Android Gingerbread (testé sur Nexus One et Nexus S), il n'y a pas de multi-touch. C'est un problème connu.

Android 3.0.1 (Xoom)

Le navigateur de la Xoom supporte le multi-touch de façon basique, mais uniquement sur un seul élément du DOM. Le navigateur ne répond pas correctement à deux touches simultanées sur différents éléments du DOM. En d'autres mots, le code suivant réagira à deux touches simultanées :

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

Mais le suivant 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)

Les terminaux sous iOS supportent pleinement le multi-touch, sont capables de suivre plusieurs doigts, et fournissent une expérience tactile très réactive dans le navigateur.

Outils de développement

En développement mobile, il est souvent plus facile de commencer à travailler sur un ordinateur de bureau et de s'occuper ensuite des fonctionnalités spécifiquement mobiles sur les terminaux que vous désirez supporter. Cependant, le multi-touch est une fonctionnalité difficile à tester sur PC, puisque la plupart des PCs n'ont pas d'interface tactile.

Effectuer les tests sur mobile risque de ralentir votre développement, puisque chaque modification que vous faites devra être envoyée sur un serveur et ensuite chargée sur le terminal. Une fois chargée, vous serez très limité pour débugger votre application, sachant que les tablettes et les smartphones n'intègrent pas d'outils de développement web.

Une solution à ce problème est de simuler les évènements tactiles sur votre machine de développement. Pour le single-touch, les évènements tactiles peuvent être simulés avec les évènements de la souris. Les évènements multi-touch peuvent être simulés si vous avez un périphérique d'entrée tactile, comme sur un Apple Macbook.

Évènements single-touch

Si vous désirez simuler des évènements single-touch sur votre PC, essayez Phantom Limb, qui simule les évènements tactiles sur les pages et vous donne une énorme main à utiliser.

Il existe aussi un plugin jQuery, Touchable, qui unifie les évènements de la souris et les évènements tactiles à travers les plateformes.

Évènements multi-touch

Pour permettre à vos applications multi-touch de fonctionner dans votre navigateur en utilisant un trackpad multi-touch (comme un Apple Macbook ou MagicPad), j'ai créé MagicTouch.js, qui capture les évènements tactiles de votre trackpad et les convertit en évènements tactiles standards.

  1. Téléchargez et installez le plugin npTuioClient NPAPI dans ~/Library/Internet Plug-Ins/.
  2. Téléchargez l'application TongSeng TUIO pour MagicPad et démarrez le serveur.
  3. Téléchargez MagicTouch.js, une librairie javascript qui simule des évènements tactiles compatibles avec la spécification, basés sur les informations renvoyées par npTuioClient.
  4. Incluez le script magictouch.js et le plugin npTuioClient dans votre application comme ceci :
<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>

J'ai testé cette solution uniquement sur Chrome 10, mais elle devrait fonctionner sur les autres navigateurs modernes sans trop de difficultés.

Si votre PC n'a pas de périphérique multi-touch, vous pouvez simuler les évènements tactiles en utilisant d'autres trackers TUIO, comme reacTIVision. Pour plus d'informations, voir la page du projet TUIO.

Notez que vos mouvements peuvent être identiques aux mouvements multi-touch utilisés par l'OS. Sur Max OS X, vous pouvez configurer les évènements système dans les préférences du Trackpad, situées dans les préférences Système.

Au fur et à mesure que les fonctionnalités multi-touch sont adoptées par les navigateurs mobiles, je suis très enthousiaste à l'idée de voir de nouvelles applications web tirant pleinement parti de cette riche API.

Comments

0