OpenStreetmap : Insérer des marqueurs depuis une base de données

6 novembre 2019 - : Javascript PHP Tutoriel - : 7 commentaires - Javascript MySQL Openstreetmap PHP

Cet article fait suite à la demande de plusieurs visiteurs dans les commentaires de l'article "Pas à pas – Insérer une carte OpenStreetMap sur votre site".

Il est conseillé de suivre cet article en préambule.

Nous allons traiter de l'ajout de marqueurs sur une carte OpenStreetMap à partir d'une base de données MySQL.

La base de données

Avant tout chose, voici la base de données dans laquelle seront stockées les différents marqueurs que nous souhaitons afficher sur notre carte.

Base de données

Elle est composée d'une seule table (agences), pour faire simple, dans laquelle nous avons 4 champs

  • id : contient l'identifiant unique de chaque ligne (nombre entier)
  • nom : contient le nom du marqueur (chaîne de caractères)
  • lat : pour la latitude du marqueur (décimal 10 chiffres dont 8 après la virgule)
  • lon : pour la longitude du marqueur (décimal 10 chiffres dont 8 après la virgule)

Nous allons donc interroger cette table au moyen d'un fichier php.

Les fichiers PHP

J'ai fait le choix de créer une structure REST pour le PHP. Je vous invite à consulter l'article "Live Coding : Créer une API REST" pour avoir les détails. Vous pouvez bien sûr faire un fichier simple qui effectue une requête et renvoie du JSON.

Mis à part le fichier de connexion à la base de données, nous avons 2 fichiers, le modèle, pour la requête, et le contrôleur, pour le traitement des données.

Le modèle

Le fichier "Agences.php" est le modèle, qui permet d'effectuer la requête.

Il contient le code suivant

<?php
class Agences{
    // Connexion
    private $connexion;
    private $table = "agences";

    // object properties
    public $id;
    public $nom;
    public $lat;
    public $lon;

    /**
     * Constructeur avec $db pour la connexion à la base de données
     *
     * @param $db
     */
    public function __construct($db){
        $this->connexion = $db;
    }

    /**
     * Lecture des agences
     *
     * @return void
     */
    public function lire(){
        // On écrit la requête
        $sql = "SELECT * FROM " . $this->table;

        // On prépare la requête
        $query = $this->connexion->prepare($sql);

        // On exécute la requête
        $query->execute();

        // On retourne le résultat
        return $query;
    }
}

Le contrôleur

Notre contrôleur "liste.php" contient tout le traitement de la demande, de la vérification de la méthode (imposée par REST) à l'envoi des données en json et des codes de retour HTTP.

Son code est le suivant

<?php
// Headers requis
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");

// On vérifie que la méthode utilisée est correcte
if($_SERVER['REQUEST_METHOD'] == 'GET'){
    // On inclut les fichiers de configuration et d'accès aux données
    include_once './config/Database.php';
    include_once './models/Agences.php';

    // On instancie la base de données
    $database = new Database();
    $db = $database->getConnection();

    // On instancie les agences
    $agence = new Agences($db);

    // On récupère les données
    $stmt = $agence->lire();

    // On vérifie si on a au moins 1 agence
    if($stmt->rowCount() > 0){
        // On initialise un tableau associatif
        $tableauAgences = [];
        $tableauAgences['agences'] = [];

        // On parcourt les agences
        while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
            extract($row);

            $agen = [
                "id" => $id,
                "nom" => $nom,
                "lat" => $lat,
                "lon" => $lon,
            ];

            $tableauAgences['agences'][] = $agen;
        }

        // On envoie le code réponse 200 OK
        http_response_code(200);

        // On encode en json et on envoie
        echo json_encode($tableauAgences);
    }

}else{
    // On gère l'erreur
    http_response_code(405);
    echo json_encode(["message" => "La méthode n'est pas autorisée"]);
}

Méthode "simplifiée"

Pour celles et ceux d'entre vous qui souhaitent un fichier PHP plus simple, voici un exemple qui fera un travail similaire

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

$host = "localhost";
$db_name = "agences";
$username = "root";
$password = "";
try{
    $db = new PDO("mysql:host=" . $host . ";dbname=" . $db_name, $username, $password);
    $db->exec("set names utf8");
}catch(PDOException $exception){
    echo "Erreur de connexion : " . $exception->getMessage();
}

$sql = "SELECT * FROM agences";

// On prépare la requête
$query = $db->prepare($sql);

// On exécute la requête
$query->execute();

while($row = $query->fetch(PDO::FETCH_ASSOC)){
    extract($row);

    $agen = [
        "id" => $id,
        "nom" => $nom,
        "lat" => $lat,
        "lon" => $lon,
    ];

    $tableauAgences['agences'][] = $agen;
}

// On encode en json et on envoie
echo json_encode($tableauAgences);

La carte

Nous voici maintenant au coeur du sujet, la gestion de la carte.

Comme sur d'autres articles, je mets le HTML, le CSS et le javascript dans le même fichier pour simplifier les exemples, mais il est fortement conseillé de les séparer dans des fichiers distincts.

Nous allons partir d'un fichier standard dans lequel nous avons initialisé une carte, avec les lignes suivantes

<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>OpenStreetMap</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
        <!-- CSS -->
        <style>
            body{
                margin:0
            }
            #maCarte{
                height: 100vh;
            }
        </style>
    </head>
    <body>
        <div id="maCarte"></div>

        <!-- Fichiers Javascript -->
        <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js" integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og==" crossorigin=""></script>
        <script>
            // On initialise la carte
            var carte = L.map('maCarte').setView([48.852969, 2.349903], 13);
            
            // On charge les "tuiles"
            L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {
                // Il est toujours bien de laisser le lien vers la source des données
                attribution: 'données © <a href="//osm.org/copyright">OpenStreetMap</a>/ODbL - rendu <a href="//openstreetmap.fr">OSM France</a>',
                minZoom: 1,
                maxZoom: 20
            }).addTo(carte);
        </script>
    </body>
</html>

Dans ce fichier, nous allons ensuite interroger l'url qui renvoie nos données, c'est à dire le fichier "liste.php" créé dans la partie précédente

Pour ce faire, nous utiliserons Ajax et l'objet XMLHttpRequest.

let xmlhttp = new XMLHttpRequest();

xmlhttp.onreadystatechange = () => {
    // La transaction est terminée ?
    if(xmlhttp.readyState == 4){
        // Si la transaction est un succès
        if(xmlhttp.status == 200){
            // On traite les données reçues

        }else{
            console.log(xmlhttp.statusText);
        }
    }
}

xmlhttp.open("GET", "http://agence.test/liste_simple.php");

xmlhttp.send(null);

A l'intérieur de la 2ème condition, nous allons traiter les données, à commencer par convertir le json reçu en objet Javascript

let donnees = JSON.parse(xmlhttp.responseText)

Puis nous allons boucler sur les objets reçus, qui sont rassemblés dans notre exemple sous le nom "agences"

// On boucle sur les données (ES8)
Object.entries(donnees.agences).forEach(agence => {
    // Ici j'ai une seule agence

})

Et enfin on crée un marqueur pour chaque agence et on lui met un popup

// On crée un marqueur pour l'agence
let marker = L.marker([agence[1].lat, agence[1].lon]).addTo(carte)

// On met le popup
marker.bindPopup(agence[1].nom)

Ce qui donne un code complet comme ceci

<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>OpenStreetMap</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
        <!-- CSS -->
        <style>
            body{
                margin:0
            }
            #maCarte{
                height: 100vh;
            }
        </style>
    </head>
    <body>
        <div id="maCarte"></div>

        <!-- Fichiers Javascript -->
        <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js" integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og==" crossorigin=""></script>
        <script>
            // On initialise la carte
            var carte = L.map('maCarte').setView([48.852969, 2.349903], 13);
            
            // On charge les "tuiles"
            L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {
                // Il est toujours bien de laisser le lien vers la source des données
                attribution: 'données © <a href="//osm.org/copyright">OpenStreetMap</a>/ODbL - rendu <a href="//openstreetmap.fr">OSM France</a>',
                minZoom: 1,
                maxZoom: 20
            }).addTo(carte);

            let xmlhttp = new XMLHttpRequest();

            xmlhttp.onreadystatechange = () => {
                // La transaction est terminée ?
                if(xmlhttp.readyState == 4){
                    // Si la transaction est un succès
                    if(xmlhttp.status == 200){
                        // On traite les données reçues
                        let donnees = JSON.parse(xmlhttp.responseText)
                        
                        // On boucle sur les données (ES8)
                        Object.entries(donnees.agences).forEach(agence => {
                            // Ici j'ai une seule agence
                            // On crée un marqueur pour l'agence
                            let marker = L.marker([agence[1].lat, agence[1].lon]).addTo(carte)
                            marker.bindPopup(agence[1].nom)
                        })
                    }else{
                        console.log(xmlhttp.statusText);
                    }
                }
            }

            xmlhttp.open("GET", "http://agence.test/liste_simple.php");

            xmlhttp.send(null);
        </script>
    </body>
</html>

Obtenir de l'aide

Pour obtenir de l'aide, vous pouvez accéder au serveur Discord pour une entraide par chat

Partager

Partager sur Facebook Partager sur Twitter Partager sur LinkedIn

Commentaires

jison a écrit le 30 juillet 2020 à 13:28

salut, ben je suis debutant dans ce domaine, si possible pouriez-vous m'aider a créer  ujne catre qui qui affiche les markers de puis la base de donnée et afficher une detailes si on click dessus svp aidez moi 

Répondre

Elnofey a écrit le 30 juillet 2020 à 09:00

Bonjour,

J'ai le même soucis, vous souvenez-vous comment vous avez résolu ça?

Répondre

safia a écrit le 4 juillet 2020 à 11:57

Bonjour,

Merci pour ce très bon tutoriel. J'ai cependant une question. Peut on rajouter en plus d'un marqueur issu d'une base de données, une géolocalisation du visiteur et le placer sur la carte également?

Merci d'avance de votre retour.

 

Répondre

Nouvelle-Techno.fr a répondu le 8 juillet 2020 à 09:26

Bonjour,

Bien sûr, c'est exactement ce que fait le code de l'article, ajouter plusieurs points.

Répondre

w a écrit le 12 avril 2020 à 06:40

Salut Monsieur, j’espère que vous êtes en bon santé, merci beaucoup pour ce tutoriel, vraiment elle est très intéressante, je vous demande s’il est possible de compléter ce cours avec nous, tout ce qui concerne :

Comment d’ajouter fullscreen, l’échelle, chercher location, et ma position dans notre carte. Comment changer le marker par un autre et en fin comment écrire plusieurs caractéristiques sur le marker

S’il vous plait monsieur je suis très besoin de ces notions, parce qu’au début j’ai travaillé sur ces notions mais ne sont pas liées aux bases données, et je trouve un problème.

Voila le script qui j’ai travaillé :

<html>

<head>

  <meta charset="utf-8" />

  <title>leaflet</title>

  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

 

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"

  integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="

  crossorigin=""/>

  <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"

  integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="

  crossorigin=""></script>

 

  <script src="https://unpkg.com/esri-leaflet@2.3.3/dist/esri-leaflet.js"

  integrity="sha512-cMQ5e58BDuu1pr9BQ/eGRn6HaR6Olh0ofcHFWe5XesdCITVuSBiBZZbhCijBe5ya238f/zMMRYIMIIg1jxv4sQ=="

  crossorigin=""></script>

 

  <link rel="stylesheet" href="https://unpkg.com/esri-leaflet-geocoder@2.3.2/dist/esri-leaflet-geocoder.css"

    integrity="sha512-IM3Hs+feyi40yZhDH6kV8vQMg4Fh20s9OzInIIAc4nx7aMYMfo+IenRUekoYsHZqGkREUgx0VvlEsgm7nCDW9g=="

    crossorigin="">

  <script src="https://unpkg.com/esri-leaflet-geocoder@2.3.2/dist/esri-leaflet-geocoder.js"

    integrity="sha512-8twnXcrOGP3WfMvjB0jS5pNigFuIWj4ALwWEgxhZ+mxvjF5/FBPVd5uAxqT8dd2kUmTVK9+yQJ4CmTmSg/sXAQ=="

    crossorigin=""></script>

 

<script src='https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/Leaflet.fullscreen.min.js'></script>

<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/leaflet.fullscreen.css' rel='stylesheet' />

 

  <style>

    body { margin:0; padding:0; }

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

  </style>

</head>

 

<body>

<script type="text/javascript" src="app.js"></script>

<div id="map"></div>

<script>

 var N0= [32.348426,-6.340571];

var map = L.map('map').setView(N0, 13);

 L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {

  maxZoom: 20

}).addTo(map);

var greenIcon = L.icon({

    iconUrl: 'tree.png',

    iconSize:     [32, 37], // size of the icon

    iconAnchor:   [16, 37], // point of the icon which will correspond to marker's location

    popupAnchor:  [0, -30] // point from which the popup should open relative to the iconAnchor

});

// ajout d'un markeur

var N0 = L.marker(N0, {icon:greenIcon});

var A=L.layerGroup([N0]);

var overlays= {

  "Atlass" : A,}

L.control.layers(null, overlays).addTo(map);

L.control.scale().addTo(map);

map.addControl(new L.Control.Fullscreen());

N0 .bindPopup('<h4>IDBASE : 0<br>TYPE EMPLACEMENT : palmier<br>DOMINIALITE : jardin<br>ARRONDISSEMENT : beni mellal atlass<br>GENRE : <br>HAUTEUR : 12<br>CIRCONFERENCE : 170<br>X : -6.33872019178<br>Y :  32.35019338190</h4>');

 

 var searchControl = L.esri.Geocoding.geosearch().addTo(map);

  var results = L.layerGroup().addTo(map);

  searchControl.on('results', function (data) {

    results.clearLayers();

    for (var i = data.results.length - 1; i >= 0; i--) {

      results.addLayer(L.marker(data.results[i].latlng));

    }

  });

</script>

</body>

</html>

Répondre

adrien a écrit le 25 mars 2020 à 13:32

Bonjour,

Je vous remercie pour ce très bon tutoriel. J'ai pu l'adapter à mon site internet et cela fonctionne.

Cependant je voudrais maintenant adapter le système de cluster que vous proposez dans ce tutoriel https://nouvelle-techno.fr/actualites/2018/05/11/pas-a-pas-inserer-une-carte-openstreetmap-sur-votre-site?page=1 mais je n'y arrive pas.

Ci-dessous vous trouverez mon code.

<include file="../headers/header_common_head.tpl" />
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
		<link rel="stylesheet" type="text/css" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.css" />
        <link rel="stylesheet" type="text/css" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.Default.css" />
		<!-- CSS -->
        <style>
            body{margin:0}
            #maCarte{height: 100vh;}
        </style>
<include file="../headers/header_common_body.tpl" />

<div class="arbre">Vous &#234;tes ici : 
	<a href="index.php">R&ecirc;ve de montagne</a> &gt;
	Visualiser un fond de carte
</div>
<div class="cadre">
	<div class="cadre_1_hg">
		<div class="cadre_1_hd">
			<h2>Localisation d'un lieu</h2>
		</div>
	</div>  
	<div class="cadre_1_cg">
		<div class="cadre_1_cd">	
		
			<div id="maCarte"></div>
			
		</div>
	</div>		
			
	<div class="cadre_1_bg">
		<div class="cadre_1_bd">
			<div class="cadre_1_b">
				&nbsp	
			</div>
		</div>
	</div>
</div>

<!-- Fichiers Javascript -->
<script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js" integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og==" crossorigin=""></script>
<script type='text/javascript' src='https://unpkg.com/leaflet.markercluster@1.3.0/dist/leaflet.markercluster.js'></script>
<script>
    // On initialise la carte
    var markerClusters; // Servira à stocker les groupes de marqueurs
	var macarte = null;
	var carte = L.map('maCarte').setView([48.852969, 2.349903], 13);
	markerClusters = L.markerClusterGroup();
	

            
    // On charge les "tuiles"
    L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {
    
	// Il est toujours bien de laisser le lien vers la source des données
    attribution: 'données © <a href="//osm.org/copyright">OpenStreetMap</a>/ODbL - rendu <a href="//openstreetmap.fr">OSM France</a>',
    minZoom: 1,
    maxZoom: 20
    }).addTo(carte);

    let xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = () => 
	{
		// La transaction est terminée ?
		if(xmlhttp.readyState == 4)
		{
			// Si la transaction est un succès
			if(xmlhttp.status == 200){
				// On traite les données reçues
				let donnees = JSON.parse(xmlhttp.responseText)
							
				// On boucle sur les données (ES8)
				Object.entries(donnees.agences).forEach(agence => {
					// Ici j'ai une seule agence
					// On crée un marqueur pour l'agence
					let marker = L.marker([agence[1].lat, agence[1].lon]).addTo(carte)
					marker.bindPopup(agence[1].nom)
					markerClusters.addLayer(marker)
				})
				macarte.addLayer(markerClusters);
				
			}else
			{
				console.log(xmlhttp.statusText);
			}
		}
			
    }
	
    xmlhttp.open("GET", "http://127.0.0.1/revedemontagne/google/carte_gene.php");
	xmlhttp.send(null);

</script>
		
		

<include file="../footer.tpl" />

La carte s'affiche bien mais plus les points enregistrés dans la base de données.

Pouvez-vous m'aider.

Je vous remercie

 

Répondre

adrien a répondu le 27 mars 2020 à 13:16

Bonjour,

Je vous remercie pour ce superbe tutoriel.

J'ai pu finalement trouver pourquoi mon adaptation de code ne fonctionner pas.

Maintenant ça marche super bien :) https://revedemontagne.fr/carte-openstreetmap.html

Répondre

Obtenir de l'aide

Il n'est plus possible d'ajouter de commentaires.

Pour obtenir de l'aide, vous pouvez accéder au serveur Discord pour une entraide par chat