Integracja map w aplikacji Angular za pomocą Leaflet

Integracja mapy Leaflet w wersji Angular 8
Jim Armstrong
Jim Armstrong

Follow

Oct 17, 2019 – 6 min read

Ten artykuł jest zorientowany na początkujących programistów Angular, którzy chcą zintegrować Leaflet ze swoimi aplikacjami. Integracja zależności stron trzecich w Angular może być wszędzie od trywialnych do problematycznych. Podczas gdy Leaflet skłania się bardziej ku trywialnej stronie, mapy, które płynnie dostosowują się do rozmiaru przeglądarki mogą przedstawiać pewne problemy z konfiguracją w stosunku do cyklu życia Angular.

Przed rozpoczęciem dekonstrukcji, skieruj swoją przyjazną, sąsiednią przeglądarkę do następującego Githuba.

Teraz możesz podążać za projektem lub rozwidlić go i użyć jako bazy dla swoich własnych aplikacji.

Wstęp

Ten samouczek zakłada niewielką ilość wcześniejszej wiedzy na temat Leaflet, ale nie więcej niż jest to wyrażone w Leaflet Quickstart Guide.

ArcGis jest używany do kafelkowania w aplikacji omawianej w tym artykule (pakiet esri-leaflet jest instalowany z npm).

Angular Setup

Bardzo niewiele trzeba zrobić po wszechobecnej instalacji npm. Niezbędne style Leaflet są udostępniane poprzez plik angular.json,

"styles": ,

Miałem mieszane wyniki z @types/leaflet, więc ta aplikacja nie wykorzystuje typowania dla uproszczenia. Kafelki Leaflet i ESRI są importowane tak, jak pokazano poniżej,

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

Mapa Leaflet, na przykład, jest tymczasowo wpisana jako dowolna; nie krępuj się ustalać typowania jako ćwiczenia po zdekonstruowaniu samouczka.

Współrzędne środka mapy są ważne dla inicjalizacji mapy. Wiele demek koduje tę informację na sztywno. Jako alternatywę, ten tutorial ilustruje jak wstrzyknąć współrzędne środka mapy używając Angular’s Injection Tokens.

Współrzędne to dwuwymiarowy punkt na mapie, reprezentowany przez szerokość i długość geograficzną. InjectionToken dla współrzędnej może być utworzony w sposób zilustrowany w pliku /src/app/tokens.ts,

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

INIT_COORDS jest używany w pliku /src/app/app.module.ts do wykonania rzeczywistego (lat/długości) dostarczania (lub definicji),

providers: ,

To przenosi definicję centrum mapy na najwyższy poziom w aplikacji Angular (gdzie jest łatwo widoczna i prawie samodokumentująca się).

Aby wstrzyknąć tę współrzędną do aplikacji, zaimportuj INIT_COORDS z pliku tokens i wstrzyknij z konstruktora klasy. Jest to zilustrowane w pliku /src/app/map.component.ts (podstawowy komponent mapy w tym tutorialu),

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

Komponent mapy

Aplikacja omawiana w tym artykule wyświetla mapę o stałej wysokości i szerokości, która rozciąga się na całe okno przeglądarki. Mapa jest przerysowywana wraz ze zmianą rozmiaru okna. Niektóre markery są również renderowane na wierzchu kafelków mapy.

Mapa jest zintegrowana z aplikacją poprzez szablon głównego komponentu aplikacji, jak pokazano poniżej

/src/app/app.component.html

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

a kod źródłowy komponentu mapy znajduje się w /src/app/maps/map.component.ts .

Mapa jest renderowana do kontenera (DIV), który jest obecnie w szablonie komponentu mapy,

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

Jeśli szerokość i wysokość zawierającego DIV są stałe, wtedy kafelki mapy mogą być renderowane we wczesnym punkcie cyklu życia komponentu. Możliwe są dwa podejścia do przekazywania zmiennej szerokości i wysokości, outside-in i inside-out. Metoda outside-in definiuje Angular Inputs dla szerokości i wysokości. Komponent nadrzędny jest odpowiedzialny za przekazywanie szerokości i wysokości do komponentu mapy. Podejście inside-out definiuje szerokość i wysokość wewnątrz komponentu mapy i „przekazuje” te informacje do jego szablonu. Większość aplikacji używa podejścia outside-in. W tym tutorialu zastosowano metodę inside-out dla celów ilustracyjnych. Zmodyfikuj kod, aby zmienić przekazywanie szerokości i wysokości jako ćwiczenie.

Zmienna szerokość i wysokość wprowadza pewne subtelne problemy związane z renderowaniem mapy. Kuszące jest wykonywanie wszystkiego związanego z konfiguracją Leaflet w handlerze on-init, a to zazwyczaj działa ze stałą szerokością i wysokością. Ponieważ w tym tutorialu szerokość mapy zmienia się w zależności od rozmiaru przeglądarki, lepiej jest rozdzielić proces inicjalizacji mapy pomiędzy handlerami cyklu życia on-init i after-view-init. Zostało to zilustrowane w następujących segmentach kodu z /src/app/maps/map.component.ts .

Po pierwsze, identyfikacja zawierającego DIV dla inicjalizacji mapy jest odciążona do ViewChild,

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

Większość konfiguracji mapy jest wykonywana w 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();
}

Unieważnienie rozmiaru mapy jest odroczone do ngAfterViewInit, kiedy dostępna jest pełna szerokość i wysokość niezbędna do działania kafelków mapy. Zmienna mapy odnosi się do mapy Leaflet utworzonej w handlerze ngOnInit.

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

Zauważ, że handler aktualizacji rozmiaru mapy ponownie oblicza zmienne klasy currentWidth i currentHeight, które są powiązane ze stylami DIV, które kontrolują szerokość i wysokość DIV mapy. Leaflet używa tych informacji o szerokości/wysokości do ponownego kafelkowania i renderowania mapy.

Ponieważ definicja szerokości/wysokości mapy i zmiana rozmiaru mapy ze zmianami w oknie są obsługiwane wewnętrznie do komponentu mapy, prosty handler zmiany rozmiaru okna jest dodany.

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

Może to być również obsługiwane przez zewnętrzną usługę, uruchamianą poza Angular, i debounced. Jeśli będzie wystarczające zainteresowanie, dostarczę samouczek, który zilustruje tę technikę.

Kontrole map

Leaflet pozwala na niestandardowe kontrolki, ale możesz również użyć komponentów Angular jako kontrolek map. Utwórz komponent Angular i użyj CSS do pozycjonowania. Używałem tego w kilku projektach dla wysoce niestandardowych kontrolek zoomu. Zobacz folder /src/app/maps/map-control dla szkieletu, który może być użyty jako punkt wyjścia.

Odnieś się do /src/app/maps/map.component.scss dla odpowiednich stylizacji.

Uważaj na z-index

Jeśli kafelkowanie lub jakiś inny aspekt wyświetlania mapy nie wydaje się działać, może to być problem z z-index. W przeszłości musiałem ponownie mapować z-indeksy po prostu ze zmiany dostawców kafelków lub nawet migracji z Angular 7 do Angular 8!

Map Markers

Markery o znanych współrzędnych mogą być dodawane do mapy. Zdefiniuj współrzędne, a następnie utwórz ikonę Leaflet dla każdego z nich. Współrzędne markerów w tym tutorialu są zdefiniowane w głównym komponencie aplikacji,

/src/app/app.component.ts

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

i są przekazywane jako Angular Input do komponentu mapy,

/src/app/app.component.html

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

Markery są renderowane w komponencie mapy,

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

Interaktywność

Dodano kilka handlerów dla podstawowej interaktywności mapy, mianowicie mouse-click i mouse-move. Ten ostatni aktualizuje bieżącą pozycję mapy (lat/długość) na podstawie pozycji myszy.

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

Ciąg odzwierciedlający bieżącą pozycję jest wyświetlany w szablonie komponentu mapy,

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

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

Wynik

Buduj aplikację i powinieneś zaobserwować coś podobnego do tego zrzutu ekranu,

Angular wersja 8 i Leaflet Map

Przesuń mysz nad mapą, aby zaobserwować aktualizacje pozycji myszy we współrzędnych mapy.

Mam nadzieję, że to sprawi, że zaczniesz pracować z Angular i Leaflet. Te dwie aplikacje bardzo dobrze ze sobą współpracują i istnieje niemal nieograniczony potencjał dla wysoce interaktywnych, wciągających map.

Powodzenia w pracy z Angular!

Po więcej dobroci Angular, koniecznie sprawdź najnowszy odcinek podcastu The Angular Show.

ng-conf: The Musical to dwudniowa konferencja od ludzi ng-conf, która odbędzie się 22 kwietnia & 23 kwietnia 2021 roku. Sprawdź to na ng-conf.org

.

Dodaj komentarz