La semplice guida alle mappe Angular Leaflet

Leaflet è uno dei principali framework di mappatura basati su Javascript. È ampiamente utilizzato in tutto il settore per aggiungere mappe interattive a siti web e applicazioni.

Tuttavia, può essere difficile da includere nelle applicazioni Angular.io. Non gioca esattamente bene né con Angular né con Typescript. Dopo aver avuto l’avventura di migrare un sito basato su mappe Leaflet ad Angular 8, mi è stato chiaro che non c’era un buon riferimento per questo compito. Questi post sono il mio tentativo di documentare gli apprendimenti. (AGGIORNAMENTO: anche se questo articolo è stato scritto per Angular 8 – le applicazioni e i metodi funzionano ancora in Angular 11).

Questo sarà un post in più parti:

  • Le basi (questo post),
  • Aggiungere controlli,
  • Funzioni & Controlli dinamici,
  • Controlli personalizzati, e
  • Going PWA – service workers e altro

L’obiettivo di questa serie è che tu sia in grado di creare una mappa Leaflet in un progetto basato su Angular-CLI senza problemi, problemi e punti morti.

Si è scoperto che, anche se aggiungere Leaflet ad Angular.io non è significativamente difficile, è molto “fiddly” poiché Leaflet non è particolarmente Angular (o Typescript) friendly. Leaflet usa una struttura di variabili globali L e .extend metodi che confondono TS. Inoltre elabora un volume di eventi che metterebbe in ginocchio le applicazioni Angular se fossero sottoposte al rilevamento dei cambiamenti.

Per fortuna, c’è un buon punto di partenza in @asymmetrik/ngx-leaflet. Questo fornisce una configurazione di base per le mappe di base. viene anche fornito con un paio di buoni tutorial per la mappatura di base (qui e qui), ma sembrano aver perso interesse prima di arrivare alle cose difficili.

Inizio

Come da documentazione, è necessario installare :

npm install leaflet
npm install @types/leaflet
npm install @asymmetrik/ngx-leaflet

e aggiungere le importazioni al app.module.ts.

A questo punto – puoi praticamente aggiungere una semplice mappa all’app, quindi potresti pensare a cosa fosse tutto questo trambusto – ma ci stiamo arrivando.

Complicazioni CSS

Prima, dobbiamo parlare di CSS. Ngx-leaflet esegue Leaflet al di fuori di Angular stesso – che mi sembra essere il modo migliore per evitare che gli eventi Leaflet causino eventi di cambiamento multipli in Angular.

Tuttavia, probabilmente per questo motivo, Leaflet non si adatta al sistema di incapsulamento CSS di Angular.io e tutti i riferimenti CSS devono essere a livello globale.

Questo di solito significa che si aggiunge il CSS di Leaflet in angular.json come segue

{
...
"styles": ,
...
}

o in styles.css:

@import "./node_modules/leaflet/dist/leaflet.css"

Questo vale anche per i fogli di stile per ogni controllo, che diventa noioso dato che, in Leaflet, ogni controllo ha il proprio CSS. Ho scoperto che la cosa migliore è aggiungere il CSS di Leaflet a angular.json e il CSS dei singoli controlli a styles.css principalmente per una migliore leggibilità.

Nota che, in entrambi i casi, il leaflet.css dovrebbe essere elaborato prima degli altri CSS in styles.css. Altrimenti, il CSS per i controlli non sarà efficace.

Complicanze del compilatore

Questo è anche il punto in cui cominciamo ad imbatterci in una delle prime complicazioni del compilatore.

Le applicazioni basate su leaflet create in questo modo funzionano per ng build e funzionano con "aot": true ma sembrano non funzionare bene per la configurazione di defaultng build --prod.

Questo sembra essere intorno all’ottimizzazione e penso che sia dovuto al tree-shaking. Dopo alcuni esperimenti, ho scoperto che ng build --prod funziona in modo affidabile finché "buildOptimizer": false è in angular.json.

Non rimanere intrappolato in L

La maggior parte dei tutorial e della documentazione ti dirà che devi portare la variabile globale L in typescript usando la seguente importazione :

import * as L from 'leaflet'

Questo è vero se vuoi usare il codice JS esistente direttamente nel TS, ma ho scoperto che finché hai caricato @types/leaflet puoi importare i typedef per nome da 'leaflet' (es.g. import {Map} from 'leaflet' e tutto funziona come previsto. Questo rende il vostro codice TS molto più leggibile e, beh, TS-ish!

Una semplice mappa

Quindi. Creiamo la nostra mappa. Nell’esempio qui sotto, sto creando una mappa OpenStreetMap (dato che è quello su cui lavora la mia applicazione) come componente separato. A questo livello, questo può sembrare un lavoro extra, ma vedremo più avanti, ci permette di impostare un componente mappa con caratteristiche aggiuntive che possono essere riutilizzate in più punti del flusso dell’app.

Questo componente ha come default un livello OSM e una vista globale nelle opzioni – anche se le opzioni sono impostate come @Inputs() così i default possono essere sovrascritti dal componente padre.

Il componente mappa emette anche eventi quando la mappa è pronta in modo che altre parti dell’app possano accedere alla mappa, e dopo un evento di zoom con il nuovo livello di zoom. Potete anche emettere altri eventi come gli eventi di spostamento e di livello – ma questo è ciò di cui la mia app aveva bisogno e penso che dimostri il principio. Useremo gli eventi mappa e zoom nelle prossime sezioni.

La mappa viene aggiunta al dom usando la direttiva ngx-leaflet nel componente HTML.

Infine, il componente viene usato aggiungendo quanto segue al genitore HTML:

<app-osm-map
="options"
(map$)="receiveMap($event)"
(zoom$)="receiveZoom($event)"
></app-osm-map>

Read This Next