La géolocalisation avec Javascript

05 février 2017

Cet article date de 2017 et présente une approche bas-niveau. Si vous utilisez React, je vous recommande d'utiliser la librairie de hooks react-use et son hook useGeolocation.

Dans ce court article, nous allons voir comment récupérer les informations de géolocalisation du navigateur et les comparer à d’autres points.

En premier, vous pouvez tester avec cet exemple qui montre une liste de points abritrairement choisis les plus proches de vous. N’oubliez pas d’autoriser la géolocalisation si votre navigateur vous le propose.

Le support sur les différents navigateurs est excellent ( voir sur caniuse.com ), mais on peut désactiver la fonctionnalité dans l’éventualité où l’API n’est pas disponible.

Tester si la géolocalisation est disponible est très simple :

```javascript
if (navigator.geolocation) {
    // do stuff here... add a button, for instance
}
```

Récupérer la position de l'utilisateur

Il suffit d’une fonction pour récupérer la position du navigateur :

navigator.geolocation.getCurrentPosition

Elle reçoit deux fonctions et un objet d’options en paramètre.

La première fonction reçoit la position et est exécutée en cas de succès.

La seconde fonction gère les erreurs, par exemple si l’utilisateur a désactivé la géolocalisation ou si pour une raison technique, la position ne peut être obtenue.

L’objet d’options permet de paramétrer trois options :

  • enableHighAccuracy: défaut à false. Si true, le navigateur essaie d’avoir la meilleure précision possible. Cela peut entraîner un temps de réponse plus lent.
  • timeout: défaut à Infinity. On peut spécifier un temps d’attente maximum en millisecondes. Il est très important de définir une valeur limite à ce paramètre. De cette sorte, on est sûr de recevoir une erreur si l’obtention de la position prend trop de temps.
  • maximumAge: défaut à 0. La réponse peut être mise en cache pour un temps indiqué en millisecondes.

Voici une fonction qui trouve les coordonnées du navigateur après avoir obtenu l’autorisation de l’utilisateur :

var myPosition = null;

function getLocation() {
    navigator.geolocation.getCurrentPosition((position) => {
        // return the coordinates
        myPosition = position.coords;
    }, (error) => {
        // check if the user denied geolocation, or if there was any other problem
        if (error.code == error.PERMISSION_DENIED) {
            alert('Geolocation has been disabled on this page');
        } else {
            alert('Unable to find your position, try again later.');
        }
    }, {
        timeout: 10000
    });
}

Comparer des points géolocalisés

Cela permet par exemple de fournir une fonctionnalité du type « 10 restaurants se trouvent autour de vous ».

const points = [
    { name: 'Lausanne', lat: 46.534271, lng: 6.620206 },
    { name: 'Zürich', lat: 47.381583, lng: 8.531827 },
    { name: 'Le Mans', lat: 48.001837, lng: 0.194578 },
    { name: 'Montpellier', lat: 43.624121, lng: 3.871447 },
    { name: 'Münich', lat: 48.140408, lng: 11.586595 },
    { name: 'Mexico', lat: 19.427701, lng: -99.266023 },
    { name: 'Buenos Aires', lat: -34.422808, lng: -58.572664 },
    { name: 'Brasilia', lat: -15.792772, lng: -47.883031 },
    { name: 'Yaoundé', lat: 3.875265, lng: 11.487751 },
    { name: 'Oklahoma City', lat: 35.509992, lng: -97.539860 },
    { name: 'Québec', lat: 45.502601, lng: -73.589665 }
];

/**
 * Filter the list in the given radius in km
 */
function filterPoints(radius) {
    // don't do anything else until we have a position
    if (myPosition == null) {
        return false;
    }

    // return only the points in the area
    return points.filter(
        (point) => calculateDistance(myPosition.latitude, myPosition.longitude, point.lat, point.lng) <= radius
    );
}

Et finalement, le coeur de cette comparaison, c'est la fonction calculateDistance que voici :

function calculateDistance(lat1, long1, lat2, long2) {
    var p = 0.017453292519943295;    // Math.PI / 180
    var c = Math.cos;
    var a = 0.5 - c((lat2 - lat1) * p)/2 +
        c(lat1 * p) * c(lat2 * p) *
        (1 - c((long2 - long1) * p))/2;

    return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
}

On fournit les paramètres requis, soit les coordonnées des deux points à comparer et on obtient une distance en kilomètres.

Conclusion

Géolocaliser un utilisateur avec JavaScript offre une expérience utilisateur intéressante

Filtrer des points en frontend est une façon élégante d’offrir à vos utilisateurs une expérience personnalisée et utile.

Je vous laisse à disposition un exemple fonctionnel ici : Filtrer des points selon votre localisation