Gestes pincer et zoomer
Ajouter la gestion des gestes à une application peut améliorer de manière significative l'expérience utilisateur. Il existe de nombreux types de gestes, du simple geste swipe (balayage de l'écran) aux gestes plus complexes avec plusieurs doigts comme le twist (rotation), où les points de contact (dits pointeurs) bougent dans des directions différentes.
Cet exemple montre comment détecter les gestes de pinch/zoom (pincer/zoomer), en utilisant les événements de pointeur
pour détecter si l'utilisateur bouge deux pointeurs plus proches ou plus loin l'un de l'autre.
Note : Une version en direct de cette application est disponible sur Github. Le code source est également disponible sur Github; les pull requests et bug reports sont les bienvenus.
Exemple
Dans cet exemple, on utilise les événement de pointeur
pour détecter simultanément plusieurs appareils de pointage quel qu'en soit le type, comme les doigts, la souris, et le stylet. Le geste de pincer (zoomer), qui consiste à déplacer deux pointeurs plus près l'un vers l'autre, change la couleur d'arrière-plan de l'élément cible en lightblue
. Le geste d'étirer (dézoomer), qui consiste à déplacer deux pointeur plus loin l'un de l'autre, change la couleur d'arrière-plan de l'élément cible en pink
.
Définir la cible du toucher
L'application utilise un <div>
pour définir la zone cible du pointeur.
<style>
div {
margin: 0em;
padding: 2em;
}
#target {
background: white;
border: 1px solid black;
}
</style>
État global
Prendre en charge un mouvement à deux pointeurs nécessite de conserver un état des événements du pointeur durant les différentes phases de l'événement. Cette application utilise deux variables globales pour mettre en cache l'état de l'événement.
// Variables globales pour mettre en cache l'état de l'événement
var evCache = new Array();
var prevDiff = -1;
Enregistrer les gestionnaires d'événement
Les gestionnaires d'événement sont enregistrés pour les événements de pointeur suivants: pointerdown
, pointermove
et pointerup
. Le gestionnaire pour pointerup
est utilisé pour les événements pointercancel
, pointerout
et pointerleave
puisque ces quatre événements ont la même sémantique dans cette application.
function init() {
// Ajoute les gestionnaires d'événements pour la cible du pointeur
var el = document.getElementById("target");
el.onpointerdown = pointerdown_handler;
el.onpointermove = pointermove_handler;
// Même chose pour les événements pointer{up,cancel,out,leave} puisque
// la sémantique pour ces événements - dans cette appli - est identique.
el.onpointerup = pointerup_handler;
el.onpointercancel = pointerup_handler;
el.onpointerout = pointerup_handler;
el.onpointerleave = pointerup_handler;
}
Pointer down
L'événement pointerdown
est déclenché quand un pointeur (souris, stylo/stylet ou point de contact sur un écran tactile) entre en contact avec la surface de contact. Dans cette application, l'état de l'événement doit être mis en cache dans le cas où il fait partie d'un geste à deux pointeurs pour pincer/zoomer.
function pointerdown_handler(ev) {
// L'événement pointerdown signale le début d'une interraction de toucher.
// L'événement est mis en cache pour prendre en charge les gestes à 2 doigts
evCache.push(ev);
log("pointerDown", ev);
}
Pointer move
Le gestionnaire d'événement pointermove
détecte si un utilisateur est en train d'effectuer le geste de pincer/zoomer. Si deux pointeurs sont utilisés, et que la distance entre les pointeurs augmente (ce qui signifie qu'on étire ou dézoome), la couleur d'arrière-plan est changée en pink
, et si la distance entre les pointeurs diminue (ce qui signifie qu'on pince ou dézoome), la couleur d'arrière-plan est changée en lightblue
. Dans une application plus sophistiquée, le pincement ou l'étirement pourrait être utilisé pour appliquer une sémantique spécifique à l'application.
Quand cet événement est traité, la bordure de la cible est définie à dashed
pour fournir une indication visuelle claire que l'élément a reçu un événement de déplacement.
function pointermove_handler(ev) {
// Cette fonction implémente la détection du mouvement horizontal pincer/zoomer.
//
// Si la distance entre les deux pointeurs augmente (zoomer),
// l'arrière-plan de l'élément cible est changé en "pink" et si la
// distance diminue (dezoomer), la couleur est changée en "lightblue".
//
// Cette fonctionne définie la bordure de l'élément cible à "dashed" pour indiquer
// visuellement que la cible du pointeur a reçu un événement de déplacement.
log("pointerMove", ev);
ev.target.style.border = "dashed";
// Trouve le pointeur en cours dans le cache et le met à jour avec cet événement
for (var i = 0; i < evCache.length; i++) {
if (ev.pointerId == evCache[i].pointerId) {
evCache[i] = ev;
break;
}
}
// Si deux pointeurs sont utilisés, vérifie le geste de pincement
if (evCache.length == 2) {
// Calcule la distance entre les deux pointeurs
var curDiff = Math.abs(evCache[0].clientX - evCache[1].clientX);
if (prevDiff > 0) {
if (curDiff > prevDiff) {
// La distance entre les deux pointeurs a augmenté
log("Pinch moving OUT -> Zoom in", ev);
ev.target.style.background = "pink";
}
if (curDiff < prevDiff) {
// La distance entre les deux pointeurs a diminué
log("Pinch moving IN -> Zoom out", ev);
ev.target.style.background = "lightblue";
}
}
// Met en cache la distance pour les événements suivants
prevDiff = curDiff;
}
}
Pointer up
L'événement pointerup
est déclenché quand le pointeur est levé de la surface de contact. Quand cela arrive, l'événement est retiré du cache et la couleur d'arrière-plan et bordure de la cible sont rétablies à leur valeur d'origine.
Dans cette application, ce gestionnaire est également utilisé pour les événements pointercancel
, pointerleave
et pointerout
.
function pointerup_handler(ev) {
log(ev.type, ev);
// Retire ce pointeur du cache et rétablit l'arrière-plan et
// et bordure de la cible
remove_event(ev);
ev.target.style.background = "white";
ev.target.style.border = "1px solid black";
// Si le nombre de pointeurs restant est inférieur à deux, remet à zéro la différence
if (evCache.length < 2) prevDiff = -1;
}
Application UI
Cette application utilise un élément <div>
comme zone de toucher et fournit des boutons pour activer et nettoyer les logs.
Note :
Pour empêcher que le comportement par défaut du navigateur au toucher surcharge le gestionnaire de l'application, la propriété touch-action
est appliquée à l'élément <body>
.
<body onload="init();" style="touch-action:none">
<div id="target">
Touchez l'écran avec deux pointeurs, puis pincez ou étirez.<br />
La couleur d'arrière-plan changera en rose au pincement (Zoomer) ou en bleu
clair à l'étirement (Dézoomer).
</div>
<!-- UI pour log/debug -->
<button id="log" onclick="enableLog(event);">
Démarrer/Stopper les logs
</button>
<button id="clearlog" onclick="clearLog(event);">Nettoyer les logs</button>
<p></p>
<output></output>
</body>
Fonctions diverses
Ces fonctions prennent en charge l'application mais ne sont pas directement impliquées dans le flux des événements.
Gestion du Cache
Cette fonction aide à gérer le cache global des événements, evCache
.
function remove_event(ev) {
// Supprime l'événement du cache
for (var i = 0; i < evCache.length; i++) {
if (evCache[i].pointerId == ev.pointerId) {
evCache.splice(i, 1);
break;
}
}
}
Log des événements
Ces fonctions sont utilisées pour afficher l'activité du pointeur dans la fenêtre de l'application (pour aider à debugger et à apprendre le flux des événements).
// Flag log
var logEvents = false;
// Fonctions Log/debug
function enableLog(ev) {
logEvents = logEvents ? false : true;
}
function log(prefix, ev) {
if (!logEvents) return;
var o = document.getElementsByTagName('output')[0];
var s = prefix + ": pointerID = " + ev.pointerId +
" ; pointerType = " + ev.pointerType +
" ; isPrimary = " + ev.isPrimary;
o.innerHTML += s + "
";
}
function clearLog(event) {
var o = document.getElementsByTagName('output')[0];
o.innerHTML = "";
}
Voir aussi
- Pointer Events now in Firefox Nightly; Mozilla Hacks; by Matt Brubeck and Jason Weathersby; 2015-Aug-04
- jQuery Pointer Events Polyfill
- Gestures; Google Design Patterns