# 260302 Mise en place du Frontend

Nous allons créer une page web contenant une carte interactive (basée sur OpenStreetMap). Quand tu cliqueras n'importe où sur cette carte, la page web enverra les coordonnées à ton API (que nous avons codée la semaine dernière). Ton serveur vérifiera si le clic est dans la zone "Paris Test" et affichera le résultat directement sur la carte sous forme de petite bulle (popup).

Pour cela, nous allons utiliser **Leaflet.js**, qui est la bibliothèque standard, légère et gratuite pour faire de la cartographie sur le web.

Voici les 3 étapes pour y parvenir.

---

### Étape 1 : Créer le dossier "public"

Sur ton VPS, nous allons créer un dossier qui contiendra les fichiers visibles par les utilisateurs (comme les pages HTML).

1. Connecte-toi à ton VPS et place-toi dans le dossier du projet :
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-847 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQwgQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2446650269-847 ng-star-inserted"><span class="ng-tns-c2446650269-847">Bash</span><div _ngcontent-ng-c2446650269="" class="buttons ng-tns-c2446650269-847 ng-star-inserted"><button aria-label="Copier le code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2446650269-847 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-847"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-847"></div></div></div>```
    cd /var/www/alteris-geomatic
    
    ```
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-847 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQwgQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-847"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-847"></div></div></div>
2. Crée le dossier `public` :
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-848 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQwwQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2446650269-848 ng-star-inserted"><span class="ng-tns-c2446650269-848">Bash</span><div _ngcontent-ng-c2446650269="" class="buttons ng-tns-c2446650269-848 ng-star-inserted"><button aria-label="Copier le code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2446650269-848 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-848"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-848"></div></div></div>```
    mkdir public
    
    ```
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-848 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQwwQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-848"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-848"></div></div></div>

### Étape 2 : Créer la page web (`index.html`)

C'est ici que nous allons intégrer la carte.

1. Crée et ouvre le fichier HTML dans le dossier `public` :
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-849 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQxAQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2446650269-849 ng-star-inserted"><span class="ng-tns-c2446650269-849">Bash</span><div _ngcontent-ng-c2446650269="" class="buttons ng-tns-c2446650269-849 ng-star-inserted"><button aria-label="Copier le code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2446650269-849 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-849"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-849"></div></div></div>```
    nano public/index.html
    
    ```
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-849 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQxAQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-849"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-849"></div></div></div>
2. Copie et colle ce code complet. J'ai ajouté des commentaires pour t'expliquer exactement ce que fait chaque partie :
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-850 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQxQQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2446650269-850 ng-star-inserted"><span class="ng-tns-c2446650269-850">HTML</span><div _ngcontent-ng-c2446650269="" class="buttons ng-tns-c2446650269-850 ng-star-inserted"><button aria-label="Copier le code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2446650269-850 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-850"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-850"></div></div></div>```
    
    <html lang="fr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Alteris - Carte Interactive</title>
    
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
    
        <style>
            /* On s'assure que la carte prenne tout l'écran */
            body { margin: 0; padding: 0; }
            #maCarte { width: 100vw; height: 100vh; }
        </style>
    </head>
    <body>
    
        <div id="maCarte"></div>
    
        <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
    
        <script>
            // --- INITIALISATION DE LA CARTE ---
            // On centre la vue sur Paris avec un niveau de zoom de 10
            const map = L.map('maCarte').setView([48.85, 2.35], 10);
    
            // On ajoute le fond de plan gratuit OpenStreetMap
            L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                maxZoom: 19,
                attribution: '© OpenStreetMap contributors'
            }).addTo(map);
    
            // --- LOGIQUE DE CLIC ---
            // On écoute l'événement "click" sur la carte
            map.on('click', async function(evenement) {
    
                // On récupère la latitude et la longitude cliquées
                const lat = evenement.latlng.lat;
                const lng = evenement.latlng.lng;
    
                // On prépare notre format GeoJSON pour l'API
                // Attention : en GeoJSON, on met toujours [Longitude, Latitude]
                const pointGeoJSON = {
                    type: "Point",
                    coordinates: [lng, lat]
                };
    
                try {
                    // On envoie la donnée à notre serveur Node.js
                    const reponse = await fetch('/api/check-zone', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify(pointGeoJSON)
                    });
    
                    const resultat = await reponse.json();
    
                    // On affiche le message du serveur dans une bulle sur la carte
                    L.popup()
                        .setLatLng(evenement.latlng)
                        .setContent("<b>Résultat spatial :</b><br>" + resultat.message)
                        .openOn(map);
    
                } catch (erreur) {
                    console.error("Erreur :", erreur);
                    alert("Impossible de joindre le serveur Alteris.");
                }
            });
        </script>
    </body>
    </html>
    
    ```
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-850 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQxQQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-850"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-850"></div></div></div>
3. Sauvegarde et quitte (`Ctrl+O`, `Entrée`, `Ctrl+X`).

### Étape 3 : Indiquer au serveur Node.js d'afficher cette page

Actuellement, notre serveur `server.js` ne sait faire que de l'API. Nous allons lui dire de "servir" notre nouveau dossier public lorsqu'un visiteur arrive sur le site.

1. Ouvre ton fichier serveur :
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-851 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQxgQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2446650269-851 ng-star-inserted"><span class="ng-tns-c2446650269-851">Bash</span><div _ngcontent-ng-c2446650269="" class="buttons ng-tns-c2446650269-851 ng-star-inserted"><button aria-label="Copier le code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2446650269-851 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-851"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-851"></div></div></div>```
    nano server.js
    
    ```
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-851 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQxgQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-851"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-851"></div></div></div>
2. Trouve ces lignes au début de ton fichier :
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-852 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQxwQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2446650269-852 ng-star-inserted"><span class="ng-tns-c2446650269-852">JavaScript</span><div _ngcontent-ng-c2446650269="" class="buttons ng-tns-c2446650269-852 ng-star-inserted"><button aria-label="Copier le code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2446650269-852 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-852"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-852"></div></div></div>```
    app.use(bodyParser.json());
    
    // Route de vérification simple
    app.get('/', (req, res) => {
        res.send('Serveur Alteris Géomatique opérationnel 🟢');
    });
    
    ```
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-852 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQxwQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-852"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-852"></div></div></div>
3. **Remplace la route `app.get(...)`** par cette simple ligne de code qui indique le dossier public :
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-853 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQyAQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2446650269-853 ng-star-inserted"><span class="ng-tns-c2446650269-853">JavaScript</span><div _ngcontent-ng-c2446650269="" class="buttons ng-tns-c2446650269-853 ng-star-inserted"><button aria-label="Copier le code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2446650269-853 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-853"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-853"></div></div></div>```
    app.use(bodyParser.json());
    
    // On demande à Express de servir les fichiers du dossier "public"
    app.use(express.static('public'));
    
    ```
    
    <div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-853 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQyAQ" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-853"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-853"></div></div></div>
4. Sauvegarde et quitte (`Ctrl+O`, `Entrée`, `Ctrl+X`).

### Étape 4 : Redémarrer et Tester

Pour que Node.js lise ton fichier `server.js` mis à jour, il faut le relancer via PM2 :

<div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-854 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQyQQ" decode-data-ved="1" id="bkmrk-bash" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2446650269-854 ng-star-inserted"><span class="ng-tns-c2446650269-854">Bash</span><div _ngcontent-ng-c2446650269="" class="buttons ng-tns-c2446650269-854 ng-star-inserted"><button aria-label="Copier le code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2446650269-854 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-854"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-854"></div></div></div>```
pm2 restart alteris-api

```

<div _ngcontent-ng-c2446650269="" class="code-block ng-tns-c2446650269-854 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwjS_fmv4oCTAxUAAAAAHQAAAAAQyQQ" decode-data-ved="1" id="bkmrk--2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_0acb689ec00ec265","c_5b7951c496f77574",null,"rc_4c81634ad6ea5d1c",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c2446650269="" class="formatted-code-block-internal-container ng-tns-c2446650269-854"><div _ngcontent-ng-c2446650269="" class="animated-opacity ng-tns-c2446650269-854"></div></div></div>---

### C'est l'heure du test visuel ! 🗺️

Ouvre ton navigateur web (Chrome, Firefox, etc.) et rends-toi sur l'adresse de ton projet : 👉 **[https://alteris.juxjux.ovh](https://www.google.com/search?q=https://alteris.juxjux.ovh)**

Tu devrais voir une magnifique carte s'afficher.

</body></html>