Creaimo un server di mappe geospaziali con Node.js e Mapbox

Creaimo un server di mappe geospaziali con Node.js e Mapbox

In questo articolo vedremo come creare un server di mappe in grado di visualizzare dati geospaziali memorizzati in file in formato GeoJSON. Per svilu

Sviluppare con il Google Web Toolkit (GWT)
Google Maps Api: come ottenere la API key per poter utilizzare le mappe sul nostro sito web
Ext JS: un framework JavaScript multiuso

In questo articolo vedremo come creare un server di mappe in grado di visualizzare dati geospaziali memorizzati in file in formato GeoJSON. Per sviluppare questa applicazione utilizzeremo Node.js ed Express per la parte backend e Mapbox per il frontend. Il linguaggio di programmazione utilizzato è dunque Javascript sia per il lato server che per quello client.

GeoJSON è un formato per la codifica di collezioni di dati geometrici spaziali in formato JSON (JavaScript Object Notation). Supporta i seguenti tipi geometrici:

  • Point
  • LineString
  • Polygon
  • MultiPoint
  • MultiLineString
  • MultiPolygon

Questi oggetti geometrici insieme ad altre proprietà sono incapsulati in strutture definite Feature. Una lista di Feature vengono a loro volta contenute in una FeatureCollection. Esiste un’ulteriore formato denominato TopoJSON il quale è una estensione di GeoJSON che codifica le geometrie in topologie spaziali. 

Per lo sviluppo di questa applicazione client-server di mappe geospaziali, è stato utilizzato Visual Studio Code (disponibile per tutte le piattaforme Windows, Linux e MacOS) che è possibile scaricare gratuitamente dal sito Microsoft:

https://code.visualstudio.com/

Il codice Javascript che andremo a descrivere è disponibile su GitHub:

https://github.com/angeloonline/GeoJsonMapServer

Il server di mappe geospaziali che andremo a costruire possiamo vederla come una versione light di MapServer. MapServer è un ambiente di sviluppo e fruizione Open Source finalizzato alla rappresentazione di dati geospaziali. MapServer supporta un consistente numero di formati geospaziali: oltre geojson supporta ad esempio dati vettoriali come shapefile e raster come geotiff.  Per la parte backend della nostra applicazione web, come detto in precedenza, abbiamo utilizzato Node.js, che è un runtime JavaScript Open source multipiattaforma orientato agli eventi per l’esecuzione di codice JavaScript, costruita sul motore JavaScript V8 di Google Chrome. Grazie a Node.js è possibile utilizzare Javascript anche per la parte server, oltre che utilizzarlo per la parte client fruibile da browser, così facendo è possibile utilizzare lo stesso linguaggio per entrambi i layer di un software.

E’ possibile scaricare il runtime Node.js (consiglio una versione LTS, ad esempio la 12) da questa url:

https://nodejs.org/it/download/

Installando Node.js potremo utilizzare anche il suo gestore dei pacchetti npm, che consiste in un client da linea di comando, chiamato anch’esso npm, e un database online di pacchetti pubblici e privati, chiamato npm registry.

Tramite npm possiamo creare il nostro programma Node.js con il comando:

npm init

che costruirà lo skeleton della nostra applicazione ed in particolare crea il file package.json che include tra l’altro, l’entry point della nostra applicazione e i pacchetti da cui dipende. Ad esempio la nostra applicazione dipende dai seguenti pacchetti:

  • express
  • ejs
  • compression
  • dotenv
  • moment
  • nodemon

L’applicazione ha inoltre anche delle dipendenze di “sviluppo” (sezione devDependencies del file package.json):

  • babel
  • webpack

Per quanto riguarda Express (chiamato anche Express.js) questi è un noto framework web Javascript flessibile e leggero che fornisce una serie di funzioni avanzate per le applicazioni web scritte con Node.js. Mette inoltre a disposizione una miriade di metodi di utilità HTTP e middleware, per la creazione veloce di API affidabili.

Utilizzando Express possiamo sviluppare l’entry point della nostra applicazione che chiameremo index.js:

import express from 'express'
import compress from 'compression'
import load from 'dotenv'
import path from 'path'
import router from './routers/routes.js'

// configure dotenv to retrieve environment variables
load.config()
// use express as framework
var app = express()
// set the view engine to ejs
app.set('view engine', 'ejs')
// set views path
app.set('views', path.join(__dirname, '/views'))
// define main route
app.use('/mapserver', router)
// define static resources
app.use('/mapserver/public/css/', express.static(__dirname + '/public/css'))
app.use('/mapserver/public/img/', express.static(__dirname + '/public/img'))
app.use('/mapserver/public/js/', express.static(__dirname + '/public/js'))

console.log('Configured port in .env file is %s', process.env.MAP_SERVER_PORT)
const port = process.env.MAP_SERVER_PORT || 3010
console.log('port selected is %s', port)
// compress files as gzip or deflate
app.use(compress())

app.listen(port, function() {
    console.log('Map server listening on port %s!', port)
})

Nella prima sezione importiamo i moduli che ci serviranno, poi configuriamo dotenv per poter accedere a delle variabili di ambiente definite in un file .env, che riportiamo:

MAP_SERVER_PORT=3010

Questa variabile ci serve per definire la porta di ascolta del nostro server di Mappe. Successivamente istanziamo Express e definiamo come template engine per le nostre pagine HTML, l’engine EJS (Embedded JavaScript). Ejs è un linguaggio di templating che ci permette di definire delle pagine HTML con all’interno dei placeholder del tipo:

<%= nome_placeholder %>

che verranno poi popolati lato javascript.

Definiamo inoltre un path principale della nostra applicazione ed un router che gestirà invece la navigazione tra e varie pagine:

// define main route
app.use('/mapserver', router)

Successivamente definiamo delle risorse statiche che verranno utilizzate lato client:

// define static resources
app.use('/mapserver/public/css/', express.static(__dirname + '/public/css'))
app.use('/mapserver/public/img/', express.static(__dirname + '/public/img'))
app.use('/mapserver/public/js/', express.static(__dirname + '/public/js'))

Infine abilitiamo la compressione dei file (utilizzando il middleware compression, che utilizza gzip o deflate) e lanciamo il nostro server in ascolto sulla porta precedentemente definita:

// compress files as gzip or deflate
app.use(compress())

app.listen(port, function() {
    console.log('Map server listening on port %s!', port)
})

La parte client dell’applicazione composta da un file template html (viewMap.ejs) ed un file in vanilla Javascript (viewMap.js) si occupa di renderizzare la mappa georeferenziata sovrapponendo dei layer geospaziali che ricaviamo da dei file GeoJSON. Come servizio di mappe utilizziamo Mapbox il quale ci consente di poter utilizzare le mappe se non sforiamo dei limiti di utilizzo (attualmente posti a 50.000 richieste al giorno). Per poter utilizzare Mapbox dobbiamo ottenere un access token iscrivendoci al loro servizio:

https://account.mapbox.com/

Ad esempio per il mio token abbiamo le seguenti statistiche di utilizzo:

Sotto la voce sessions abbiamo il riepilogo di quante volte il servizio di mappe è stato invocato

Possiamo creare una mappa con il seguente codice:

var map = new mapboxgl.Map({
        container: 'map',
        style: 'mapbox://styles/mapbox/streets-v11',
        zoom: 5,
        center: [12.496365, 41.902782],
    })

dove possiamo passare il tipo di mappa che vogliamo visualizzare (nell’esempio di tipo streets), il livello di zoom e con quali coordinate centrarla. La mappa verrà visualizzata nel nostro div con id=map:

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

Caricata la mappa, aggiungiamo una sorgente di dati di tipo geojson:

map.addSource('geojson-map', {
            type: 'geojson',
            data: './public/mapfile/' + varMap,
            generateId: true,
        })

e successivamente aggiungiamo un layer alla mappa prelevandolo da questa sorgente GeoJSON:

map.addLayer(
            {
                id: 'places',
                type: 'fill',
                source: 'geojson-map',
                layout: { visibility: 'visible' },
                paint: {
                    'fill-color': '#f08',
                    'fill-opacity': [
                        'case',
                        ['boolean', ['feature-state', 'hover'], false],
                        1,
                        0.5,
                    ],
                },
            },
            firstSymbolId
        )

questo layer è di tipo fill (riempe con un colore dato da fill-color le feature presenti nel file geojson) ed ha un effetto di hovering (la proprietà opacity passa ad 1) al passaggio del mouse. Al click del mouse su una feature viene visualizzata una tabella contenenti le informazioni presenti nel file geojson.

Alla mappa possono anche essere applicati degli stili, cioè il tipo di visualizzazione che si vuole dare: quali dati disegnare, con quale ordine e altre informazioni. Neell’applicazione è possibile scegliere tr ai seguenti stili predefiniti di Mapbox:

  • streets
  • light
  • dark
  • outdoors
  • satellite

E’ possibile cambiare lo stile di una mappa con la funzione setStyle, che nell’applicazione si trova nella funzione switchStyle:

function switchStyle(style) {
        var styleId = style.target.id
        map.setStyle('mapbox://styles/mapbox/' + styleId)
}

L’applicazione permette di modificare l’opacità del layer GeoJSON utilizzando uno slider (da 0 a 100%) mentre con un pulsante può essere reso visibile o meno il medesimo layer.

Il server di mappe geospaziali ha il seguente aspetto finale:

Una mappa di esempio dell’Italia con un layer geojson che mostra le varie province

Nella sezione Home dell’applicazione è possibile scegliere tra diversi file geojson precaricati il layer da applicare alla mappa. E’ possibile aggiungere altri layer geojson copiando altri file nella cartella src/geojson_files.

Una demo dell’applicazione di mappe geospaziali è disponibile al seguente indirizzo:

https://www.devnode.it/mapserver/

Il server è una macchina virtuale linux (Ubuntu) deployata su Azure, la piattaforma Cloud di Microsoft.

A conclusione di questo post, vi lasciamo alcuni link, disponibili anche nella sezione Resources dell’applicazione, da cui poter scaricare ulteriori file GeoJSON:

  • Geojson-italy: progetto ospitato su GitHub di risorse GeoJSON riguardanti l’Italia;
  • world.geo.json: ulteriore progetto ospitato su GitHub di risorse GeoJSON stavolta riguardanti il mondo intero;
  • geojson.io: un servizio online che permette di creare i propri dati vettoriali in formato GeoJSON.

COMMENTS

WORDPRESS: 0