Compiler avec Chrome

Intégrer des briques LEGO® au Web multi-appareils

Build with Chrome, un test amusant pour les utilisateurs de Chrome sur ordinateur, lancé à l'origine en Australie, a été relancé en 2014 avec une disponibilité mondiale, des liens avec LE FILM LEGO® et la prise en charge des appareils mobiles. Dans cet article, nous allons partager certains enseignements tirés du projet, en particulier concernant le passage d'une expérience réservée au bureau à une solution multiécran compatible avec la saisie au clavier et au toucher.

L'histoire de Build avec Chrome

La première version de Build with Chrome a été lancée en Australie en 2012. Nous voulions montrer la puissance du Web d'une manière totalement inédite et présenter Chrome à une toute nouvelle audience.

Le site se composait de deux grandes parties : le mode "Créer", qui permet aux utilisateurs de créer des constructions à l'aide de briques LEGO, et le mode "Explorer", qui permet de parcourir les créations sur une version LEGO de Google Maps.

La 3D interactive était essentielle pour offrir aux utilisateurs la meilleure expérience de construction LEGO possible. En 2012, WebGL n'était disponible publiquement que dans les navigateurs pour ordinateur. Build était donc conçu pour une expérience sur ordinateur uniquement. Explore utilisait Google Maps pour afficher les créations, mais lorsque vous zoomiez suffisamment, la carte passait à une implémentation WebGL qui affichait les créations en 3D, tout en utilisant Google Maps comme texture de base. Nous voulions créer un environnement dans lequel les passionnés de LEGO de tous âges pourraient exprimer facilement et intuitivement leur créativité et explorer les créations des autres.

En 2013, nous avons décidé d'étendre Build with Chrome aux nouvelles technologies Web. Parmi ces technologies, figurait WebGL dans Chrome pour Android, qui permettrait naturellement à Build with Chrome de devenir une expérience mobile. Pour commencer, nous avons d'abord développé des prototypes tactiles, puis nous avons interrogé le matériel de l'outil de création afin de comprendre le comportement des gestes et la réactivité tactile que nous pourrions rencontrer dans un navigateur par rapport à une application mobile.

Un front-end responsif

Nous devions prendre en charge les appareils avec saisie tactile et par souris. Toutefois, l'utilisation de la même interface utilisateur sur les petits écrans tactiles s'est avérée être une solution non optimale en raison des contraintes d'espace.

Dans Build, l'interactivité est omniprésente: vous pouvez faire un zoom avant et arrière, changer la couleur des briques et, bien sûr, sélectionner, faire pivoter et placer des briques. Il s'agit d'un outil sur lequel les utilisateurs passent souvent beaucoup de temps. Il est donc important qu'ils aient un accès rapide à tout ce qu'ils utilisent fréquemment et qu'ils se sentent à l'aise pour interagir avec lui.

Lorsque vous concevez une application tactile hautement interactive, vous constaterez rapidement que l'écran semble petit et que les doigts de l'utilisateur ont tendance à recouvrir une grande partie de l'écran lorsqu'ils interagissent. Cela nous est apparu évident lorsque nous avons travaillé avec le générateur. Lors de la conception, vous devez vraiment tenir compte de la taille physique de l'écran plutôt que des pixels des graphiques. Il est important de réduire le nombre de boutons et de commandes pour consacrer autant d'espace que possible à l'écran au contenu lui-même.

Notre objectif était de rendre Build naturel sur les appareils tactiles, non seulement en ajoutant une saisie tactile à l'implémentation d'origine pour ordinateur, mais aussi en donnant l'impression qu'il était vraiment conçu pour le tactile. Nous avons finalement créé deux variantes de l'interface utilisateur, l'une pour les ordinateurs de bureau et les tablettes à grand écran, et l'autre pour les appareils mobiles à petit écran. Dans la mesure du possible, il est préférable d'utiliser une seule implémentation et d'assurer une transition fluide entre les modes. Dans notre cas, nous avons déterminé qu'il existait une différence d'expérience si importante entre ces deux modes que nous avons décidé de nous appuyer sur un point d'arrêt spécifique. Les deux versions partagent de nombreuses fonctionnalités, et nous avons essayé de tout faire avec une seule implémentation de code. Toutefois, certains aspects de l'interface utilisateur fonctionnent différemment entre les deux.

Nous utilisons les données de l'user-agent pour détecter les appareils mobiles, puis nous vérifions la taille de la fenêtre d'affichage pour déterminer si l'UI mobile pour petit écran doit être utilisée. Il est un peu difficile de choisir un point d'arrêt pour ce qui doit être considéré comme un "grand écran", car il est difficile d'obtenir une valeur fiable de la taille physique de l'écran. Heureusement, dans notre cas, il n'a pas vraiment d'importance que nous affichons l'UI pour petit écran sur un appareil tactile à grand écran, car l'outil fonctionnera toujours correctement. Certains boutons peuvent cependant sembler un peu trop grands. Nous avons finalement défini le point d'arrêt sur 1 000 pixels. Si vous chargez le site à partir d'une fenêtre plus large que 1 000 pixels (en mode paysage), vous obtiendrez la version pour grand écran.

Parlons un peu des deux tailles d'écran et des deux expériences:

Grand écran, compatible avec la souris et l'écran tactile

La version pour grand écran est diffusée sur tous les ordinateurs de bureau compatibles avec la souris et sur les appareils tactiles à grand écran (tels que le Google Nexus 10). Cette version est proche de la solution d'origine pour ordinateur de bureau en termes de commandes de navigation disponibles, mais nous avons ajouté la compatibilité avec l'écran tactile et certains gestes. Nous ajustons l'UI en fonction de la taille de la fenêtre. Par conséquent, lorsqu'un utilisateur redimensionne la fenêtre, il peut supprimer ou redimensionner une partie de l'UI. Pour ce faire, nous utilisons des requêtes média CSS.

Exemple: Lorsque la hauteur disponible est inférieure à 730 pixels, le curseur de zoom en mode "Découvrir" est masqué:

@media only screen and (max-height: 730px) {
    .zoom-slider {
        display: none;
    }
}

Petit écran, compatibilité avec l'écran tactile uniquement

Cette version est diffusée sur les appareils mobiles et les petites tablettes (appareils cibles Nexus 4 et Nexus 7). Cette version nécessite la compatibilité avec le multipoint.

Sur les appareils à petit écran, nous devons accorder au contenu autant d'espace que possible. Nous avons donc apporté quelques modifications pour maximiser l'espace, principalement en masquant les éléments peu utilisés:

  • Le sélecteur de blocs de création se réduit à un sélecteur de couleur pendant la création.
  • Nous avons remplacé les commandes de zoom et d'orientation par des gestes à plusieurs doigts.
  • La fonctionnalité plein écran de Chrome est également utile pour gagner de l'espace à l'écran.
Créer sur un grand écran
Créez des applications sur grand écran. Le sélecteur de blocs est toujours visible, et quelques commandes se trouvent sur le côté droit.
Créer sur un petit écran
Créez votre application sur un petit écran. Le sélecteur de blocs est réduit et certains boutons ont été supprimés.

Performances et compatibilité de WebGL

Les appareils tactiles modernes disposent de GPU assez puissants, mais ils sont encore loin de leurs homologues pour ordinateur. Nous savions donc que nous aurions des difficultés en termes de performances, en particulier dans le mode Explorer 3D, où nous devons afficher de nombreuses créations en même temps.

Sur le plan de la créativité, nous voulions ajouter quelques nouveaux types de briques avec des formes complexes et même de la transparence, des fonctionnalités qui sont généralement très lourdes pour le GPU. Cependant, nous devions être rétrocompatibles et continuer à prendre en charge les créations de la première version. Nous ne pouvions donc pas définir de nouvelles restrictions, comme réduire considérablement le nombre total de briques dans les créations.

Dans la première version de Build, nous avions limité le nombre maximal de briques pouvant être utilisées dans une création. Un "indicateur de briques" indiquait le nombre de briques restantes. Dans la nouvelle implémentation, certaines des nouvelles briques ont un impact plus important sur le compteur de briques que les briques standards, ce qui réduit légèrement le nombre maximal total de briques. C'était un moyen d'inclure de nouvelles briques tout en conservant des performances correctes.

Dans le mode Explorer 3D, de nombreuses opérations se déroulent simultanément : chargement des textures de la plaque de base, chargement des créations, animation et rendu des créations, etc. Cela nécessite beaucoup de ressources de la part du GPU et du processeur. Nous avons donc effectué de nombreux profilages de frame dans les outils de développement Chrome afin d'optimiser ces éléments autant que possible. Sur les appareils mobiles, nous avons décidé de faire un zoom un peu plus rapproché sur les créations afin de ne pas avoir à en afficher autant en même temps.

Certains appareils nous ont obligés à revoir et à simplifier certains des nuanceurs WebGL, mais nous avons toujours trouvé un moyen de résoudre le problème et de passer à autre chose.

Prise en charge des appareils non WebGL

Nous voulions que le site soit quelque peu utilisable même si l'appareil du visiteur n'est pas compatible avec WebGL. Il existe parfois des moyens de représenter la 3D de manière simplifiée à l'aide d'une solution de canevas ou de fonctionnalités CSS3D. Malheureusement, nous n'avons pas trouvé de solution suffisamment efficace pour répliquer les fonctionnalités de création et d'exploration 3D sans utiliser WebGL.

Pour plus de cohérence, le style visuel des créations doit être le même sur toutes les plates-formes. Nous aurions pu opter pour une solution 2,5D, mais cela aurait modifié l'apparence des créations. Nous avons également dû réfléchir à la façon de nous assurer que les créations créées avec la première version de Build with Chrome avaient le même aspect et fonctionnaient aussi bien dans la nouvelle version du site que dans la première.

Le mode Explorer 2D est toujours accessible aux appareils non WebGL, même si vous ne pouvez pas créer de nouvelles créations ni explorer en 3D. Les utilisateurs peuvent ainsi se faire une idée de la profondeur du projet et de ce qu'ils pourraient créer avec cet outil s'ils disposaient d'un appareil compatible avec WebGL. Le site peut ne pas être aussi utile pour les utilisateurs qui ne disposent pas de WebGL, mais il doit au moins servir de teaser et les inciter à l'essayer.

Il est parfois impossible de conserver des versions de remplacement pour les solutions WebGL. Plusieurs raisons peuvent expliquer ce choix : performances, style visuel, coûts de développement et de maintenance, etc. Toutefois, si vous décidez de ne pas implémenter de solution de remplacement, vous devez au moins prendre en charge les visiteurs qui ne sont pas compatibles avec WebGL, leur expliquer pourquoi ils ne peuvent pas accéder entièrement au site et leur indiquer comment résoudre le problème en utilisant un navigateur compatible avec WebGL.

Gestion des actifs

En 2013, Google a lancé une nouvelle version de Google Maps avec les modifications d'interface utilisateur les plus importantes depuis son lancement. Nous avons donc décidé de repenser Build with Chrome pour qu'il s'adapte à la nouvelle interface utilisateur de Google Maps. Pour ce faire, nous avons pris en compte d'autres facteurs. La nouvelle conception est relativement plate, avec des couleurs unies et des formes simples. Cela nous a permis d'utiliser du CSS pur sur de nombreux éléments d'interface utilisateur, réduisant ainsi l'utilisation d'images.

Dans Explorer, nous devons charger de nombreuses images : miniatures des créations, textures de carte pour les bases et enfin les créations 3D. Nous prenons des mesures particulières pour nous assurer qu'il n'y a pas de fuite de mémoire lorsque nous chargeons constamment de nouvelles images.

Les créations 3D sont stockées dans un format de fichier personnalisé empaqueté sous la forme d'une image PNG. En stockant les données des créations 3D sous forme d'image, nous avons pu transmettre les données directement aux nuanceurs qui génèrent les créations.

Pour toutes les images générées par les utilisateurs, la conception nous a permis d'utiliser les mêmes tailles d'image sur toutes les plates-formes, réduisant ainsi l'utilisation du stockage et de la bande passante.

Gérer l'orientation de l'écran

Il est facile d'oublier à quel point le format de l'écran change lorsque vous passez du mode portrait au mode paysage, ou inversement. Vous devez en tenir compte dès le départ lors de l'adaptation pour les appareils mobiles.

Sur un site Web traditionnel avec défilement activé, vous pouvez appliquer des règles CSS pour obtenir un site responsif qui réorganise le contenu et les menus. Tant que vous pouvez utiliser la fonctionnalité de défilement, cela est assez facile à gérer.

Nous avons également utilisé cette méthode avec Build, mais nous avons été un peu limités dans la façon dont nous pouvions résoudre la mise en page, car nous devions rendre le contenu visible en permanence et avoir un accès rapide à un certain nombre de commandes et de boutons. Pour les sites de contenu purs, comme les sites d'actualités, une mise en page fluide est tout à fait logique, mais pour une application de jeu comme la nôtre, c'était un défi. Trouver une mise en page qui fonctionne à la fois en mode paysage et portrait, tout en offrant une bonne vue d'ensemble du contenu et une interaction confortable, s'est avéré difficile. Nous avons finalement décidé de conserver la création en mode paysage uniquement et de demander à l'utilisateur de faire pivoter son appareil.

Explorer a été beaucoup plus facile à résoudre dans les deux orientations. Il nous a suffi d'ajuster le niveau de zoom de la 3D en fonction de l'orientation pour obtenir une expérience cohérente.

La majeure partie de la mise en page du contenu est contrôlée par CSS, mais certains éléments liés à l'orientation devaient être implémentés en JavaScript. Nous avons constaté qu'il n'existait pas de bonne solution multi-appareil pour utiliser window.orientation afin d'identifier l'orientation. Nous avons donc fini par comparer window.innerWidth et window.innerHeight pour identifier l'orientation de l'appareil.

if( window.innerWidth > window.innerHeight ){
  //landscape
} else {
  //portrait
}

Ajouter la compatibilité avec le mode tactile

Il est relativement simple d'ajouter la prise en charge de la saisie tactile au contenu Web. L'interactivité de base, comme l'événement de clic, fonctionne de la même manière sur les ordinateurs de bureau et les appareils tactiles. Toutefois, pour les interactions plus avancées, vous devez également gérer les événements tactiles : "touchstart", "touchmove" et "touchend". Cet article explique comment utiliser ces événements. Internet Explorer n'est pas compatible avec les événements tactiles, mais utilise plutôt les événements de pointeur (pointerdown, pointermove, pointerup). Les événements de pointeur ont été envoyés au W3C pour être normalisés, mais pour le moment, ils ne sont implémentés que dans Internet Explorer.

Dans le mode Explorer 3D, nous voulions la même navigation que dans l'implémentation standard de Google Maps : un doigt pour faire un panoramique sur la carte et pincer avec deux doigts pour faire un zoom. Étant donné que les créations sont en 3D, nous avons également ajouté le geste de rotation à deux doigts. Cela nécessite généralement l'utilisation d'événements tactiles.

Il est recommandé d'éviter les calculs lourds, tels que la mise à jour ou le rendu de la 3D dans les gestionnaires d'événements. Stockez plutôt l'entrée tactile dans une variable et réagissez à l'entrée dans la boucle de rendu requestAnimationFrame. Cela permet également d'implémenter une souris en même temps. Il vous suffit de stocker les valeurs de souris correspondantes dans les mêmes variables.

Commencez par initialiser un objet pour stocker l'entrée, puis ajoutez l'écouteur d'événements touchstart. Dans chaque gestionnaire d'événements, nous appelons event.preventDefault(). Cela permet d'empêcher le navigateur de continuer à traiter l'événement tactile, ce qui pourrait entraîner un comportement inattendu, tel que le défilement ou la mise à l'échelle de l'intégralité de la page.

var input = {dragStartX:0, dragStartY:0, dragX:0, dragY:0, dragDX:0, dragDY:0, dragging:false};
plateContainer.addEventListener('touchstart', onTouchStart);

function onTouchStart(event) {
  event.preventDefault();
  if( event.touches.length === 1){
    handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
    //start listening to all needed touchevents to implement the dragging
    document.addEventListener('touchmove', onTouchMove);
    document.addEventListener('touchend', onTouchEnd);
    document.addEventListener('touchcancel', onTouchEnd);
  }
}

function onTouchMove(event) {
  event.preventDefault();
  if( event.touches.length === 1){
    handleDragging(event.touches[0].clientX, event.touches[0].clientY);
  }
}

function onTouchEnd(event) {
  event.preventDefault();
  if( event.touches.length === 0){
    handleDragStop();
    //remove all eventlisteners but touchstart to minimize number of eventlisteners
    document.removeEventListener('touchmove', onTouchMove);
    document.removeEventListener('touchend', onTouchEnd);
    //also listen to touchcancel event to avoid unexpected behavior when switching tabs and some other situations
    document.removeEventListener('touchcancel', onTouchEnd);
  }
}

Nous ne stockons pas l'entrée dans les gestionnaires d'événements, mais dans des gestionnaires distincts: handleDragStart, handleDragging et handleDragStop. En effet, nous voulons pouvoir les appeler également à partir des gestionnaires d'événements de la souris. Gardez à l'esprit que, bien que cela soit peu probable, l'utilisateur peut utiliser l'écran tactile et la souris en même temps. Plutôt que de gérer directement cette demande, nous nous assurons simplement que rien ne se passe.

function handleDragStart(x ,y ){
  input.dragging = true;
  input.dragStartX = input.dragX = x;
  input.dragStartY = input.dragY = y;
}

function handleDragging(x ,y ){
  if(input.dragging) {
    input.dragDX = x - input.dragX;
    input.dragDY = y - input.dragY;
    input.dragX = x;
    input.dragY = y;
  }
}

function handleDragStop(){
  if(input.dragging) {
    input.dragging = false;
    input.dragDX = 0;
    input.dragDY = 0;
  }
}

Lorsque vous effectuez des animations basées sur le mouvement tactile, il est souvent utile de stocker également le mouvement delta depuis le dernier événement. Par exemple, nous l'avons utilisé comme paramètre pour la vitesse de la caméra lorsque vous vous déplacez sur toutes les plaques de base dans Explorer, car vous ne faites pas glisser les plaques de base, mais vous déplacez la caméra.

function onAnimationFrame() {
  requestAnimationFrame( onAnimationFrame );

  //execute animation based on input.dragDX, input.dragDY, input.dragX or input.dragY
 /*
  /
  */

  //because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
  input.dragDX=0;
  input.dragDY=0;
}

Exemple intégré:faire glisser un objet à l'aide d'événements tactiles Implémentation similaire à celle utilisée pour faire glisser la carte Explore 3D dans Build with Chrome: http://cdpn.io/qDxvo

Gestes multipoint

Plusieurs frameworks ou bibliothèques, tels que Hammer ou QuoJS, peuvent simplifier la gestion des gestes multipoint. Toutefois, si vous souhaitez combiner plusieurs gestes et avoir un contrôle total, il est parfois préférable de partir de zéro.

Pour gérer les gestes de pincement et de rotation, nous stockons la distance et l'angle entre deux doigts lorsque le deuxième doigt est placé à l'écran:

//variables representing the actual scale/rotation of the object we are affecting
var currentScale = 1;
var currentRotation = 0;

function onTouchStart(event) {
  event.preventDefault();
  if( event.touches.length === 1){
    handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
  }else if( event.touches.length === 2 ){
    handleGestureStart(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY );
  }
}

function handleGestureStart(x1, y1, x2, y2){
  input.isGesture = true;
  //calculate distance and angle between fingers
  var dx = x2 - x1;
  var dy = y2 - y1;
  input.touchStartDistance=Math.sqrt(dx*dx+dy*dy);
  input.touchStartAngle=Math.atan2(dy,dx);
  //we also store the current scale and rotation of the actual object we are affecting. This is needed to support incremental rotation/scaling. We can't assume that an object is always the same scale when gesture starts.
  input.startScale=currentScale;
  input.startAngle=currentRotation;
}

Dans l'événement "touchmove", nous mesurons ensuite en continu la distance et l'angle entre ces deux doigts. La différence entre la distance de départ et la distance actuelle est ensuite utilisée pour définir l'échelle, et la différence entre l'angle de départ et l'angle actuel est utilisée pour définir l'angle.

function onTouchMove(event) {
  event.preventDefault();
  if( event.touches.length  === 1){
    handleDragging(event.touches[0].clientX, event.touches[0].clientY);
  }else if( event.touches.length === 2 ){
    handleGesture(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY );
  }
}

function handleGesture(x1, y1, x2, y2){
  if(input.isGesture){
    //calculate distance and angle between fingers
    var dx = x2 - x1;
    var dy = y2 - y1;
    var touchDistance = Math.sqrt(dx*dx+dy*dy);
    var touchAngle = Math.atan2(dy,dx);
    //calculate the difference between current touch values and the start values
    var scalePixelChange = touchDistance - input.touchStartDistance;
    var angleChange = touchAngle - input.touchStartAngle;
    //calculate how much this should affect the actual object
    currentScale = input.startScale + scalePixelChange*0.01;
    currentRotation = input.startAngle+(angleChange*180/Math.PI);
    //upper and lower limit of scaling
    if(currentScale<0.5) currentScale = 0.5;
    if(currentScale>3) currentScale = 3;
  }
}

Vous pouvez utiliser la modification de la distance entre chaque événement touchmove de la même manière que pour le glissement, mais cette approche est souvent plus utile lorsque vous souhaitez un mouvement continu.

function onAnimationFrame() {
  requestAnimationFrame( onAnimationFrame );
  //execute transform based on currentScale and currentRotation
  /*
  /
  */

  //because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
  input.dragDX=0;
  input.dragDY=0;
}

Si vous le souhaitez, vous pouvez également activer le glissement de l'objet lorsque vous effectuez les gestes de pincement et de rotation. Dans ce cas, vous utiliserez le point central entre les deux doigts comme entrée pour le gestionnaire de glissement.

Exemple intégré:faire pivoter et mettre à l'échelle un objet en 2D Comme la carte de l'onglet "Explorer" : http://cdpn.io/izloq

Compatibilité avec la souris et le tactile sur le même matériel

De nos jours, plusieurs ordinateurs portables, comme le Chromebook Pixel, sont compatibles avec la saisie à la souris et à l'écran tactile. Cela peut entraîner des comportements inattendus si vous n'y faites pas attention.

Il est important de ne pas simplement détecter la compatibilité avec l'écran tactile, puis d'ignorer la saisie de la souris, mais de prendre en charge les deux à la fois.

Si vous n'utilisez pas event.preventDefault() dans vos gestionnaires d'événements tactiles, des événements de souris émulés seront également déclenchés afin que la plupart des sites non optimisés pour les écrans tactiles continuent de fonctionner. Par exemple, pour un seul appui sur l'écran, ces événements peuvent se déclencher dans une séquence rapide et dans l'ordre suivant:

  1. touchstart
  2. touchmove
  3. touchend
  4. survol avec la souris
  5. mousemove
  6. mousedown
  7. mouseup
  8. clic

Si vos interactions sont un peu plus complexes, ces événements de souris peuvent entraîner un comportement inattendu et perturber votre implémentation. Il est souvent préférable d'utiliser event.preventDefault() dans les gestionnaires d'événements tactiles et de gérer la saisie de la souris dans des gestionnaires d'événements distincts. Sachez que l'utilisation de event.preventDefault() dans les gestionnaires d'événements tactiles empêche également certains comportements par défaut, tels que le défilement et l'événement de clic.

"Dans Build with Chrome, nous ne voulions pas que le zoom se produise lorsqu'un utilisateur effectue un double-appui sur le site, même si c'est la norme dans la plupart des navigateurs. Nous utilisons donc la balise Meta de la fenêtre d'affichage pour indiquer au navigateur de ne pas faire un zoom lorsque l'utilisateur effectue un double appui. Cela supprime également le délai de clic de 300 ms, ce qui améliore la réactivité du site. (Le délai de clic permet de faire la distinction entre un appui simple et un appui double lorsque le zoom par double appui est activé.)

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

N'oubliez pas que lorsque vous utilisez cette fonctionnalité, il vous incombe de rendre le site lisible sur toutes les tailles d'écran, car l'utilisateur ne pourra pas faire un zoom avant.

Saisie par souris, tactile et clavier

Dans le mode Explorer 3D, nous voulions proposer trois façons de naviguer sur la carte: la souris (glisser), l'écran tactile (glisser, pincer pour zoomer et faire pivoter) et le clavier (parcourir avec les touches fléchées). Toutes ces méthodes de navigation fonctionnent légèrement différemment, mais nous avons utilisé la même approche pour toutes : définir des variables dans les gestionnaires d'événements et agir en conséquence dans la boucle requestAnimationFrame. La boucle requestAnimationFrame n'a pas besoin de savoir quelle méthode est utilisée pour la navigation.

Par exemple, nous pouvons définir le mouvement de la carte (dragDX et dragDY) avec les trois méthodes d'entrée. Voici l'implémentation du clavier:

document.addEventListener('keydown', onKeyDown );
document.addEventListener('keyup', onKeyUp );

function onKeyDown( event ) {
  input.keyCodes[ "k" + event.keyCode ] = true;
  input.shiftKey = event.shiftKey;
}

function onKeyUp( event ) {
  input.keyCodes[ "k" + event.keyCode ] = false;
  input.shiftKey = event.shiftKey;
}

//this needs to be called every frame before animation is executed
function handleKeyInput(){
  if(input.keyCodes.k37){
    input.dragDX = -5; //37 arrow left
  } else if(input.keyCodes.k39){
    input.dragDX = 5; //39 arrow right
  }
  if(input.keyCodes.k38){
    input.dragDY = -5; //38 arrow up
  } else if(input.keyCodes.k40){
    input.dragDY = 5; //40 arrow down
  }
}

function onAnimationFrame() {
  requestAnimationFrame( onAnimationFrame );
  //because keydown events are not fired every frame we need to process the keyboard state first
  handleKeyInput();
  //implement animations based on what is stored in input
   /*
  /
  */

  //because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
  input.dragDX = 0;
  input.dragDY = 0;
}

Exemple intégré:navigation à l'aide de la souris, de l'écran tactile et du clavier: http://cdpn.io/catlf

Résumé

L'adaptation de Build with Chrome pour prendre en charge les appareils tactiles de nombreuses tailles d'écran a été une expérience d'apprentissage. L'équipe n'avait pas beaucoup d'expérience avec ce niveau d'interactivité sur les appareils tactiles, et nous avons beaucoup appris au cours du processus.

Le plus grand défi s'est avéré être de résoudre les problèmes d'expérience et de conception utilisateur. Les défis techniques consistaient à gérer de nombreuses tailles d'écran, des événements tactiles et des problèmes de performances.

Bien que les nuanceurs WebGL sur les appareils tactiles aient posé quelques problèmes, le résultat a été presque meilleur que prévu. Les appareils deviennent de plus en plus puissants, et les implémentations WebGL s'améliorent rapidement. Nous pensons que nous allons utiliser WebGL sur les appareils beaucoup plus fréquemment dans un avenir proche.

Si vous ne l'avez pas déjà fait, créez quelque chose d'incroyable !