介绍
Leaflet 支持标记。这些是放置在地图上的可以包含信息的指示器。这提供了一种在地图上突出显示地标和目的地的方法。
注意:这是关于使用 Angular 和 Leaflet 的 4 部分系列的第 2 部分。
在本教程中,您将学习如何使用管理标记逻辑的服务向地图添加标记。
先决条件
要完成本教程,您需要:
第 1 步 – 下载 GeoJSON 数据
本教程将绘制美国各州首府的GeoJSON数据。它还包括一些关于州名、首都名和人口的额外元数据。
注意: 该usa-capitals.geojson
文件在随附的项目 repo 中可用。
在data
目录下新建一个子目录assets
:
- mkdir src/assets/data
然后,将usa-capitals.geojson
文件保存在此目录中。
第 2 步 – 创建标记服务
此时,您应该在 Angular 应用程序中有一个 Leaflet 的工作实现。
使用终端窗口导航到项目目录。然后,运行以下命令以生成新服务:
- npx @angular/cli generate service marker --skip-tests
这将创建一个新文件:marker.service.ts
.
接下来,您将在您的app.module.ts
. 您还将从您的assets
文件夹加载数据,因此您需要包含HttpClientModule
.
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 { AppComponent } from './app.component';
import { MapComponent } from './map/map.component';
@NgModule({
declarations: [
AppComponent,
MapComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
MarkerService
],
bootstrap: [AppComponent]
})
export class AppModule { }
您的应用程序现在支持您的新MarkerService
.
第 3 步 – 加载和绘制标记
接下来,marker.service.ts
在代码编辑器中打开新创建的并添加HttpClient
到构造函数中:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class MarkerService {
capitals: string = '/assets/data/usa-capitals.geojson';
constructor(private http: HttpClient) { }
}
创建一个将加载 GeoJSON 数据并创建标记的新函数。此函数将接受 Leaflet 地图作为参数。
修改marker.service.ts
导入 Leaflet 并声明一个makeCapitalMarkers
函数:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import * as L from 'leaflet';
@Injectable({
providedIn: 'root'
})
export class MarkerService {
capitals: string = '/assets/data/usa-capitals.geojson';
constructor(private http: HttpClient) { }
makeCapitalMarkers(map: L.map): void { }
}
使用HttpClient
,获取数据并subscribe
得到结果。
获得数据后,您将遍历每个要素,构建一个标记,并将其添加到地图中。
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import * as L from 'leaflet';
@Injectable({
providedIn: 'root'
})
export class MarkerService {
capitals: string = '/assets/data/usa-capitals.geojson';
constructor(private http: HttpClient) {
}
makeCapitalMarkers(map: L.map): void {
this.http.get(this.capitals).subscribe((res: any) => {
for (const c of res.features) {
const lon = c.geometry.coordinates[0];
const lat = c.geometry.coordinates[1];
const marker = L.marker([lat, lon]);
marker.addTo(map);
}
});
}
}
此代码处理加载和向地图添加标记的逻辑。
现在,您必须从MapComponent
以下位置调用此方法:
import { Component, AfterViewInit } from '@angular/core';
import * as L from 'leaflet';
import { MarkerService } from '../marker.service';
@Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.css']
})
export class MapComponent implements AfterViewInit {
private map;
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);
}
constructor(private markerService: MarkerService) { }
ngAfterViewInit(): void {
this.initMap();
this.markerService.makeCapitalMarkers(this.map);
}
}
如果此时您要运行您的应用程序,您会在控制台中遇到两个错误:
Outputmarker-icon-2x.png:1 GET http://localhost:4200/marker-icon-2x.png 404 (Not Found)
marker-shadow.png:1 GET http://localhost:4200/marker-shadow.png 404 (Not Found)
您需要将 Leaflet 的资产导入到您的项目中以引用marker-icon-2x.png
和marker-shadow.png
图像文件。
打开angular.json
文件并添加 Leafletimages
目录:
{
// ...
"projects": {
"angular-leaflet-example": {
// ...
"architect": {
"build": {
// ...
"options": {
// ...
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "node_modules/leaflet/dist/images/",
"output": "./assets"
}
],
// ..
},
// ...
},
// ...
}
}},
"defaultProject": "angular-leaflet-example"
}
此代码将在本地复制 Leaflet 的标记图像。
然后,重新访问map.component.ts
并定义图标:
import { Component, AfterViewInit } from '@angular/core';
import * as L from 'leaflet';
import { MarkerService } from '../marker.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;
constructor(private markerService: MarkerService) { }
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);
}
ngAfterViewInit(): void {
this.initMap();
this.markerService.makeCapitalMarkers(this.map);
}
}
保存您的更改。然后,停止您的应用程序并重新启动它。在 Web 浏览器 ( localhost:4200
) 中打开应用程序并观察州首府的标记:
此时,您有一个支持默认标记的地图。
第 4 步 – 显示圆形标记
在下一步中,您会将标记从图标更改为圆圈。然后缩放圆圈的大小以反映州议会大厦的人口。
打开MarkerService
并创建一个makeCapitalCircleMarkers()
函数。它将与makrCapitalMarkers()
功能非常相似。在 Leaflet 的marker
方法中,您将使用该circleMarker
方法:
makeCapitalCircleMarkers(map: L.map): void {
this.http.get(this.capitals).subscribe((res: any) => {
for (const c of res.features) {
const lon = c.geometry.coordinates[0];
const lat = c.geometry.coordinates[1];
const circle = L.circleMarker([lat, lon]);
circle.addTo(map);
}
});
}
然后,调用这个函数MapComponent
:
ngAfterViewInit(): void {
this.initMap();
// this.markerService.makeCapitalMarkers(this.map);
this.markerService.makeCapitalCircleMarkers(this.map);
}
保存这些更改并在 Web 浏览器 ( localhost:4200
) 中打开应用程序:
图标现在已替换为圆圈。
circleMarker
接受第三个可选参数。这个对象可以包含一个radius
属性。在您的 中MarkerService
,修改makeCapitalCircleMarkers
函数以使用半径20
:
const circle = L.circleMarker([lat, lon], { radius: 20 }).addTo(map);
此代码将所有半径的大小设置为相同的值 ( 20
)。
接下来,您将更改半径以反映州首府的人口:
static scaledRadius(val: number, maxVal: number): number {
return 20 * (val / maxVal);
}
此函数接受一个值(人口)、一个最大值(最大人口),并返回范围 [0 – 20] 内的半径。
您将使用传播运算符并map
找到人口最多的首都:
const maxPop = Math.max(...res.features.map(x => x.properties.population), 0);
从 GeoJSON 数据来看,最大的人口将是:“亚利桑那州凤凰城”(1626078
)。
最后,您将使用ScaledRadius
作为半径函数将它们组合在一起。
MarkerService
在代码编辑器中打开并进行以下更改:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import * as L from 'leaflet';
@Injectable({
providedIn: 'root'
})
export class MarkerService {
capitals: string = '/assets/data/usa-capitals.geojson';
constructor(private http: HttpClient) { }
static scaledRadius(val: number, maxVal: number): number {
return 20 * (val / maxVal);
}
makeCapitalMarkers(map: L.map): void {
this.http.get(this.capitals).subscribe((res: any) => {
for (const c of res.features) {
const lon = c.geometry.coordinates[0];
const lat = c.geometry.coordinates[1];
const marker = L.marker([lat, lon]);
marker.addTo(map);
}
});
}
makeCapitalCircleMarkers(map: L.map): void {
this.http.get(this.capitals).subscribe((res: any) => {
const maxPop = Math.max(...res.features.map(x => x.properties.population), 0);
for (const c of res.features) {
const lon = c.geometry.coordinates[0];
const lat = c.geometry.coordinates[1];
const circle = L.circleMarker([lat, lon], {
radius: MarkerService.scaledRadius(c.properties.population, maxPop)
});
circle.addTo(map);
}
});
}
}
保存您的更改。然后,停止您的应用程序并重新启动它。在 Web 浏览器 ( localhost:4200
) 中打开应用程序并观察州首府的新比例圆圈标记:
您现在有一个支持标记的地图。
结论
在这篇文章中,您创建了一个标记服务来加载数据并构建标记。您学习了如何创建两种类型的标记:L.marker
和L.circleMarker
。最后,您学习了如何通过传递半径函数来定义每个圆形标记的大小。