~ read.

Géolocalisation de vos visiteurs en Javascript grâce à HTML 5 !

Voici une fonctionnalité intéressante de l'HTML 5 qui vous permettra de géolocaliser vos visiteurs en Javascript sans bibliothèque supplémentaire, directement grâce aux spécifications du W3C. Cette fonctionnalité est plutôt bien intégrée dans la plupart des navigateurs modernes ainsi que sur les téléphones mobiles (iPhone, Android, etc).

Cependant si la géolocalisation est au centre de votre application, il vous faudra gérer le fait que certains risquent de ne pas l'avoir dans leur navigateur (notamment les utilisateurs de IE < 9).

Google Maps utilise cette fonctionnalité pour vous situer sur la carte. Pour la tester, rendez-vous sur Google Maps et cliquez simplement sur le petit bouton à gauche de la carte, entre les flèches de navigation et le bonhomme de Street View.

Comment ça marche ?

Le navigateur va demander la permission à l'utilisateur (via une barre affichée en haut de la page web) de récupérer différentes informations concernant sa position actuelle (adresse IP, réseaux WiFi dans les environs, etc) et va ensuite les envoyer à un service de géolocalisation, dans le cas de Firefox, à Google Location Services.

Google Location Services renvoie alors une estimation de géolocalisation (latitude, longitude etc.). Suivant votre position actuelle cela peut-être très précis, ou alors pas du tout.

Le fonctionnement est un peu différent pour ce qui est des téléphones mobiles, le navigateur va ici utiliser directement le GPS intégré pour localiser l'utilisateur. La position récupérée sera donc bien plus exacte !

Si vous souhaitez plus d'informations, n'hésitez pas à consulter la page de Mozilla consacrée à ce sujet.

Comment fait-on ?

Nous allons commencer par voir les différentes méthodes et options qui s'offrent à nous, avec des exemples concrets d'utilisation.

Geolocation API

Nous allons utiliser l'objet navigator.geolocation, dont voici les méthodes disponibles :

Méthode Description
getCurrentPosition() Récupère la position actuelle de l'utilisateur.
watchPosition() Récupère la position actuelle qui sera ensuite mise à jour si l'utilisateur se déplace ou si une position plus précise est trouvée.
clearWatch() Annule une recherche de position appelée avec watchPosition().

Les méthodes getCurrentPosition() et watchPosition() acceptent toutes les deux les mêmes paramètres :

Paramètre Description
successCallback Fonction à appeler lorsque la position aura été trouvée.
errorCallback Fonction à appeler en cas d'erreur.
options Objet contenant des options supplémentaires pour la géolocalisation.

Pour utiliser l'API de géolocalisation, il suffit donc d'appeler l'une des méthodes présentées ci-dessus en fournissant les paramètres qui vous sont utiles.

N'oubliez pas également de vérifier si le navigateur/système prend en charge cette fonctionnalité ! Vous pouvez le faire avec Modernizr par exemple, ou simplement en vérifiant si navigator.geolocation existe chez l'utilisateur.

Voici un exemple tout simple où l'API retournera la position à la fonction showLocation() en cas de succès, et une erreur à la fonction errorHandler en cas d'erreur :

// La géolocalisation est-elle prise en charge par le navigateur ?
if(navigator.geolocation)
{
    navigator.geolocation.getCurrentPosition(showLocation, errorHandler);
}
else
{
    alert('Votre navigateur ne prend malheureusement pas en charge la géolocalisation.');
}

Options supplémentaires

Le dernier paramètre de getCurrentPosition() et watchPosition() permet de définir des options supplémentaires pour la localisation. Il s'agit d'un objet pouvant contenir les attributs suivants :

Attribut Valeur Description
enableHighAccuracy true/false Si le navigateur le permet (en général plutôt sur des appareils équipés d'un GPS), vous pouvez demander à récupérer la position exacte du visiteur.
maximumAge millisecondes C'est l'age maximum de la position que pourra vous retourner le navigateur. Permet de retourner une position qui aurait été gardée en cache plutôt que de la recalculer. La géolocalisation sera donc plus rapide mais peut-être pas exacte.
timeout millisecondes C'est le temps maximum à attendre pour obtenir la position.

Voici par exemple comment l'utiliser. Nous récupérons ici une position (sans haute précision) d'il y a moins de 60 secondes, avec un timeout de 27 secondes.

navigator.geolocation.getCurrentPosition(showLocation, errorHandler, {enableHighAccuracy:false, maximumAge:60000, timeout:27000});

Récupérer et traiter la position

Maintenant que nous savons utiliser l'API de géolocalisation, il va falloir traiter les réponses retournées par celle-ci.

En cas de localisation réussie, l'API retournera à la fonction de callback définie (ici showLocation) un objet Position contenant les éléments suivants :

Attribut Type Description
timestamp date Timestamp du moment où la position de l'utilisateur a été récupérée.
coords object Objet nsIDOMGeoPositionCoords contenant les informations sur la position de l'utilisateur.
coords.latitude double La latitude de l'utilisateur, en degrés.
coords.longitude double La longitude de l'utilisateur, en degrés.
coords.altitude double L'altitude de l'utilisateur, en mètres. 0 si l'appareil ne gère pas l'altitude.
coords.accuracy double La précision de la position, en mètres.
coords.altitudeAccuracy double La précision de l'altitude, en mètres. 0 si l'appareil ne gère pas l'altitude.
coords.heading double Défini la direction du mouvement en degrés dans le sens des aiguilles d'une montre.
coords.speed double Vitesse de l'utilisateur, en mètres/secondes.

Il vous suffit donc ensuite de récupérer et de traiter les informations qui vous intéressent.

Voici par exemple une fonction qui affichera une boite de dialogue avec la latitude/longiture de l'utilisateur :

function showLocation(position)
{
    alert('Latitude : '+ position.coords.latitude +' - Longitude : '+ position.coords.latitude);
}

Simple, non ?

Gestion des erreurs

Il peut arriver que la localisation ne fonctionne pas, ou que l'utilisateur la refuse.

Dans ce cas l'API appelera la deuxième fonction de callback, chez nous errorHandler, avec en paramètre un objet PositionError contenant les éléments suivants :

Attribut Type Description
code chiffre C'est le type d'erreur qui s'est produit. Il s'agit d'un chiffre entre 0 et 3. Pour les détails, voir le tableau ci-dessous.
message texte C'est un message d'erreur complet, à insérer dans des logs ou pour débugger par exemple.

Codes d'erreur

Voici la liste des codes d'erreurs possibles, ainsi que leur signification.

Code Titre Description
0 UNKNOWN_ERROR Une erreur inconnue s'est produite et a ainsi empêché de récupérer la position de l'utilisateur.
1 PERMISSION_DENIED La permission de récupérer la position n'a pas été accordée. Soit l'utilisateur l'a directement refusée, soit elle a été refusée par des paramètres du navigateur.
2 POSITION_UNAVAILABLE La position ne peut pas être déterminée. Les fournisseurs de géolocalisation ont retourné une erreur interne.
3 TIMEOUT Le temps maximum d'attente défini pour récupérer une nouvelle position a été dépassé.

A vous ensuite de gérer les erreurs comme bon vous semble. Vous pouvez simplement afficher un message d'erreur générique et logger les informations supplémentaires pour vous permettre de débugger d'éventuels problèmes. Ou alors personnaliser les messages en fonction des codes d'erreur.

Voici donc un exemple de fonction de gestion des erreurs qui affiche un message générique et logge les détails.

function errorHandler(error)
{
    // On log l'erreur sans l'afficher, permet simplement de débugger.
    console.log('Geolocation error : code '+ error.code +' - '+ error.message); 

    // Affichage d'un message d'erreur plus "user friendly" pour l'utilisateur.
    alert('Une erreur est survenue durant la géolocalisation. Veuillez réessayer plus tard ou contacter le support.');
}

Suivre les déplacements de l'utilisateur

Voyons maintenant comment utiliser les fonctions watchPosition() et clearWatch() pour suivre les déplacements des utilisateurs.

La fonction watchPosition() s'utilise exactement de la même manière que la fonction getCurrentPosition(). La seule différence est que watchPosition() va appeler la fonction showLocation() à chaque fois qu'une nouvelle position sera trouvée, c'est à dire dès que l'utilisateur se déplacera ou qu'une position plus précise sera trouvée.

La fonction clearWatch() servira alors à arrêter la recherche de nouvelle position. En effet, la méthode watchPosition() retourne un watchID qu'il suffit ensuite de passer à la fonction clearWatch() pour annuler la mise à jour de la position.

Voici donc comment cela peut être implémenté :

  1. Lorsque l'utilisateur clic sur "Démarrer la géolocalisation", il appelle la fonction watchPosition() et enregistre le watchID dans une variable.
  2. Celle-ci appelle ensuite la fonction showLocation() à chaque fois qu'une nouvelle position est trouvée et affiche donc la latitude/longitude sur la page web.
  3. Lorsque l'utilisateur clic sur "Arrêter", la fonction clearWatch() est appelée avec le watchID récupéré à la première étape.

Exemple complet

Voici un exemple complet d'utilisation de la fonction getCurrentPosition(). Il s'agit en fait simplement du regroupement des différentes parties présentées ci-dessus.
Vous pouvez voir cet exemple en action ici, sur mon jsFiddle.

$(document).ready(function() {
    // La géolocalisation est-elle prise en charge par le navigateur ?
    if(navigator.geolocation)
    {
        navigator.geolocation.getCurrentPosition(showLocation, errorHandler, {enableHighAccuracy:false, maximumAge:60000, timeout:27000});
    }
    else
    {
        alert('Votre navigateur ne prend malheureusement pas en charge la géolocalisation.');
    }
});

// Fonction de traitement de la position
function showLocation(position)
{
    document.write('Latitude : '+ position.coords.latitude +' - Longitude : '+ position.coords.latitude);
}

// Fonction de gestion des erreurs
function errorHandler(error)
{
    // On log l'erreur sans l'afficher, permet simplement de débugger.
    console.log('Geolocation error : code '+ error.code +' - '+ error.message); 

    // Affichage d'un message d'erreur plus "user friendly" pour l'utilisateur.
    alert('Une erreur est survenue durant la géolocalisation. Veuillez réessayer plus tard ou contacter le support.');
}

Sources et liens utiles