Maps mit Leaflet in die Angular-Anwendung integrieren

Maps mit Leaflet in die Angular-Version integrieren 8
Jim Armstrong
Jim Armstrong

Follow

Okt 17, 2019 – 6 min read

Dieser Artikel richtet sich an beginnende Angular-Entwickler, die Leaflet in ihre Anwendungen integrieren wollen. Die Integration von Drittanbieter-Abhängigkeiten in Angular kann von trivial bis problematisch reichen. Während Leaflet eher zur trivialen Seite tendiert, können Karten, die sich fließend an die Browsergröße anpassen, einige Setup-Probleme in Bezug auf den Angular-Lebenszyklus mit sich bringen.

Bevor Sie mit der Dekonstruktion beginnen, sollten Sie Ihren freundlichen Nachbarschaftsbrowser auf das folgende Github verweisen.

Jetzt können Sie dem Projekt folgen oder es aufspalten und als Basis für Ihre eigenen Anwendungen verwenden.

Hintergrund

Dieses Tutorial setzt ein geringes Maß an Leaflet-Vorkenntnissen voraus, aber nicht mehr, als im Leaflet Quickstart Guide angegeben ist.

ArcGis wird in der in diesem Artikel behandelten Anwendung zum Kacheln verwendet (das esri-leaflet-Paket wird von npm installiert).

Angular Setup

Nach der allgegenwärtigen npm-Installation muss nur sehr wenig getan werden. Die notwendigen Leaflet-Stile werden über die angular.json-Datei zur Verfügung gestellt.

"styles": ,

Ich habe gemischte Erfahrungen mit @types/leaflet gemacht, daher nutzt diese Anwendung der Einfachheit halber keine Typisierungen. Leaflet- und ESRI-Kacheln werden wie unten gezeigt importiert,

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

Eine Leaflet-Karte ist zum Beispiel vorübergehend wie eine beliebige Karte typisiert; Sie können die Typisierungen gerne als Übung festschreiben, nachdem Sie das Tutorial dekonstruiert haben.

Koordinaten des Mittelpunkts einer Karte sind für die Karteninitialisierung wichtig. Viele Demos codieren diese Information fest. Als Alternative wird in diesem Tutorial gezeigt, wie man die Koordinaten des Kartenzentrums mit Hilfe von Angulars Injection Tokens injiziert.

Eine Koordinate ist ein zweidimensionaler Punkt auf einer Karte, der durch Breiten- und Längengrad dargestellt wird. Ein InjectionToken für eine Koordinate kann wie in der Datei /src/app/tokens.ts dargestellt erstellt werden,

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

INIT_COORDS wird in der Datei /src/app/app.module.ts-Datei verwendet, um die eigentliche (lat/long) Bereitstellung (oder Definition) durchzuführen,

providers: ,

Dadurch wird die Definition des Kartenmittelpunkts auf die höchste Ebene in der Angular-Anwendung verschoben (wo sie leicht zu sehen und fast selbstdokumentierend ist).

Um diese Koordinate in die Anwendung zu injizieren, importieren Sie INIT_COORDS aus der Token-Datei und injizieren sie von einem Klassenkonstruktor. Dies wird in der Datei /src/app/map.component.ts (die primäre Kartenkomponente in diesem Tutorial) veranschaulicht,

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

Kartenkomponente

Die in diesem Artikel behandelte Anwendung zeigt eine Karte mit fester Höhe und einer Breite, die sich über das gesamte Browserfenster erstreckt. Die Karte wird neu gezeichnet, wenn die Größe des Fensters geändert wird.

Die Karte wird über das Template der Hauptanwendung in die Anwendung integriert, wie unten gezeigt

/src/app/app.component.html

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

und der Quellcode der Kartenkomponente befindet sich in /src/app/maps/map.component.ts.

Die Karte wird in einen Container (DIV) gerendert, der sich aktuell in der Vorlage der Kartenkomponente befindet,

/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>

Wenn die Breite und Höhe des enthaltenen DIVs festgelegt sind, können die Kartenkacheln zu einem frühen Zeitpunkt im Lebenszyklus der Komponente gerendert werden. Für die Übergabe von variabler Breite und Höhe sind zwei Ansätze möglich, outside-in und inside-out. Die Outside-in-Methode definiert Angular Inputs für Breite und Höhe. Die übergeordnete Komponente ist für die Übermittlung von Breite und Höhe an die Map-Komponente verantwortlich. Bei der Inside-Out-Methode werden Breite und Höhe intern in der Map-Komponente definiert und diese Informationen an die Vorlage weitergegeben. Die meisten Anwendungen verwenden den Outside-In-Ansatz. In diesem Tutorial wird zur Veranschaulichung die Inside-Out-Methode verwendet. Ändern Sie zu Übungszwecken den Code, um die Übergabe von Breite und Höhe zu ändern.

Variable Breite und Höhe führen zu einigen subtilen Problemen in Bezug auf die Kartendarstellung. Es ist verlockend, alles, was mit der Einrichtung von Leaflet zu tun hat, im On-Init-Handler auszuführen, und das funktioniert normalerweise mit fester Breite und Höhe. Da in diesem Tutorial die Breite der Karte mit der Browsergröße variiert, ist es besser, den Initialisierungsprozess der Karte zwischen dem On-Init- und dem After-View-Init-Lifecycle-Handler zu trennen. Dies wird in den folgenden Codesegmenten aus /src/app/maps/map.component.ts veranschaulicht.

Zunächst wird die Identifizierung eines enthaltenden DIV für die Karteninitialisierung an ein ViewChild ausgelagert,

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

Der größte Teil der Karteneinrichtung wird in ngOnInit durchgeführt,

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

Die Invalidierung der Kartengröße wird auf ngAfterViewInit verschoben, wenn die volle Breite und Höhe, die für die Kartenkacheln erforderlich ist, verfügbar ist. Die Map-Variable bezieht sich auf die Leaflet Map, die im ngOnInit-Handler erstellt wurde.

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

Beachten Sie, dass der Handler zur Aktualisierung der Map-Größe die Variablen currentWidth und currentHeight der Klasse neu berechnet, die an die DIV-Stile gebunden sind, die die Breite und Höhe des Map-DIVs steuern. Leaflet verwendet diese Breiten-/Höheninformationen, um die Karte neu zu kacheln und neu zu rendern.

Da die Definition der Breite/Höhe der Karte und die Größenänderung der Karte bei Fensteränderungen intern in der Kartenkomponente behandelt werden, wird ein einfacher Handler für die Fenstergröße hinzugefügt.

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

Dies könnte auch von einem externen Dienst gehandhabt werden, der außerhalb von Angular läuft und entprellt wird. Bei ausreichendem Interesse werde ich ein Tutorial zur Verfügung stellen, das diese Technik veranschaulicht.

Map Controls

Leaflet erlaubt zwar benutzerdefinierte Steuerelemente, aber man kann auch Angular-Komponenten als Map Controls verwenden. Erstellen Sie die Angular-Komponente und verwenden Sie CSS für die Positionierung. Ich habe dies in mehreren Projekten für stark angepasste Zoom-Steuerelemente verwendet. Im Ordner /src/app/maps/map-control finden Sie ein Skelett, das als Ausgangspunkt verwendet werden kann.

Beziehen Sie sich auf /src/app/maps/map.component.scss für das relevante Styling.

Achten Sie auf den z-index

Wenn die Kachelung oder ein anderer Aspekt der Kartenanzeige nicht zu funktionieren scheint, kann es ein Problem mit dem z-index sein. In der Vergangenheit musste ich z-Indizes neu zuordnen, einfach weil ich den Kachelanbieter gewechselt oder sogar von Angular 7 auf Angular 8 migriert habe!

Kartenmarkierungen

Markierungen mit bekannten Koordinaten können zu einer Karte hinzugefügt werden. Definieren Sie die Koordinaten und erstellen Sie dann ein Leaflet-Symbol für jeden einzelnen. Die Koordinaten der Marker werden in diesem Tutorial in der Hauptkomponente der App definiert,

/src/app/app.component.ts

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

und als Angular Input an die Kartenkomponente übergeben,

/src/app/app.component.html

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

Markierungen werden in der Kartenkomponente gerendert,

/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);
}
}
}
}

Interaktivität

Ein paar Handler für grundlegende Karteninteraktivität wurden für Sie hinzugefügt, nämlich Mausklick und Mausbewegung. Letzterer aktualisiert die aktuelle Kartenposition (lat/long) basierend auf der Mausposition.

/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}`;
}

Der String, der die aktuelle Position widerspiegelt, wird in der Vorlage der Kartenkomponente angezeigt,

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

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

Das Ergebnis

Erstellen Sie die Anwendung und Sie sollten etwas ähnliches wie diesen Screenshot sehen,

Angular Version 8 und Leaflet Map

Bewegen Sie die Maus über die Karte und beobachten Sie die Aktualisierung der Mausposition in Kartenkoordinaten.

Ich hoffe, dass dies ein guter Einstieg in die Arbeit mit Angular und Leaflet ist. Diese beiden Anwendungen arbeiten sehr gut zusammen, und es gibt ein nahezu unbegrenztes Potenzial für hochgradig interaktive, ansprechende Karten.

Viel Erfolg bei Ihren Angular-Bemühungen!

Für mehr Angular-Tauglichkeit sollten Sie sich die neueste Episode des Podcasts The Angular Show ansehen.

ng-conf: The Musical ist eine zweitägige Konferenz der ng-conf-Leute, die am 22. & 23. April 2021 stattfindet. Informieren Sie sich unter ng-conf.org

Schreibe einen Kommentar