En enkel guide till Angular Leaflet Maps

Leaflet är ett av de viktigaste Javascript-baserade ramverken för kartor. Det används ofta i branschen för att lägga till interaktiva kartor på webbplatser och i program.

Det kan dock vara svårt att inkludera det i Angular.io-appar. Det spelar inte riktigt bra ihop med vare sig Angular eller Typescript. Efter att jag hade äventyret att migrera en Leaflet-kartbaserad webbplats till Angular 8 stod det klart för mig att det inte fanns någon riktigt bra referens för den här uppgiften. Dessa inlägg är mitt försök att dokumentera lärdomarna. (UPDATE: Även om den här artikeln skrevs för Angular 8 – fungerar tillämpningarna och metoderna fortfarande i Angular 11).

Detta kommer att bli ett inlägg i flera delar :

  • Grundläggande (det här inlägget),
  • Lägga till kontroller,
  • Funktioner & Dynamiska kontroller,
  • Anpassade kontroller, och
  • Gå till PWA – service workers med mera

Målet med den här serien är att du ska kunna skapa en Leaflet-mapp i ett Angular-CLI-baserat projekt utan krångel, krångel och återvändsgränder.

Det visar sig att även om det inte är nämnvärt svårt att lägga till Leaflet i Angular.io är det mycket ”krångligt” eftersom Leaflet inte är särskilt Angular (eller Typescript) vänligt. Leaflet använder en global L variabelstruktur och .extend metoder som förvirrar TS. Den bearbetar också en mängd händelser som skulle få Angular-applikationer att gå på knä om de skulle genomgå ändringsdetektering.

Turligtvis finns det en bra utgångspunkt i @asymmetrik/ngx-leaflet. Det ger en ganska mycket boilerplate-installation för grundläggande kartor. det kommer också med ett par bra handledningar till grundläggande kartor (här och här) men de verkar ha tappat intresset innan de kom till de svåra sakerna.

Geting Started

Enligt dokumentationen måste du installera :

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

och lägga till importerna till app.module.ts.

I det här läget – du kan i stort sett lägga till en enkel karta i appen, så du kanske tänker vad det hela handlade om – men vi kommer till det.

CSS-komplikationer

Först måste vi prata om CSS. Ngx-leaflet kör Leaflet utanför själva Angular – vilket jag förstår är det bästa sättet att undvika att Leaflet-händelserna orsakar flera ändringshändelser i Angular.

Men förmodligen på grund av detta passar Leaflet inte in i Angular.ios CSS-kapslingssystem och alla CSS-referenser måste vara på global nivå.

Detta innebär vanligtvis att du lägger till Leaflets CSS i angular.json på följande sätt

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

eller i styles.css:

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

Detta gäller även för formatmallarna för varje kontroll, vilket blir tröttsamt eftersom varje kontroll i Leaflet har sin egen CSS. Jag kom fram till att det bästa var att lägga till Leaflets CSS till angular.json och den enskilda kontrollens CSS till styles.css främst för bättre läsbarhet.

Bemärk att i båda fallen ska leaflet.css bearbetas före den övriga CSS:en i styles.css. Annars kommer CSS:en för kontrollerna inte att vara effektiv.

Compiler Complications

Det är också här vi börjar stöta på en av de första kompilatorkomplikationerna.

Leaflet-baserade appar som skapats på det här sättet fungerar för ng build och fungerar med "aot": true men tycks misslyckas kraftigt med standardkonfigurationen ng build --prod.

Det här tycks handla om optimering och jag tror att det kanske beror på tree-shaking. Efter lite experimenterande fann jag att ng build --prod fungerar tillförlitligt så länge "buildOptimizer": false finns i angular.json.

Få inte fast i L

De flesta handledningar och dokumentationen kommer att tala om för dig att du måste föra in den globala L-variabeln i typescript med hjälp av följande import :

import * as L from 'leaflet'

Detta stämmer om du vill använda befintlig JS-kod direkt i TS, men jag upptäckte att så länge du har laddat @types/leaflet så kan du importera typdefinitioner med namn från 'leaflet' (e.t.ex. import {Map} from 'leaflet' och allt fungerar som förväntat. Detta gör din TS-kod mycket mer läsbar och, ja, TS-ish!

En enkel karta

Så. Låt oss skapa vår karta. I exemplet nedan skapar jag en OpenStreetMap-karta (eftersom det är den som min app arbetar på) som en separat komponent. På den här nivån kan detta tyckas vara extra arbete, men vi ska se senare att det gör det möjligt för oss att skapa en kartkomponent med ytterligare funktioner som kan återanvändas på flera ställen i appflödet.

Denna komponent har som standard ett OSM-skikt och en global vy i alternativen – även om alternativen är inställda som @Inputs() så kan standardvärdena åsidosättas av den överordnade komponenten.

Kartkomponenten sänder också ut händelser när kartan är klar så att andra delar av appen kan få tillgång till kartan, och efter en zoomhändelse med den nya zoomnivån. Du kan också emittera andra händelser, t.ex. flytt- och lagerhändelser – men det här är vad min app behövde och jag tycker att det demonstrerar principen. Vi kommer att använda händelserna karta och zoom i de kommande avsnitten.

Kartan läggs till i domen med hjälp av ngx-leaflet-direktivet i komponentens HTML.

Slutligt används komponenten genom att lägga till följande i den överordnade HTML:

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

Läs det här nästa

.