4E e 4I SIA: L'uso della libreria Leaflet e il plugin Leaflet Routing Machine


Il "web mapping"



In questa lezione affronteremo la differenza tra Leaflet (la libreria di base) e Leaflet Routing Machine (un plugin specializzato), seguita da un esempio pratico che le usa entrambe.

🌍 Lezione: Mappe Web con Leaflet

Pensa a Leaflet come a una scatola di LEGO. Da sola, ti fornisce tutti i mattoncini base (la mappa, i segnaposto, le forme), ma non ti dà un "castello" o una "macchina" già pronti.

1. Cos'è Leaflet (Il Motore Principale)


Leaflet è una libreria JavaScript leggera e open-source per creare mappe interattive. È il "motore" della mappa.

Come funziona? Il suo funzionamento si basa sul concetto di Layers (Livelli). Immagina di lavorare su fogli di lucido trasparenti impilati:

Il Contenitore (HTML): Per prima cosa, hai bisogno di un "telaio" nel tuo HTML in cui la mappa possa vivere. Questo è un semplice <div> con un ID, ad esempio <div id="map"></div>.

L'Oggetto Mappa (L.map): Quando inizializzi Leaflet (es. L.map('map')), stai creando la "base" su cui appoggerai i fogli lucidi. Gli dici dove centrarsi e con quale zoom iniziale.

Il Tile Layer (L.tileLayer): Questo è il primo e più importante foglio lucido. È lo sfondo della mappa (es. le strade, i palazzi, i fiumi). Leaflet non crea queste immagini; le "scarica" da un servizio esterno (come OpenStreetMap) sotto forma di tante piccole "mattonelle" (tiles) e le assembla.

I Vector Layers (I Dati): Questi sono gli altri fogli lucidi che metti sopra lo sfondo. Possono essere:

L.marker: Un segnaposto (come un pin).

L.polyline: Una linea (perfetta per un percorso!).

L.polygon: Un'area (come il confine di una città).

L.popup: Una finestrella che appare al clic.

In sintesi: Leaflet è la libreria che gestisce l'interazione (zoom, pan), organizza i livelli e disegna segnaposto e forme. Non sa come calcolare un percorso stradale.


2. Cos'è "Leaflet Machine" (Il Plugin Specializzato)


È molto probabile che tu ti riferisca a Leaflet Routing Machine. Questo non fa parte di Leaflet, ma è un plugin molto popolare.

Tornando alla nostra analogia LEGO: se Leaflet è la scatola di mattoncini, Leaflet Routing Machine è il manuale di istruzioni e i pezzi speciali per costruire una "macchina da corsa".

Cosa fa?

Si occupa di una cosa specifica: calcolare e disegnare percorsi stradali.

Come funziona?

Leaflet Routing Machine è un "intermediario". Quando gli dai un punto di partenza e uno di arrivo, fa due cose:

Chiede il percorso: Contatta un servizio di routing esterno (come OSRM, che è il predefinito e gratuito) e gli dice: "Ehi, come arrivo dal Colosseo al Duomo di Milano?".

Disegna il percorso: Il servizio gli risponde con un elenco di coordinate (la rotta) e le istruzioni di guida (es. "Svolta a destra tra 200m"). Leaflet Routing Machine prende queste coordinate e usa la funzione L.polyline di Leaflet per disegnare la linea blu sulla mappa e crea un pannello laterale con le istruzioni.

In sintesi: Leaflet Routing Machine usa Leaflet per disegnare sulla mappa, ma aggiunge la "logica" per interrogare un servizio esterno e ottenere indicazioni stradali.


🛠️ Esempio Pratico: Calcolare un Percorso



Creiamo una singola pagina HTML che carica Leaflet e Leaflet Routing Machine per mostrare il percorso stradale dal Colosseo (Roma) al Duomo di Milano.

Basta creare un file, chiamarlo mappa_percorso.html, incollare il codice qui sotto e aprirlo in un browser (devi essere connesso a Internet).
HTML

<!DOCTYPE html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Esempio Leaflet con Routing</title>

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.css" />

    <style>
        /* Setup della pagina per occupare tutto lo spazio disponibile */
        body { font-family: sans-serif; margin: 0; padding: 0; }
        
        /* Il contenitore della mappa deve avere un'altezza definita */
        #map { height: 100vh; width: 100%; }
    </style>
</head>
<body>

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

    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
    <script src="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.js"></script>

    <script>
        // --- 1. Inizializzazione della Mappa ---
        // Centriamo la visuale sull'Italia (latitudine 42.5, longitudine 12.5) con zoom 6
        const map = L.map('map').setView([42.5, 12.5], 6);

        // --- 2. Aggiunta dello sfondo (Tile Layer) ---
        // Utilizziamo le mappe gratuite di OpenStreetMap
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        }).addTo(map);

        // --- 3. Configurazione del Calcolo Percorso (Routing) ---
        const routingControl = L.Routing.control({
            // Definiamo i punti di passaggio: Roma (Colosseo) e Milano (Duomo)
            waypoints: [
                L.latLng(41.8902, 12.4922), 
                L.latLng(45.4642, 9.1900)
            ],
            routeWhileDragging: true, // Ricalcola il percorso se trascini i punti
            show: true,               // Mostra il pannello laterale con le istruzioni
            language: 'it'            // Imposta le istruzioni stradali in italiano
        }).addTo(map);

        // --- 4. Aggiunta di Marker personalizzati con Popup ---
        // Marker per la partenza a Roma
        L.marker([41.8902, 12.4922]).addTo(map)
            .bindPopup('<b>Partenza:</b> Colosseo, Roma')
            .openPopup();

        // Marker per l'arrivo a Milano
        L.marker([45.4642, 9.1900]).addTo(map)
            .bindPopup('<b>Arrivo:</b> Duomo, Milano');
    </script>

</body>
</html>

🚀 Cosa Vedrai


Aprendo questo file nel browser, vedrai:

Una mappa a schermo intero dell'Italia.

Una linea blu che mostra il percorso stradale esatto da Roma a Milano.

Due segnaposto (che abbiamo aggiunto manualmente per chiarezza).

Un pannello sulla sinistra con le istruzioni di guida dettagliate (es. "Prendi l'autostrada A1", "Esci a...").

Tutto questo è reso possibile dalla collaborazione tra Leaflet (che disegna) e Leaflet Routing Machine (che calcola).

Adesso proviamo a modificare questo esempio, magari per permettere all'utente di cliccare sulla mappa per scegliere la partenza e l'arrivo.

Invece di "imporre" il percorso (Roma -> Milano), lasceremo che sia l'utente a decidere.

Per fare questo, modificheremo la nostra logica JavaScript:

Inizializzeremo il "Routing Control" senza waypoint predefiniti.

Useremo l'evento map.on('click', ...) di Leaflet per "catturare" i clic dell'utente sulla mappa.

Gestiremo una logica semplice:

Il primo clic imposta la Partenza.

Il secondo clic imposta l'Arrivo e fa partire il calcolo del percorso.

Un terzo clic... ricomincia da capo, impostando una nuova partenza.

Useremo il metodo routingControl.setWaypoints([...]) per aggiornare dinamicamente il percorso.

🛠️ Esempio Pratico: Percorso Interattivo con Click

<!DOCTYPE html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Esempio Leaflet con Routing Interattivo</title>
    
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.css" />
    
    <style>
        body { font-family: sans-serif; margin: 0; padding: 0; }
        #map { height: 100vh; width: 100%; }
        
        /* Stile per il pannello delle istruzioni stradali */
        .leaflet-routing-container { background: white; padding: 10px; border-radius: 5px; }
        
        /* Stile per il box di aiuto in alto al centro */
        #helper { 
            position: absolute; top: 10px; left: 50%; transform: translateX(-50%); 
            z-index: 1000; background: white; padding: 10px 20px; 
            border-radius: 5px; font-weight: bold; box-shadow: 0 2px 5px rgba(0,0,0,0.2); 
        }
    </style>
</head>
<body>

    <div id="map"></div>
    <div id="helper">Clicca sulla mappa per impostare la Partenza</div>

    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
    <script src="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.js"></script>

    <script>
        // --- 1. Inizializzazione Mappa e Tile Layer ---
        const map = L.map('map').setView([42.5, 12.5], 6); // Centrata sull'Italia
        
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        }).addTo(map);

        const helperText = document.getElementById('helper');

        // --- 2. Inizializzazione Routing Machine (Senza waypoints iniziali) ---
        const routingControl = L.Routing.control({
            routeWhileDragging: true, // Ricalcola il percorso mentre si trascinano i punti
            show: true,               // Mostra il pannello con le indicazioni
            language: 'it',           // Lingua italiana
            createMarker: function() { return null; } // Gestiamo i marker manualmente
        }).addTo(map);

        // --- 3. Logica dei Click e Variabili di Stato ---
        let startPoint = null;
        let endPoint = null;
        let startMarker = null;
        let endMarker = null;

        map.on('click', function(e) {
            const clickedLatLng = e.latlng;

            if (!startPoint) {
                // --- PRIMO CLICK: Imposta la Partenza ---
                startPoint = clickedLatLng;
                
                if (startMarker) map.removeLayer(startMarker);
                if (endMarker) map.removeLayer(endMarker);

                startMarker = L.marker(startPoint, { draggable: true })
                    .addTo(map)
                    .bindPopup('<b>Partenza</b><br>Trascina per spostare')
                    .openPopup();

                helperText.textContent = "Ora clicca sulla mappa per impostare l'Arrivo";
                routingControl.setWaypoints([]); // Pulisce eventuali percorsi precedenti

            } else if (!endPoint) {
                // --- SECONDO CLICK: Imposta l'Arrivo e Calcola il Percorso ---
                endPoint = clickedLatLng;

                endMarker = L.marker(endPoint, { draggable: true })
                    .addTo(map)
                    .bindPopup('<b>Arrivo</b><br>Trascina per spostare')
                    .openPopup();

                helperText.textContent = "Percorso calcolato! Clicca di nuovo per ricominciare.";
                
                // Attiva il calcolo del percorso
                routingControl.setWaypoints([startPoint, endPoint]);

                // Aggiorna il percorso se l'utente trascina i marker esistenti
                startMarker.on('dragend', updateRoute);
                endMarker.on('dragend', updateRoute);

            } else {
                // --- CLICK SUCCESSIVI: Reset e Nuova Partenza ---
                startPoint = clickedLatLng;
                endPoint = null;

                if (startMarker) map.removeLayer(startMarker);
                if (endMarker) map.removeLayer(endMarker);

                startMarker = L.marker(startPoint, { draggable: true })
                    .addTo(map)
                    .bindPopup('<b>Partenza</b><br>Trascina per spostare')
                    .openPopup();

                helperText.textContent = "Ora clicca sulla mappa per impostare l'Arrivo";
                routingControl.setWaypoints([]);
            }
        });

        // Funzione per aggiornare il percorso dopo il trascinamento (drag)
        function updateRoute() {
            startPoint = startMarker.getLatLng();
            endPoint = endMarker.getLatLng();
            routingControl.setWaypoints([startPoint, endPoint]);
        }
    </script>
</body>
</html>

💡 Come Usarlo


Apri il file mappa_interattiva.html nel tuo browser.

Primo click: Fai clic in un punto qualsiasi dell'Italia (es. Napoli). Apparirà un marker di "Partenza".

Secondo click: Fai clic su un altro punto (es. Venezia). Apparirà un marker di "Arrivo", e vedrai il pannello delle istruzioni e la linea blu del percorso che vengono calcolati automaticamente.

Trascina: Prova a trascinare uno dei due marker. Il percorso si aggiornerà in tempo reale.

Terzo click: Fai clic in un altro punto (es. Bari). La mappa si resetterà, i vecchi marker spariranno e Bari diventerà la tua nuova partenza. Il ciclo ricomincia.



Commenti

Post popolari in questo blog

Esercizi in Excel e fogli di Google

Le domande (e le risposte) all'orale di informatica esame di stato nei corsi: Sistemi Informativi aziendali (ex programmatori), Itis Informatica (ex Abacus), Liceo Tecnologico