介绍
传单支持形状。通过提供包含边界数据的 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
在代码编辑器中打开并进行以下更改:
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
到构造函数中:
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
.
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 层提供了一个工厂。让我们把这个逻辑放在它自己的函数中,然后在数据解析后调用它。
// ...
@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
:
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()
在将形状图层添加到地图后调用它。
这是map.component.ts
该bringToBack()
方法的完整文件:
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
‘sonEachFeature()
和 的交互性L.DomEvent.On
。
关于使用 Angular 和 Leaflet 的 4 部分系列到此结束。
如果您想了解有关 Angular 的更多信息,请查看我们的 Angular 主题页面以获取练习和编程项目。