Découverte d'ODEM, Typescript et NodeJS

Bien le bonjour,

Derrière ce titre un peu large se cache en fait un article fourre tout dans lequel je vais pouvoir vous présenter les quelques travaux que j’ai effectué récemment.

Présentation

Commençons par planter le décor, tout d’abord ODEM kézako ? Comme une vidéo vaut mieux que de longues phrases.

Il s’agit donc d’une démonstration lancé par google il y a quelques jours permettant d’interagir sur un profil google+ grâce à son téléphone.Vous pouvez d’ailleurs vous même tester cette interface à l’adresse odem.chromeexperiments.com (pas besoin de compte pour essayer).

Ensuite qu’est ce que TypeScript ? Il s’agit d’un langage créé par Microsoft permettant d’écrire du code qui sera ensuite “compilé” en JavaScript. Rien de bien nouveau, il s’agit d’un concurrent de CoffeeScript mais qui, à mon humble avis semble plus lisible. De plus c’est opensource, simple à apprendre, donc pourquoi s’en priver ? La documentation du langage est disponible ici.

Enfin Node.JS… Ai-je vraiment besoin de le présenter ? Il s’agit d’une technologie permettant de faire tourner du javascript côté serveur de façon légère, le tout supportant tout un tas de modules, tel que Socket.IO. Comme ce n’est pas vraiment l’intérêt de cet article de vous présenter Node.JS, je vous laisse visiter le site officiel.

Quel rapport entre ces trois technologies me dirai vous ? Et bien j’ai voulu voir comment fonctionnait ODEM et si il était possible pour un noob du développement web tel que moi de reproduire ce type de système. Comme je voulais apprendre le langage TypeScript à ce moment là, je me suis dis que ça me ferai une bonne occasion. Forcément pour pouvoir interfacer le mobile tactile avec l’écran de présentation, Node.JS me semblait un très bon choix, et ce serai encore une fois une bonne occasion de faire quelques lignes de plus en TypeScript.

Prérequis

Alors tout d’abord, il faut avoir un téléphone mobile ou bien un interface tactile (logique non ?) avec un navigateur supportant quelques fonctionnalités HTML5 (chrome fera très bien l’affaire).

On partira ensuite du principe que votre installation de Typescript est opérationnelle. De même pour celle de Node.JS.

Principe

Donc commençons par définir le périmètre, notre projet sera bien sûr beaucoup plus simple que la démo de google. Nous allons donc reprendre la démo disponible ici qui nous montre comment faire pivoter une voiture sur un iphone grâce à javascript. Nous allons donc reprendre ce code puis le séparer en deux. Une d’elle ne permettra que l’affichage de la voiture qui tourne, et l’autre sera celle qui contrôle la rotation de la voiture. Le serveur Node.JS permettra quant à lui d’interfacer le deux parties.

Let’s GO

Partie 1: L’affichage

La première chose à faire c’est commencer par télécharger ce sprite, il s’agit des différentes positions de la voiture que nous allons faire tourner. Ensuite on va créer le squelette HTML de notre affichage :

<html>
 <head>
     <title>Opem Like</title>  
     <meta name="viewport" content="initial-scale=1.0; minimum-scale=1.0; maximum-scale=1.0;" />    
     <style type="text/css">
          body
         {                        
             margin:0;
             padding:0;    
             font-family:helvetica;
             font-weight:bold;
             color:#000;
             background-color:#ccc;             
         }
         #wrapper
         {
             width:320px;
             height:416px;
             position:relative;
             text-align:center;            
             overflow:hidden;                        
         }
         #imageHolder
         {
            width:240px;
            height:200px;
            background:url(sprite.png) 0 0 no-repeat;
            position:absolute;
            top:150px;
            left:37px;                         
         }

     </style>
 </head>

 <body>
  <div id="wrapper">
   <div id="imageHolder"></div>
  </div>
 </body>

 <script type="text/javascript" src="http://localhost:1666/socket.io/socket.io.js"></script>
 <script type="text/javascript" src="js/client.js"></script>
</html>

Rien de bien étonnant dans ce code, mis à part les deux scripts javascript chargés en bas de page. Nous allons commencer par étudier client.js.

Il s’agit du script qui va recevoir les ordres pour bouger la voiture. Voyons le TypeScript qui va faire celà:

class Car{

 /* Définition des attributs et de leurs types */
 _imageHolder: object;
 _distance: number;
 _counter: number;
 _noOfImages: number;

 /* Constructeur de la class Car */
 constructor(){
  this._distance = 0;
  this._counter = 0;
  this._noOfImages = 18; // Nombre d'image du sprites

  /* On recupère l'emplacement où la voiture sera affichée */
  this._imageHolder = document.getElementById("imageHolder");
 }


 /* Méthodes pour tourner la voiture à gauche ou à droite */
 moveForward(){
  this._counter++;
  if(this._counter == this._noOfImages){
   this._counter = 0;
  }
  if(this._counter == 3 || this._counter == 12){
   this._imageHolder.style.width = "238px";
  } else {
   this._imageHolder.style.width = "240px";
  }

  this._imageHolder.style.backgroundPosition = (-this._counter * 240) + "px 0px";
 }

 moveBackward(){
  this._counter--;
  if(this._counter == -1){
   this._counter = this._noOfImages - 1;
  }

  if( this._counter == 15){
   this._imageHolder.style.backgroundPosition = (-this._counter * 240 - 2) + "px 0px";
  }
  else if (this._counter == 13 || this._counter == 12) {
   this._imageHolder.style.width = "239px";
   this._imageHolder.style.backgroundPosition = (-this._counter * 240) + "px 0px";
  }
  else {
   this._imageHolder.style.backgroundPosition = (-this._counter * 240) + "px 0px";
  }
 }
}

/* Une fois le script chargé, on execute le code qui suit */
window.onload = () => {

 /* On crée un objet Car */
 var voiture = new Car()

 /* On crée un socket avec le serveur Node.JS */
 var socket = io.connect('http://localhost:1666');

 /* A la reception d'un ordre 'move' */
 socket.on('move', function(data){

  /* On tourne la voiture selon l'ordre donné */
  if(data.direction == 'gauche'){
   voiture.moveBackward();
  } else {
   voiture.moveForward();
  }
 });
}

Partie 2: L’interface tactile

Maintenant que notre affichage est codé, nous allons maintenant passer au contrôleur tactile, une simple page web de ce type suffira:

<html>
 <head>
  <title>Test</title>
 </head>

 <body>
  <div id="joujou"></div>

  <script type="text/javascript" src="js/mobile.js"></script>
  <script type="text/javascript" src="http://localhost:1666/socket.io/socket.io.js"></script>
 </body>
</html>

Encore une fois pas grand chose de surprenant, nous allons étudier le code TypeScript qui permet de générer mobile.js. L’inclusion de socket.io.js sera expliqué dans la dernière partie de cet article.

Le script mobile.js ne demande que quelques lignes, en effet il va traiter les mouvements effectué par l’utilisateur sur l’écran tactile, puis va les traiter pour savoir si l’utilisateur veut tourner le véhicule à gauche ou à droite.

class Movement {

 /* Définition des attributs de la classe */
 _element: HTMLElement;
 _socket: Socket;
 _isMouseDown: Boolean;

 _initX: number;
 _presentX: number;

 _distance: number;

  /* Constructeur de la classe
  *
  * Argument: HTMLElement
  * Cet argument permet de définir quelle zone de la page traitera les entrées utilisateurs
  *
  */
 constructor (element: HTMLElement){
  this._socket = io.connect('http://localhost:1666'); // On crée une socket avec le serveur Node.JS

  this._element = element;
  this._distance = 0;

  this.onTouchStart = this.onTouchStart.bind(this);
  this.onTouchMove = this.onTouchMove.bind(this);
  this.onTouchEnd = this.onTouchEnd.bind(this);

  // On bind nos fonctions aux events touchScreen
  this._element.addEventListener('touchstart', this.onTouchStart);
  this._element.addEventListener('touchmove', this.onTouchMove);
  this._element.addEventListener('touchend', this.onTouchEnd);
 }


 /* Appelé quand l'utilisateur appuie son doigts sur l'écran */
 onTouchStart(event){
  var e = event.changedTouches[0];

  this._isMouseDown = true;

  this._initX = e.pageX;
 }


 /* Appelé quand l'utilisateur bouge son doigts sur l'écran */
 onTouchMove(event){
  var e = event.changedTouches[0];
  if(this._isMouseDown){
   this._presentX = e.pageX;
   this._distance = parseInt((this._presentX - this._initX)/10);

   if(this._distance <= -1) {
    this._initX = e.pageX;
    this.sendDirection('droite');
   } else if (this._distance >= 1) {
    this._initX = e.pageX;
    this.sendDirection('gauche');
   } else {}
  }
 }

 /* Appelé lorsque l'utilisateur retire son doigts de l'écran */
 onTouchEnd(event){
  if(this._isMouseDown){
   this._isMouseDown = false;
  }
 }

 /* Envoi la direction au serveur */
 sendDirection(dir: string){
  console.log(dir);
  this._socket.emit('move', { direction: dir});
 }
}

/* Execute le code qui suit une fois que le script est chargé */
window.onload = () => {
 /* On crée un objet mouvement */
 new Movement(document.body);
}

Passons maintenant à la création du serveur.

Partie 3: Le serveur

Nous voilà arrivé à la dernière partie de cet article, nous allons donc créer le serveur Node.JS qui relayera les ordres envoyés du téléphone vers la page qui affiche la voiture. Nous aurons tout d’abord besoin d’installer le module socket.io (vous savez les inclusions que l’ont faisait sur le client mobile et la page d’affichage ;)). Pour cela rien de plus simple il suffit de taper la commande suivante : npm install socket.io. Maintenant que c’est fait passons au code:

///<reference path='node.d.ts' />
///<reference path='socket.io.d.ts' />

/* On importe les modules nescessaire */
import http = module('http');
import socket = module('socket.io');

class Server {

 /* Déclaration des attributs */
 _port: number;

 /* Constructeur de la classe Server
 *
 * Argument: port (entier)
 * Cet argument permet de définir le port d'écoute du serveur
 *
 */
 constructor(port: number){
  this._port = port;
 }

 /* Méthode qui démarre le serveur */
 start(){
  var server = http.createServer(function(){
   console.log('Direct access to the page');
  });
  var io = socket.listen(server);

  server.listen(this._port)

  io.sockets.on('connection', this.onReception);
 }

 /* Appelé lorsque le serveur reçoit un ordre */
 onReception(socket){

  /* Si c'est un ordre 'move' alors on le transfert vers l'affichage */
  socket.on('move', function(data){
   socket.broadcast.emit('move', data);
  })
 }
}

/*
* On crée un objet Server, puis on le démarre
* Le serveur écoutera sur le port 1666
*/
var serveur = new Server(1666);
serveur.start();

Vous aurez surement remarqué les deux premières lignes du script. Il s’agit en fait de deux fichiers permettant d’utiliser facilement node.js et socket.io en typescript. Ils sont utilisés durant la compilation du code, vous pouvez les trouver ici et ici.

Conclusion

Ce n’est qu’un bref aperçu de ce qu’il est possible de faire avec TypeScript et Node.JS, sans compter que le code présenté ici peut largement être amélioré et optimisé.

Vous pourrez aussi trouver les sources du projet ici ! Sur ce bonsoir.

comments powered by Disqus