Este artigo é orientado para desenvolvedores angulares iniciantes que desejam integrar Leaflet em suas aplicações. A integração de dependências de terceiros em Angular pode ser em qualquer lugar, desde trivial a problemática. Enquanto o Leaflet tende mais para o lado trivial, mapas que se ajustam fluidamente com o tamanho do navegador podem apresentar alguns problemas de configuração relativos ao ciclo de vida Angular.
Antes de iniciar a desconstrução, aponte seu amigável e vizinho navegador para o seguinte Github.
Agora, você pode acompanhar ou bifurcar o projeto e usá-lo como base para suas próprias aplicações.
Background
Este tutorial presume uma pequena quantidade de conhecimento prévio de Folhetos, mas não mais do que está expresso no Guia de Início Rápido de Folhetos.
ArcGis é usado para a colocação de mosaicos na aplicação abordada neste artigo (o pacote de folhetos esri é instalado a partir do npm).
Configuração Angular
Muito pouco precisa ser feito após a instalação ubíqua do npm. Os estilos de folhetos necessários são disponibilizados através do arquivo angular.json,
"styles": ,
Tive resultados misturados com @types/leaflet, então esta aplicação não explora digitação por uma questão de simplicidade. O folheto e os tiles da ESRI são importados como mostrado abaixo,
import * as esri from 'esri-leaflet';
import * as L from 'leaflet';
Um Mapa de Folheto, por exemplo, é temporariamente digitado como qualquer outro; sinta-se livre para firmar as digitações como um exercício depois de ter desconstruído o tutorial.
As coordenadas do centro de um mapa são importantes para a inicialização do mapa. Muitas demos hardcode esta informação. Como alternativa, este tutorial ilustra como injetar coordenadas do centro do mapa usando as fichas de injeção angular.
Uma coordenada é um ponto bidimensional em um mapa, representado pela latitude e longitude. Um InjectionToken para uma coordenada pode ser criado como ilustrado no arquivo /src/app/tokens.ts,
import { InjectionToken } from '@angular/core';
export const INIT_COORDS = new InjectionToken<{lat: number, long: number}>('INIT_COORDS');
INIT_COORDS é usado no módulo /src/app/app.ts.ts para executar a provisão (ou definição) real (lat/long),
providers: ,
Esta move a definição do centro do mapa para o nível mais alto na aplicação Angular (onde é facilmente visível e quase autodocumentada).
Para injetar esta coordenada na aplicação, importe INIT_COORDS do arquivo tokens e injetar de um construtor de classes. Isto é ilustrado no arquivo /src/app/map.pt (o componente principal do mapa neste tutorial),
constructor( @Inject(INIT_COORDS) protected _initCoords: {lat: number, long: number} )
Map Component
A aplicação coberta neste artigo exibe um mapa de altura fixa com uma largura que se estende por toda a janela do navegador. O mapa redraws como a janela é redimensionada. Alguns marcadores também são renderizados no topo dos tiles.
O mapa é integrado à aplicação através do template do componente principal da aplicação, como mostrado abaixo
/src/app/app.component.html
<app-map ="markers"></app-map>
e o código fonte do componente do mapa é encontrado em /src/app/maps/map.component.ts .
O mapa é renderizado em um container (DIV) que está atualmente no template do componente mapa,
/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>
Se a largura e a altura do DIV que contém o mapa são fixas, então os tiles do mapa podem ser renderizados em um ponto inicial no ciclo de vida do componente. Duas aproximações são possíveis para passar a largura e altura variáveis, de fora para dentro e de dentro para fora. O método outside-in define entradas angulares para largura e altura. O componente pai é responsável por comunicar a largura e a altura ao componente do mapa. A abordagem inside-out define largura e altura internas ao componente do mapa e ‘passa’ essa informação para o seu modelo. A maioria das aplicações utiliza a abordagem de fora para dentro. Este tutorial emprega o método inside-out para fins de ilustração. Modifique o código para alterar a passagem de largura e altura como um exercício.
Variable width and height introduce some subtle issues relative to map rendering. É tentador executar tudo relacionado com a configuração de Folhetos no manipulador de entrada, e isto normalmente funciona com largura e altura fixas. Como a largura do mapa varia com o tamanho do navegador neste tutorial, é melhor separar o processo de inicialização do mapa entre os manipuladores do ciclo de vida on-init e after-view-init. Isto é ilustrado nos seguintes segmentos de código de /src/app/maps/map.pt .
Primeiro, a identificação de um DIV contendo para inicialização do mapa é descarregada para uma ViewChild,
@ViewChild('primaryMap', {static: true}) protected mapDivRef: ElementRef;
protected mapDiv: HTMLDivElement;
A maior parte da configuração do mapa é feita em 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();
}
Invalidar o tamanho do mapa é diferido para ngApós-VisualizaçãoInit, quando toda a largura e altura necessárias para o mapa funcionar. A variável mapa refere-se ao Mapa de Folhetos criado no ngOnInit handler.
public ngAfterViewInit(): void
{
this.map.invalidateSize();
this.__initMapHandlers();
}
Nota que o manipulador de tamanho do mapa de atualização recompila as variáveis correnteWidth e correnteHeight da classe, que estão ligadas aos estilos DIV que controlam a largura e altura do mapa DIV. Leaflet usa essa informação de largura/altura para redirecionar e renderizar o mapa.
Desde que a definição da largura/altura do mapa e o redimensionamento do mapa com mudanças de janela são tratados internamente ao componente do mapa, um simples manipulador de tamanho de janela é adicionado.
@HostListener('window:resize', )
protected __onResize(event: any): void
{
this.__updateMapSize();
this.map.invalidateSize();
}
Isso também poderia ser tratado por um serviço externo, executado fora de Angular, e debounced. Se houver interesse suficiente, fornecerei um tutorial que ilustra a técnica.
Controles de mapa
Folheto permite controles personalizados, mas você também pode usar componentes angulares como controles de mapa. Crie o componente Angular e use o CSS para posicionamento. Já usei isso em vários projetos para controles de zoom altamente personalizados. Veja a pasta /src/app/maps/map-control para um esqueleto que pode ser usado como ponto de partida.
Refer to /src/app/maps/map.scss para estilo relevante.
Beware the z-index
Se o tiling ou algum outro aspecto da exibição do mapa não parecer funcionar, pode ser um problema com o z-index. No passado, eu tive que re-mapear z-índices simplesmente mudando de provedor de azulejos ou mesmo migrando de Angular 7 para Angular 8!
Map Markers
Markers com coordenadas conhecidas podem ser adicionados a um mapa. Defina as coordenadas e depois crie um Ícone de Desdobrável para cada uma delas. As coordenadas dos marcadores para este tutorial são definidas no componente principal da aplicação,
/src/app/app.component.ts
public markers: {lat: number, long: number}; // Map markers (relevance depends on map center)
constructor()
{
// some map markers
this.markers = ;
}
e são passadas como Entrada Angular para o componente do mapa,
/src/app/app.component.html
<app-map ="markers"></app-map>
Markers são renderizados no componente do mapa,
/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);
}
}
}
}
Interactivity
Um par de manipuladores para interatividade básica do mapa foram adicionados para você, ou seja, mouse-clique e mouse-move. Este último actualiza a posição actual do mapa (lat/long) com base na posição do rato.
/src/app/maps/map.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} Longitude: ${long}`;
}
A string que reflecte a posição actual é apresentada no modelo do componente do mapa,
/src/app/maps/map.ts.html
<div class="mouse-coords">
<span></span>
<span ="mcText"></span>
</div>
O resultado
Build a aplicação e você deve observar algo semelhante a esta captura de tela,