Portale mappe personalizzato: una guida dall'inizio alla fine

Published Apr 12, 2022 Updated Jul 03, 2023

Portale cartografico personalizzato: un'immagine guida dall'inizio alla fine

Questo articolo descrive come creare un geoportale con una mappa personalizzata, dati propri, legenda della mappa, ricerca per nome del luogo, vista satellitare di un edificio selezionato e una streetview. Leggendo, imparerete a trasformare i dati in MBTiles, a caricarli sul vostro account MapTiler Cloud e a visualizzarli in un'applicazione sviluppata con MapTiler SDK.

La mappa finale avrà questo aspetto (fate clic su un edificio per vedere la magia):

Scaricare i dati della mappa

La prima cosa da fare è scaricare i dati di alcuni edifici dal Catasto di Spagna. Nell'esempio, utilizzeremo i dati del comune di Sant Feliu de Guixols.

I dati possono essere scaricati dal seguente link: SANT FELIU DE GUIXOLS/A.ES.SDGC.BU.17170.zip

Una volta scaricati i dati, si decomprime il file zip. All'interno del file zip è presente un file chiamato A.ES.SDGC.BU.17170.building.gml con le informazioni dell'edificio; questo file è in formato GML.

Convertire un file GML in MBTiles

Per trasformare il file GML in MBTiles abbiamo diverse opzioni:

  • MapTiler Engine: questo strumento ci permette di trasformare facilmente i nostri dati in MBTiles o GeoPackage. Possiamo anche caricare direttamente i dati trasformati sul nostro account cloud. Per saperne di più, consultare l'articolo Generazione di tegole vettoriali (base).
  • GDAL/ogr2ogr: se sul computer è installato GDAL/ogr2ogr, è possibile trasformare il file GML in MBTiles utilizzando il seguente comando:

ogr2ogr -f MVT guixols.mbtiles A.ES.SDGC.BU.17170.building.gml -dsco MAXZOOM=18 -dsco MINZOOM=9 -mapFieldType DateTime=Stringa
  • MapTiler Engine CLI: crea flussi di lavoro automatizzati con tutta la potenza di MapTiler Engine. Per saperne di più su MapTiler Engine, consultare la pagina di supporto di MapTiler Engine . Per trasformare il file gml in mbtiles utilizzando MapTiler Engine è necessario eseguire il seguente comando:

maptiler-engine -o guixols.mbtiles A.ES.SDGC.BU.17170.building.gml

Come si vede, MapTiler Engine si occupa di calcolare i livelli di zoom ottimali per i nostri dati e di eseguire la trasformazione corrispondente dei tipi di dati. Nell'esempio GDAL, dobbiamo definire i livelli di zoom e indicare le trasformazioni dei tipi di dati alfanumerici in modo che siano validi in MBTiles.

Caricare i geodati su MapTiler Cloud

Abbiamo già detto che è possibile caricare i dati direttamente su MapTiler Cloud da MapTiler Engine; un altro modo per caricare MBTiles è attraverso l'Admin API di MapTiler Cloud .

There are numerous ways to send your requests to the API; whether you are a fan of API clients or go with the good old curl, don’t forget to set the Authorization header in the form of Token {YOUR_TOKEN} so we know it’s you making the requests. To make your life easier, we have also created a CLI utility to upload the tilesets.

Eseguire l'intero processo manualmente tramite curl comporta l'esecuzione di più chiamate API. Ad esempio, la chiamata all'API Admin per avviare l'ingest. L'API Admin restituisce un URL di Google Drive per caricare il file. Quindi chiama l'API di Google Drive per caricare il file e infine chiama l'API di amministrazione per elaborare il file.

Per semplificarvi la vita, abbiamo sviluppato l'utility MapTiler Cloud CLI per caricare i tileset. Questo strumento open-source è sviluppato in Python e consente di automatizzare il processo di caricamento dei dati nel cloud. È possibile accedere al codice nel repository GitHub di MapTiler Cloud CLI.

Per caricare i dati nel cloud utilizzeremo lo strumento MapTiler Cloud CLI.

Per maggiori dettagli su come installare e usare lo strumento CLI, consultare l'articolo Come caricare MBTiles o GeoPackage su MapTiler Cloud usando l'API.

Una volta installato lo strumento CLI, è necessario avviare l'ambiente virtuale in cui è installato lo strumento. Quindi, eseguire il seguente comando per caricare il file MBTiles su MapTiler Cloud:


maptiler-cloud --token=YOUR_CREDENTIAL_TOKEN tiles ingest guixols.mbtiles

Sviluppate un'applicazione con una mappa per visualizzare i vostri dati.

Per visualizzare i dati di MapTiler Cloud , realizzeremo un'applicazione utilizzando la libreria MapTiler SDK.

Creare una mappa

La prima cosa da fare è creare una mappa in cui visualizzare i nostri dati. Per caricare la cartografia di riferimento della nostra mappa chiameremo l'API MapTiler Cloud . MapTiler Cloud ha molti stili di mappa di base pronti all'uso per soddisfare un'ampia gamma di casi d'uso.

Se non avete mai lavorato con MapTiler SDK, vi consigliamo di dare un'occhiata all'esempio Iniziare a integrare le mappe. Guardate tutti questi esempi per scoprire quanto sia più veloce sviluppare con MapTiler SDK!

Creare un file chiamato index.html e copiare il seguente codice:

Aprite l'applicazione in un browser e dovreste vedere una mappa come la seguente immagine

Esempio di creazione di una mappa di base

Creare il controllo di geocodifica

Aggiungiamo un controllo che ci permetta di cercare le località. A tale scopo, utilizzeremo il controllo Geocoding.

Per caricare il componente geocoder, aggiungere le righe evidenziate nell'intestazione del file index.html.

Subito dopo la creazione della mappa scrivere:


const gc = new maptilersdkMaptilerGeocoder.GeocodingControl({});
map.addControl(gc, 'top-left');

A questo punto si dovrebbe vedere il controllo di ricerca nell'angolo superiore sinistro della mappa.

Visualizzare i dati delle mappe

Per aggiungere i nostri dati alla mappa, dobbiamo prima dichiarare una nuova origine dati e poi aggiungere un nuovo livello con le informazioni di questa origine dati.

L'inizializzazione della mappa nella pagina indica al browser di richiedere lo stile. Questa operazione può richiedere del tempo, a seconda della velocità con cui il server risponde alla richiesta di stile e del tempo necessario al browser per eseguire il rendering della mappa (in genere millisecondi). Queste risorse sono remote, quindi vengono eseguite in modo asincrono; è importante assicurarsi che lo stile sia caricato prima di eseguire altro codice.

L'oggetto mappa può informare il browser su alcuni eventi che si verificano quando lo stato della mappa cambia. Uno di questi eventi è l'evento load, che viene attivato quando lo stile è stato caricato nella mappa.

Aggiungere un'origine dati alla mappa

Con il metodo map.on('load', callback function) possiamo assicurarci che il resto del codice di callback non venga eseguito finché non si verifica l'evento.


map.addControl(gc, 'top-left');

map.on('load', () => {
  // the rest of the code will go in here
});

Pertanto, dobbiamo chiamare la funzione addSource all'interno di una funzione map.on('load'), in modo che la nuova sorgente non venga caricata prima del rendering della mappa.


map.on('load', () => {
  // the rest of the code will go in here
  map.addSource("building_source", {
  "type": "vector",
  "url": `https://api.maptiler.com/tiles/YOUR_TILESET_ID/tiles.json`
  });
});

Nello snippet di codice qui sopra si utilizza l'API di MapTiler Cloud per fare riferimento al TileJSON generato durante il caricamento dei dati su MapTiler Cloud.

Aggiungere un livello alla mappa

Una volta definita l'origine dei dati, possiamo aggiungere il livello alla mappa. A tale scopo, utilizzeremo la funzione addLayer. Subito dopo addSource, scrivere le righe successive:


map.on('load', () => {
  // the rest of the code will go in here
  map.addSource("building_source", {
  "type": "vector",
  "url": `https://api.maptiler.com/tiles/YOUR_TILESET_ID/tiles.json?key=${apiKey}`
  });

  map.addLayer({
    "id": "building_pol",
    "type": "fill",
    "source": "building_source",
    "source-layer": "Building",
    "layout": {
    "visibility": "visible"
    },
    "paint": {
    "fill-color": "#3A1888",
    "fill-opacity": [
      "literal",
      0.6
    ]
    },
    "filter": ["all",
    ["==", "$type", "Polygon"]
    ],
  }, "airport");
});

Nel frammento di codice qui sopra, aggiungiamo il livello edifici subito prima del livello etichette aeroporto. In questo modo i poligoni degli edifici appaiono sulla mappa sotto le etichette e non nascondono i testi dei nomi delle strade, dei quartieri, ecc.

Ricaricare l'applicazione e digitare Sant Feliu de Guíxols nel motore di ricerca e selezionare la prima voce nell'elenco dei risultati. L'applicazione ingrandisce il comune di Sant Feliu de Guíxols e visualizza il layer degli edifici.

Livello edifici della mappa

Mostra le informazioni sull'edificio quando si fa clic

Abbiamo già visto come aggiungere e visualizzare i propri dati su una mappa. La prossima cosa da fare è mostrare le informazioni relative a un edificio quando si fa clic su di esso. A tale scopo, utilizzeremo l'evento click della mappa.

Dopo aver aggiunto il livello alla mappa, scriveremo il seguente codice:

In questo frammento di codice, definiamo una funzione (createPopupContent) per creare il contenuto da visualizzare e registriamo l'evento click della mappa per il nostro livello edificio.

Per migliorare l'esperienza dell'utente, faremo in modo che il puntatore del cursore cambi quando si passa sopra un edificio; in questo modo l'utente saprà che può interagire con gli edifici.

Scrivete quanto segue dopo il punto in cui aggiungiamo l'evento click:


map.on('click', 'building_pol', function (e) {
  const content = createPopupContent(e.features[0]);
  new maptilersdk.Popup()
  .setLngLat(e.lngLat)
  .setHTML(content)
  .addTo(map);
});

map.on('mouseenter', 'building_pol', () => {
  map.getCanvas().style.cursor = 'pointer';
});

map.on('mouseleave', 'building_pol', () => {
  map.getCanvas().style.cursor = '';
});

Creare una mappa coropleta degli edifici

Per creare la mappa coropleta degli edifici, modificheremo lo stile del livello edifici e utilizzeremo i dati alfanumerici associati agli edifici per classificarli e dipingerli in base al valore di un determinato campo. In questo caso, utilizzeremo il campo currentUse per effettuare la classificazione.

È inoltre possibile utilizzare le applicazioni del sito MapTiler Cloud per creare una mappa con i propri dati.

Personalizzare la mappa

Se osserviamo i dati alfanumerici del livello Edifici, vedremo che per il campo Uso corrente ci sono 6 possibili valori. Creeremo un array con questi valori e assegneremo loro un testo e un colore.

Subito dopo aver dichiarato la variabile con la chiave API, scriviamo quanto segue:


maptilersdk.config.apiKey = 'slEr7lXnTotdWgNA0oLf';

const categories_field = "currentUse";
const categories = [
  {id: "1_residential", text: "Residential", color: "#FFD65F"},
  {id: "2_agriculture", text: "Agriculture", color: "#35C186"},
  {id: "3_industrial", text: "Industrial", color: "#805CC2"},
  {id: "4_1_office", text: "Office", color: "#FF8F65"},
  {id: "4_2_retail", text: "Retail", color: "#3388F1"},
  {id: "4_3_publicServices", text: "Public Services", color: "#E25041"},
];

Con questo array di categorie e colori, creeremo la funzione createFillColor per generare un'espressione che determini il colore con cui dipingere gli edifici.


const createFillColor = (categories, categories_field) => {
  const colors = categories.reduce((agg, item) => {
    agg.push(item.id);
    agg.push(item.color);
    return agg;
  }, []);
  return [
    "match",
    [
      "get",
      categories_field
    ],
    ...colors,
    "#ccc"
  ]
}

Modificare la proprietà fill-color del livello edifici in modo che invece di avere un colore definito ("#3A1888") utilizzi la funzione createFillColor per determinare il valore.


"paint": {
  "fill-color": createFillColor(categories, categories_field),
  "fill-opacity": [
    "literal",
    0.6
  ]
},

Quando si ricarica l'applicazione, si vedrà che gli edifici sono dipinti con colori diversi a seconda del loro utilizzo.

Mappa coropleta degli edifici

Creare una legenda interattiva della mappa

Creeremo una legenda interattiva sulla mappa, per mostrare i colori della classificazione, e cambieremo anche la visualizzazione di quali categorie sono attive o inattive.

La prima cosa da fare è creare una funzione per creare il filtro del livello. Utilizzeremo la proprietà filter del livello per determinare quali categorie vogliamo mostrare sulla mappa. Questo ci permetterà di modificare la visualizzazione delle categorie attive e inattive.


const createFilter = (categories, categories_field) => {
  const filters = categories.reduce((agg, item) => {
    agg.push(["in", categories_field, item.id]);
    return agg;
  }, []);
  return [
    "all",
    ["==", "$type", "Polygon"],
    ["any",
      ...filters
    ]
  ]
}

Modificare la proprietà del filtro del livello Edifici


"paint": {
    "fill-color": createFillColor(categories, categories_field),
    "fill-opacity": [
      "literal",
      0.6
    ]
  },
  "filter": createFilter(categories, categories_field),
}, "airport");

Creare il controllo della legenda

Prima di creare il controllo della legenda, creeremo un paio di funzioni che ci permetteranno di alternare la visibilità delle categorie. Accanto alla creazione della funzione createFilter scriviamo queste righe:


const removeAtIndex = (arr, index) => {
  const copy = [...arr];
  copy.splice(index, 1);
  return copy;
};

const toggle = (arr, item, getValue = item => item) => {
  const index = arr.findIndex(i => getValue(i) === getValue(item));
  if (index === -1) return [...arr, item];
  return removeAtIndex(arr, index);
}

Appena sotto il punto in cui abbiamo aggiunto il controllo di ricerca, copiate quanto segue:


map.addControl(gc, 'top-left');

class legendControl {
  constructor (categories, field) {
    this.categories = categories;
    this.field = field;
  }

  onAdd(map) {
    this._map = map;
    this._container = document.createElement('div');
    this._container.className = 'maplibregl-ctrl';
    const _fragment = document.createDocumentFragment();
    const _nav = document.createElement('nav');
    _nav.className = 'maplibregl-ctrl filter-group';
    _nav.id = 'filter-group';
    _fragment.appendChild(_nav);
    this.categories.forEach(element => {
      const _input = document.createElement('input');
      _input.type = "checkbox";
      _input.id = element.id;
      _input.className = "input-layers";
      _input.checked = true;
      const this_ = this;
      _input.addEventListener('change', function (e) {
        this_.updateLegend(e.target.id);
      });
      const _label = document.createElement('label');
      _label.htmlFor = element.id;
      const _text = document.createTextNode(element.text);
      const _legend = document.createElement('i');
      _legend.style.backgroundColor = element.color;
      _label.appendChild(_text);
      _label.appendChild(_legend);
      _nav.appendChild(_input);
      _nav.appendChild(_label);
    });
    this._container.appendChild(_fragment);
    return this._container;
  }

  onRemove() {
    this._container.parentNode.removeChild(this._container);
    this._map = undefined;
  }

  updateLegend(id) {
    let filter = this._map.getFilter('building_pol');
    if (filter){
      const [any, ...filters] = filter[2];
      filter[2] = [any, ...toggle(filters, ["in", this.field, id], (item) => item[2])];
      this._map.setFilter('building_pol', filter);
    }
  }
}
map.addControl(new legendControl(categories, categories_field), 'bottom-left');

Ora si procederà allo stile del controllo della legenda. Nella sezione stile della pagina scriviamo:


#map {position: absolute; top: 0; bottom: 0; width: 100%;}

.filter-group {
  font: 12px/20px 'Ubuntu', sans-serif;
  font-weight: 400;
  position: absolute;
  bottom: 25px;
  z-index: 1;
  border-radius: 4px;
  width: 150px;
  color: rgba(51, 51, 89, 1);
  box-shadow: 0px 15px 68px rgba(51, 51, 89, 0.15);
  background: rgba(255, 255, 255, 0.9);
}
.filter-group input[type='checkbox']:first-child + label {
  border-radius: 6px 6px 0 0;
}
.filter-group label:last-child {
  border-radius: 0 0 6px 6px;
  border: none;
}
.filter-group input[type='checkbox'] {
  display: none;
}
.filter-group input[type='checkbox'] + label {
  display: block;
  cursor: pointer;
  padding: 10px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.25);
  text-transform: capitalize;
}
.filter-group input[type='checkbox'] + label i {
  width: 18px;
  height: 18px;
  float: right;
  margin-right: 0 8px;
  opacity: 0.7;
}
.filter-group input[type='checkbox'] + label:hover {
  background-color: rgba(49, 112, 254, 0.05);
}
.filter-group input[type='checkbox'] + label:before {
  content: '';
  margin-right: 15px;
}
.filter-group input[type='checkbox']:checked + label:before {
  content: '✔';
  margin-right: 5px;
}

Ricaricate la pagina, il controllo della legenda dovrebbe trovarsi nell'angolo in basso a sinistra della mappa. Se facciamo clic su alcune categorie della legenda, vedremo che la visibilità degli edifici di quella categoria cambia.

Creare una legenda interattiva della mappa

Mostra un'immagine satellitare dell'edificio selezionato

Per creare l'immagine della vista aerea dell'edificio utilizzeremo l'API MapTiler Cloud Static Maps.

L'API Static Maps non è disponibile sul piano gratuito. Noleggiate uno dei nostri piani per poter usufruire di tutte le funzionalità disponibili in MapTiler. Cloud

Modificheremo le informazioni mostrate quando si seleziona un edificio per mostrare l'immagine della vista satellitare dello stesso.

Per creare l'immagine satellitare dell'edificio, dobbiamo conoscere il rettangolo di selezione dell'edificio. Utilizzeremo la libreria Turf.js che ci permette di ottenere il rettangolo di selezione di una geometria.

All'inizio della pagina copiare la riga seguente per aggiungere la libreria Turf:

Aggiungere la seguente riga all'inizio della funzione createPopupContent:

Nel creaContenutoPopup chiama la funzione mappe statiche per creare l'url dell'immagine della vista satellitare e aggiungere l'immagine al contenuto del popup.

Inoltre, modificheremo le informazioni mostrate nel campo Uso per mostrare il testo della categoria invece del codice identificativo. A tale scopo, creeremo una funzione che restituisca il testo della categoria selezionata.

Subito dopo la funzione toggle copiare le seguenti righe:


const getUse = (use, categories) => {
  return categories.reduce((agg, item) => {
  return item.id === use ? item.text : agg;
  }, "Unknown");
}

Chiameremo questa funzione per visualizzare le informazioni nel campo Use.

Aggiornare l'applicazione e fare clic su un edificio. Verranno visualizzate le informazioni sull'edificio e un'immagine della sua vista aerea.

Creare una vista satellitare dell'edificio

Consultate il repository di Github per ottenere il codice completo del visualizzatore.

Sintesi

In questo articolo abbiamo visto come creare una mappa interattiva con i nostri dati utilizzando l'API di MapTiler Cloud e l'SDK di MapTiler.

Abbiamo fatto:

  • Utilizzare l'Admin API per caricare i dati
  • Caricare una mappa di base grazie all'API di Maps
  • Usare il componente Geocoding API per cercare i luoghi
  • Visualizzare i dati come tessere vettoriali utilizzando l'API Tiles
  • Creare una mappa coropleta
  • Creare una legenda interattiva
  • Creare un'immagine della vista satellitare di un edificio utilizzando l'API Static Maps

Ulteriori informazioni su MapTiler Cloud API

Admin API

Come caricare MBTiles o GeoPackage in MapTiler Cloud tramite API

Come creare mappe con MapTiler Cloud API - Casi d'uso ed esempi

Wladimir Szczerban

Senior Developer Advocate
Published on Apr 12, 2022

Scopri MapTiler in francese!

Visita il sito maptiler.fr

Přečtěte si více v češtině

Více na maptiler.cz

Leggi di più in spagnolo

Visita maptiler.es

Di più in olandese

Vai a maptiler.nl

日本語で詳細をみる

maptiler.jp へ

Altre informazioni sono disponibili

su MapTiler.de

ديزملا فشتكإ

maptiler.ae ىلإ لقتنا

Esplora MapTiler in Svizzera

Visita MapTiler.ch