Géolocalisation sur Open Street Map

entre Vous et Nous

Accès direct au résultat

Le problème

Savoir où on est et le montrer sur une carte interactive.

La solution

Pour réaliser une telle application 100% web il nous faut :

La carte OSM (ou OpenStreetMap)

Ce système de cartographie coopératif est exploitable par la librairie OpenLayers qui est écrite en javascript. Celle ci permet :

Ceci devrait convenir à notre usage, mais avant de produire du code applicatif nous allons créer notre propre librairie exploitant OpenLayers.

Cette librairie devra :

Cette librairie nommée utils_osm_pts sera placée dans le fichier es/utils_osm_pts.js et sera donc composée des éléments suivants :

la fonction utils_osm_pts(pts_list)

cette fonction correspond à la déclaration de l'objet utils_osm_pts qui constitue le seul élément de cette librairie.

Elle comporte donc :

function utils_osm_pts(pts_list) {
    var map;    // objet carte utile pour passage de paramètres entre les 2 fonctions
    var ptLoc;  // le point à déplacer créé par draw_map() et manipulé par move_point()

    // dessin de la carte
    function draw_map() {
...
...
...
    }

    // déplacement du point "localisation" sur la carte
    this.move_point = function(lon, lat, head, follow) {
...
...
...
    }

    // exécution du dessin en fin de chargement
    window.addEventListener('load', draw_map, false);
}
La méthode draw_map(pts_list)

Cette méthode est une méthode privée, c'est-à-dire uniquement exploitable dans cette librairie.

Elle est en charge de :

function draw_map() {
    // création de la carte avec les contôles associés
    map = new OpenLayers.Map({
        div: "map",
        controls:[new OpenLayers.Control.Zoom(),
                  new OpenLayers.Control.KeyboardDefaults(),
                  new OpenLayers.Control.Navigation(),
                  new OpenLayers.Control.ScaleLine({bottomOutUnits: ''})]
    });
	
    map.addLayer(new OpenLayers.Layer.OSM());


    // création du plan contenant les points de repère
    refpts_layer = new OpenLayers.Layer.Vector("pts_list", {projection: "EPSG:4326"});
    // création des contres des points afin qu'ils soient cliquables
    var selectMarkerControl = new OpenLayers.Control.SelectFeature(refpts_layer, {
	// fonction invoquée lors d'une séléction (clic impair) sur un point
	onSelect: function(feature) {
	    var le_popup = new OpenLayers.Popup.FramedCloud("Popup",
							    feature.attributes.lonlat,
							    null,
							    feature.attributes.description,
							    null,
							    true);
	    feature.popup = le_popup;
	    map.addPopup(le_popup);
	},
	// fonction invoquée lors d'une séléction (clic pair) sur un point
	onUnselect: function(feature) {
	    map.removePopup(feature.popup);
	    feature.popup.destroy();
	    feature.popup = null;
	},

	// acceptation de plusieurs points simultanément sélectionné
	multiple: true,

	// comportement bistable par clic (ou touch)
	toggle: true,
    });
    // mise en place des contres et du plan de points
    map.addControl(selectMarkerControl);
    selectMarkerControl.activate();
    map.addLayer(refpts_layer);
	

    // dessin des points transmis
    for (var i = 0; i < pts_list.length; i++) {
	var pt = pts_list[i];
	var LonLat = new OpenLayers.LonLat(pt.lon, pt.lat).transform("EPSG:4326", map.getProjectionObject());
	var ptGeo = new OpenLayers.Geometry.Point(pt.lon, pt.lat);
	ptGeo.transform("EPSG:4326", map.getProjectionObject());
	map.setCenter(LonLat);
	var laFeature = new OpenLayers.Feature.Vector(ptGeo,
						      {description:pt.descr, lonlat: LonLat},
						      {externalGraphic: pt.icon_url,
						       graphicWidth: pt.icon_width,
						       graphicHeight: pt.icon_height,
						       graphicXOffset: pt.icon_shiftX,
						       graphicYOffset: pt.icon_shiftY,
						       graphicOpacity: pt.opacity,
						       rotation: pt.rotation,
						       title: pt.title});
	refpts_layer.addFeatures(laFeature);
	if (pt.showPopup) selectMarkerControl.select(laFeature);
	if (pt.name == 'localisation') {
	    // le point localisé sera rendu accéssible par la fonction de déplacement asynchrone
	    ptLoc = laFeature;
	}
    }
    // ajustement de la carte à la zone couvrant les poins visualisés
    map.zoomToExtent(refpts_layer.getDataExtent());
}
La méthode move_point(lon, lat, cap, follow)

Cette méthode est une méthode publique, c'est-à-dire exploitable en dehors de cette librairie.

Elle est en charge de :

this.move_point = function(lon, lat, head, follow) {
    var LonLat = new OpenLayers.LonLat(lon, lat).transform("EPSG:4326", map.getProjectionObject());
    ptLoc.move(LonLat);
    ptLoc.attributes.lonlat = LonLat;
    ptLoc.style.rotation = head;
    if(follow) {
        map.setCenter(LonLat,map.zoom);
        map.zoomToExtent(refpts_layer.getDataExtent());
    }
}

Notre librairie est ainsi terminée, passons à la partie contrôle de le position.

utiliser les API de localisation

Pour piloter le point de notre position nous allons utiliser les fonctions javascript suivantes :

function success(pos) {
    var lat = pos.coords.latitude;
    var lon = pos.coords.longitude;
    var head = pos.coords.heading;
    var alti = pos.coords.altitude;
    utils_osm.move_point(lon, lat, head, false);
    // on affiche le cap uniquement si l'appareil le supporte
    if (head) document.getElementById('cap').textContent = parseFloat(head).toFixed(2)+'°';
    else document.getElementById('cap').textContent = 'inconnu';
    // on affiche l'altitude uniquement si l'appareil le supporte
    if (alti) document.getElementById('alti').textContent = parseFloat(alti).toFixed(0)+'m';
    else document.getElementById('alti').textContent = 'inconnu';

};

function error(err) {
    alert('ERROR(' + err.code + '): ' + err.message);
}

options = {
    enableHighAccuracy: false,
    timeout: 60000,
    maximumAge: 0,
}

function RunLocation() {
    if (navigator.geolocation) {
        navigator.geolocation.watchPosition(success, error, options);
    } else {
        alert("Votre navigateur ne prend pas en compte la géolocalisation HTML5");
    }
}

// on lance le suivi de la position une fois la page chargée.
window.addEventListener('load', RunLocation, false);
}

Ce code javascript sera placée dans le fichier es/geoloc.js.

Maintenant il n'y a plus qu'a réaliser la page HTML contenant le code pour agglomérer le tout.

Le document HTML

Ce document doit donc contenir :

La feuille de style css/geoloc.css

Celle-ci s'adaptera aux dispositifs de petite taille (< 160mm).

body {background-color:#888}
body>h1 {
    width:100%;
    position:absolute;
    text-align:center;
    color:#FFF;
    margin-left:-50%;
    top:50%;
    left:50%;
    right:0;
    bottom:0;
}

body>h2 {
    background-color:rgba(255,255,255,0.5);
    width:auto;
    position:absolute;
    margin:0 auto;
    top:1em;
    right:1em;
    z-index:10;
    border:solid 0.1ex rgba(255,255,0,0.6);
    border-radius:0.2em;
}
body>h2>em {
    color:#800;
}

#map {
    top:0;
    left:0;
    bottom:0;
    right:0;
    position:
    fixed;
}

@media handheld, screen and (max-width: 160mm), screen and (max-device-width: 160mm) {
    body {
        font-size:200%;
        font-size:6vw;
    }
    body>h2 {
        font-size:300%;
        font-size:10vw;
        top:0.1em;
        right:0.1em;
    }
}
Le document HTML

Il intègre donc l'ensemble des librairies javascript et feuilles de style css ainsi que la définition de 2 points dont un correspondra à notre position.

body {background-color:#888}<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta charset="utf-8">
    <title>Pour vous situer sur terre...</title>
    <link rel="icon" type="images/png" href="icons/pieton.svg" />
    <link rel="stylesheet" type="text/css" href="css/geoloc.css" />
    <script>
    var ref_points = [
       {lon: 1.446,
        lat: 43.59,
        icon_url: 'icons/pieton.svg',
        name: 'localisation',
        icon_width: '2em',
        icon_height: '2em',
        icon_shiftX: 0,
        icon_shiftY: 0,
        descr: '<div id="bul2"><em>Vous</em> êtes ici...</a></div>',
        title: 'Vous'},

       {lon: 1.44608,
        lat: 43.5955,
        icon_url: 'icons/logo_ven_loc.svg',
        icon_width: '2em',
        icon_height: '2em',
        icon_shiftX: 0,
        icon_shiftY: 0,
        descr: '<div id="bul1"><a href="http://www.vous-et-nous.eu" title="Nous"><em>Nous</em> sommes là</a></div>',
        title: 'Nous'}
    ];
    </script>
    <script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script>
    <script type="text/javascript" src="es/utils_osm_pts.js"></script>
    <script type="text/javascript" src="es/geoloc.js"></script>

    </script>
  </head>
  <body>
    <h1>Assistance à la localisation</h1>
    <h2>cap <em id="cap">--</em><br/>
altitude <em id="alti">--</em></h2>
    <div id="map"></div>
  </body>
</html>

Et c'est fini, il n'y a plus qu'a charger la page de localisation ainsi réalisée dans un navigateur et jouer avec... mais attention : la localisation à partir du navigateur doit être activée, par défaut celle-ci est souvent désactivée pour des raisons de confidentialité !