Integrera kartor i din Angular-applikation med Leaflet

Integrera Leaflet-kartan i Angular-versionen 8
Jim Armstrong
Jim Armstrong

Follow

Oct 17, 2019 – 6 min read

Denna artikel riktar sig till nybörjarutvecklare inom Angular som vill integrera Leaflet i sina applikationer. Integrationen av beroenden från tredje part i Angular kan vara allt från trivial till problematisk. Medan Leaflet tenderar mer mot den triviala sidan, kan kartor som flytande anpassar sig till webbläsarens storlek presentera vissa installationsproblem i förhållande till Angular-livscykeln.

För att påbörja dekonstruktionen bör du rikta din vänliga, närliggande webbläsare till följande Github.

Nu kan du följa med eller gaffla projektet och använda det som en bas för dina egna tillämpningar.

Bakgrund

Denna handledning förutsätter en liten mängd förkunskaper om Leaflet, men inte mer än vad som uttrycks i Leaflet Quickstart Guide.

ArcGis används för kakel i applikationen som behandlas i den här artikeln (esri-leaflet-paketet installeras från npm).

Angular Setup

Varje liten sak behöver göras efter den allestädes närvarande npm-installationen. Nödvändiga Leaflet-stilar görs tillgängliga via angular.json-filen,

"styles": ,

Jag har haft blandade resultat med @types/leaflet, så det här programmet utnyttjar inte typningar för enkelhetens skull. Leaflet- och ESRI-kakor importeras enligt nedan,

import * as esri from 'esri-leaflet';
import * as L from 'leaflet';

En Leaflet Map, till exempel, är tillfälligt typad som vilken som helst; du är välkommen att fastställa typningar som en övning efter att du har dekonstruerat handledningen.

Koordinater för en kartas centrum är viktiga för kartans initialisering. Många demos kodar denna information hårt. Som ett alternativ illustrerar den här handledningen hur man injicerar koordinater för kartans centrum med hjälp av Angular Injection Tokens.

En koordinat är en tvådimensionell punkt på en karta som representeras av latitud och longitud. En InjectionToken för en koordinat kan skapas enligt illustrationen i filen /src/app/tokens.ts,

import { InjectionToken } from '@angular/core';
export const INIT_COORDS = new InjectionToken<{lat: number, long: number}>('INIT_COORDS');

INIT_COORDS används i /src/app/app.module.ts-filen för att utföra själva tillhandahållandet (eller definitionen) av (lat/long),

providers: ,

Detta flyttar definitionen av kartans centrum till den högsta nivån i Angular-applikationen (där den är lätt att se och nästan självdokumenterande).

För att injicera den här koordinaten i applikationen importerar du INIT_COORDS från tokens-filen och injicerar den från en klasskonstruktör. Detta illustreras i filen /src/app/map.component.ts (den primära kartkomponenten i den här handledningen),

constructor( @Inject(INIT_COORDS) protected _initCoords: {lat: number, long: number} )

Kartkomponent

Den applikation som behandlas i den här artikeln visar en karta med fast höjd med en bredd som sträcker sig över hela webbläsarfönstret. Kartan ritas om när fönstret ändras i storlek. Vissa markörer återges också ovanpå kartplattorna.

Kartan integreras i programmet genom den huvudsakliga app-komponentens mall, som visas nedan

/src/app/app.component.html

<app-map ="markers"></app-map>

och kartkomponentens källkod finns i /src/app/maps/map.component.ts .

Kartan återges i en behållare (DIV) som för närvarande finns i kartkomponentens mall,

/src/app/maps/map.component.html

<div>
<div>
<div #primaryMap ="currentHeight" ="currentWidth"></div>
<map-control class="map-control"></map-control>
<div class="mouse-coords">
<span></span>
<span ="mcText"></span>
</div>
</div>
</div>

Om bredden och höjden på den ingående DIV:n är bestämda kan kartplattor återges vid en tidig tidpunkt i komponentens livscykel. Två tillvägagångssätt är möjliga för att överföra variabel bredd och höjd, outside-in och inside-out. Metoden outside-in definierar Angular Inputs för bredd och höjd. Den överordnade komponenten ansvarar för att kommunicera bredd och höjd till kartkomponenten. Med inside-out-metoden definieras bredd och höjd internt i kartkomponenten och den informationen ”överförs” till dess mall. De flesta tillämpningar använder sig av den utvändiga metoden. I den här handledningen används inside-out-metoden i illustrationssyfte. Ändra koden för att ändra överlämnandet av bredd och höjd som en övning.

Variabla bredder och höjder introducerar några subtila problem i förhållande till kartåtergivning. Det är frestande att utföra allt som rör Leaflet-installationen i on-init-hanteraren, och detta fungerar vanligtvis med fast bredd och höjd. Eftersom kartans bredd varierar med webbläsarens storlek i den här handledningen är det bättre att separera initialiseringsprocessen för kartan mellan on-init- och after-view-init-livscykelhanterarna. Detta illustreras i följande kodsegment från /src/app/maps/map.component.ts .

Först avlastas identifieringen av en innehållande DIV för kartinitialisering till en ViewChild,

@ViewChild('primaryMap', {static: true}) protected mapDivRef: ElementRef;
protected mapDiv: HTMLDivElement;

Det mesta av kartinställningen utförs i ngOnInit,

public ngOnInit(): void
{
// Reference to DIV containing map is used in Leaflet initialization
this.mapDiv = this.mapDivRef.nativeElement;
this.__initializeMap();
this.__renderMap();
this.__showMarkers();
}

Invalidering av kartstorleken skjuts upp till ngAfterViewInit, när hela den bredd och höjd som krävs för att kartbrickorna ska fungera är tillgänglig. Variabeln map hänvisar till Leaflet Map som skapades i ngOnInit-hanteraren.

public ngAfterViewInit(): void
{
this.map.invalidateSize();
this.__initMapHandlers();
}

Notera att hanteraren för uppdatering av kartstorlek räknar om variablerna currentWidth och currentHeight i klassen, som är bundna till de DIV-stilar som kontrollerar bredden och höjden på kart-DIV:en. Leaflet använder den informationen om bredd/höjd för att återskapa och återskapa kartan.

Då definitionen av kartans bredd/höjd och ändring av kartans storlek med fönsterändringar hanteras internt i kartkomponenten läggs en enkel handläggare för fönsterändring till.

@HostListener('window:resize', )
protected __onResize(event: any): void
{
this.__updateMapSize();
this.map.invalidateSize();
}

Det här skulle också kunna hanteras av en tjänst utanför Angular, köras utanför Angular och avstämplas. Om intresset är tillräckligt stort kommer jag att tillhandahålla en handledning som illustrerar tekniken.

Map Controls

Leaflet tillåter anpassade kontroller, men du kan också använda Angular-komponenter som map-kontroller. Skapa Angular-komponenten och använd CSS för positionering. Jag har använt detta i flera projekt för mycket anpassade zoomkontroller. Se mappen /src/app/maps/map-control för ett skelett som kan användas som utgångspunkt.

Se /src/app/maps/map.component.scss för relevant styling.

Tänk på z-index

Om tiling eller någon annan aspekt av kartvisningen inte verkar fungera kan det vara ett problem med z-index. Tidigare har jag varit tvungen att göra om z-index helt enkelt genom att byta kakelleverantör eller till och med migrera från Angular 7 till Angular 8!

Markörer

Markörer med kända koordinater kan läggas till på en karta. Definiera koordinaterna och skapa sedan en Leaflet Icon för varje koordinat. Markeringskoordinater för den här handledningen definieras i appens huvudkomponent,

/src/app/app.component.ts

public markers: {lat: number, long: number}; // Map markers (relevance depends on map center)
constructor()
{
// some map markers
this.markers = ;
}

och skickas som en Angular Input till kartkomponenten,

/src/app/app.component.html

<app-map ="markers"></app-map>

Markörer återges i kartkomponenten,

/src/app/maps/map.component.ts

protected __showMarkers(): void
{
if (this.markers !== undefined && this.markers != null && this.markers.length > 0)
{
// Add markers
const icon = L.icon({
iconUrl: MapIconOptions.mapIcon,
iconSize: MapIconOptions.iconSize,
iconAnchor: MapIconOptions.iconAnchor,
shadowUrl: MapIconOptions.mapShadowIcon,
shadowSize: MapIconOptions.shadowSize,
shadowAnchor: MapIconOptions.shadowAnchor,
});
const n: number = this.markers.length;
let i: number;
let m: L.marker;
let x: number;
let y: number;
for (i = 0; i < n; ++i) {
x = this.markers.lat;
y = this.markers.long;
if (x !== undefined && !isNaN(x) && y !== undefined && !isNaN(y))
{
// okay to add the icon
m = L.marker(, {icon: icon}).addTo(this.map);
}
else
{
// implement your own error handling
console.log('MARKER ERROR, Marker number: ', (i+1), 'x: ', x, ' y: ', y);
}
}
}
}

Interaktivitet

Ett par hanterare för grundläggande interaktivitet i kartan har lagts till för din skull, nämligen mus-klick och mus-move. Den sistnämnda uppdaterar den aktuella kartpositionen (lat/long) baserat på musens position.

/src/app/maps/map.component.ts

protected __onMapMouseMove(evt: any): void
{
const lat: string = evt.latlng.lat.toFixed(3);
const long: string = evt.latlng.lng.toFixed(3);
this.mcText = `Latitude: ${lat} &nbsp; &nbsp; Longitude: ${long}`;
}

Strängen som återspeglar den aktuella positionen visas i kartkomponentens mall,

/src/app/maps/map.component.html

<div class="mouse-coords">
<span></span>
<span ="mcText"></span>
</div>

Resultatet

Bygg programmet och du bör observera något som liknar denna skärmdump,

Angular version 8 och Leaflet Map

Förflytta musen över kartan för att observera uppdateringar av musens position i kartans koordinater.

Jag hoppas att detta hjälper dig att komma igång med arbetet med Angular och Leaflet. Dessa två applikationer fungerar mycket bra tillsammans och det finns en nästan obegränsad potential för mycket interaktiva, engagerande kartor.

God lycka till med dina Angular-försök!

För mer Angular-godheter, se till att kolla in det senaste avsnittet av podcasten The Angular Show.

ng-conf: The Musical är en tvådagars konferens från ng-conf-folket som kommer den 22 & 23 april 2021. Kolla in den på ng-conf.org

Lämna en kommentar