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

6 novembre 2019 - : Javascript PHP Tutoriel - : 0 commentaire - : 128 - 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 aux forums de Nouvelle-Techno.fr ou au serveur Discord pour une entraide par chat

Partager

Partager sur Facebook Partager sur Twitter Partager sur LinkedIn

Commentaires

Ecrire un commentaire

Pas encore de commentaire

Ecrire un commentaire