介绍
Leaflet 支持 形状 。 通过提供包含边界数据的 GeoJSON 文件,您可以在地图上指示县、州和国家。
注意: 这是关于使用 Angular 和 Leaflet 的 4 部分系列的第 4 部分。
在本教程中,您将学习如何为美利坚合众国的大陆州渲染形状。
先决条件
要完成本教程,您需要:
- 本教程直接建立在 上一部分 中的安装和步骤之上。
第 1 步 — 下载 GeoJSON 数据
本教程将为美国各州的轮廓绘制 GeoJSON 数据。
访问 Eric Celeste 的美国 GeoJSON 和 KML 数据 并下载 5m GeoJSON 文件 (gz_2010_us_040_00_5m.json
)。
将此文件保存在您的 /assets/data
目录中。
第 2 步 - 创建形状服务
此时,您应该在 Angular 应用程序中实现了 Leaflet。
使用终端窗口导航到项目目录。 然后,运行以下命令以生成新服务:
npx @angular/cli generate service shape --skip-tests
这将创建一个新文件:shape.service.ts
。
接下来,您将在 app.module.ts
中添加此新服务作为提供程序。
在代码编辑器中打开 app.module.ts
并进行以下更改:
src/app/app.module.ts
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; import { MarkerService } from './marker.service'; import { PopupService } from './popup.service'; import { ShapeService } from './shape.service'; import { AppComponent } from './app.component'; import { MapComponent } from './map/map.component'; @NgModule({ declarations: [ AppComponent, MapComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [ MarkerService, PopupService, ShapeService ], bootstrap: [AppComponent] }) export class AppModule { }
您的应用程序现在支持您的新 ShapeService
。
第 3 步 — 加载形状
接下来,在代码编辑器中打开新创建的 shape.service.ts
并将 HttpClient
添加到构造函数中:
src/app/shape.service.ts
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class ShapeService { constructor(private http: HttpClient) { } getStateShapes() { return this.http.get('/assets/data/gz_2010_us_040_00_5m.json'); } }
函数 getStateShapes()
将返回序列化 GeoJSON 对象的 observable。 要使用它,您需要订阅 MapComponent
中的 observable。
src/app/map/map.component.ts
import { Component, AfterViewInit } from '@angular/core'; import * as L from 'leaflet'; import { MarkerService } from '../marker.service'; import { ShapeService } from '../shape.service'; // ... @Component({ selector: 'app-map', templateUrl: './map.component.html', styleUrls: ['./map.component.css'] }) export class MapComponent implements AfterViewInit { private map; private states; constructor( private markerService: MarkerService, private shapeService: ShapeService ) { } // ... ngAfterViewInit(): void { this.initMap(); this.markerService.makeCapitalCircleMarkers(this.map); this.shapeService.getStateShapes().subscribe(states => { this.states = states; }); } }
这段代码在构造函数中注入ShapeService
,创建一个局部变量来存储数据,并调用getStateShapes()
函数拉取数据并订阅结果。
注意: 更好的方法是将数据预加载到解析器中。
加载数据后,您需要将形状作为图层添加到地图中。 Leaflet 为您可以利用的 GeoJSON 层提供了一个工厂。 让我们把这个逻辑放在它自己的函数中,然后在解析完数据后调用它。
src/app/map/map.component.ts
// ... @Component({ selector: 'app-map', templateUrl: './map.component.html', styleUrls: ['./map.component.css'] }) export class MapComponent implements AfterViewInit { private map; private states; // ... private initStatesLayer() { const stateLayer = L.geoJSON(this.states, { style: (feature) => ({ weight: 3, opacity: 0.5, color: '#008f68', fillOpacity: 0.8, fillColor: '#6DB65B' }) }); this.map.addLayer(stateLayer); } ngAfterViewInit(): void { this.initMap(); this.markerService.makeCapitalCircleMarkers(this.map); this.shapeService.getStateShapes().subscribe(states => { this.states = states; this.initStatesLayer(); }); } }
initStatesLayer()
函数创建一个新的 GeoJSON 图层并将其添加到地图中。
保存您的更改。 然后,停止您的应用程序并重新启动它。 在 Web 浏览器中打开应用程序 (localhost:4200
) 并观察状态的边界:
接下来,您将附加 mouseover
和 mouseout
事件,以使用 onEachFeature
与每个形状进行交互:
src/app/map/map.component.ts
private highlightFeature(e) { const layer = e.target; layer.setStyle({ weight: 10, opacity: 1.0, color: '#DFA612', fillOpacity: 1.0, fillColor: '#FAE042' }); } private resetFeature(e) { const layer = e.target; layer.setStyle({ weight: 3, opacity: 0.5, color: '#008f68', fillOpacity: 0.8, fillColor: '#6DB65B' }); } private initStatesLayer() { const stateLayer = L.geoJSON(this.states, { style: (feature) => ({ weight: 3, opacity: 0.5, color: '#008f68', fillOpacity: 0.8, fillColor: '#6DB65B' }), onEachFeature: (feature, layer) => ( layer.on({ mouseover: (e) => (this.highlightFeature(e)), mouseout: (e) => (this.resetFeature(e)), }) ) }); this.map.addLayer(stateLayer); }
保存您的更改。 然后,在 Web 浏览器中打开应用程序 (localhost:4200
) 并将鼠标移到形状上:
但是,标记看起来很模糊,因为形状层位于标记层之上。
有两种方法可以解决这个问题。 第一种方法是将 makeCapitalCircleMarkers()
调用直接移到 initStatesLayer()
之后。 第二种方法是在形状图层添加到地图后调用 bringToBack()
。
这是使用 bringToBack()
方法的完整 map.component.ts
文件:
src/app/map/map.component.ts
import { Component, AfterViewInit } from '@angular/core'; import * as L from 'leaflet'; import { MarkerService } from '../marker.service'; import { ShapeService } from '../shape.service'; const iconRetinaUrl = 'assets/marker-icon-2x.png'; const iconUrl = 'assets/marker-icon.png'; const shadowUrl = 'assets/marker-shadow.png'; const iconDefault = L.icon({ iconRetinaUrl, iconUrl, shadowUrl, iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], tooltipAnchor: [16, -28], shadowSize: [41, 41] }); L.Marker.prototype.options.icon = iconDefault; @Component({ selector: 'app-map', templateUrl: './map.component.html', styleUrls: ['./map.component.css'] }) export class MapComponent implements AfterViewInit { private map; private states; constructor( private markerService: MarkerService, private shapeService: ShapeService ) { } private initMap(): void { this.map = L.map('map', { center: [ 39.8282, -98.5795 ], zoom: 3 }); const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, minZoom: 3, attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>' }); tiles.addTo(this.map); } private highlightFeature(e) { const layer = e.target; layer.setStyle({ weight: 10, opacity: 1.0, color: '#DFA612', fillOpacity: 1.0, fillColor: '#FAE042' }); } private resetFeature(e) { const layer = e.target; layer.setStyle({ weight: 3, opacity: 0.5, color: '#008f68', fillOpacity: 0.8, fillColor: '#6DB65B' }); } private initStatesLayer() { const stateLayer = L.geoJSON(this.states, { style: (feature) => ({ weight: 3, opacity: 0.5, color: '#008f68', fillOpacity: 0.8, fillColor: '#6DB65B' }), onEachFeature: (feature, layer) => ( layer.on({ mouseover: (e) => (this.highlightFeature(e)), mouseout: (e) => (this.resetFeature(e)), }) ) }); this.map.addLayer(stateLayer); stateLayer.bringToBack(); } ngAfterViewInit(): void { this.initMap(); // this.markerService.makeCapitalMarkers(this.map); this.markerService.makeCapitalCircleMarkers(this.map); this.shapeService.getStateShapes().subscribe(states => { this.states = states; this.initStatesLayer(); }); } }
保存您的更改。 然后,在 Web 浏览器中打开应用程序 (localhost:4200
) 并观察州首府的缩放圆形标记和州边界的形状:
您现在有一个支持形状的地图。
结论
在这篇文章中,您创建了一个加载数据和构造形状的形状服务。 您添加了与 L.GeoJSON
的 onEachFeature()
和 L.DomEvent.On
的交互性。
关于使用 Angular 和 Leaflet 的 4 部分系列到此结束。
如果您想了解有关 Angular 的更多信息,请查看 我们的 Angular 主题页面 以获取练习和编程项目。