リーフレットを使用してAngularでマップを作成する方法、パート2:マーカーサービス
序章
リーフレットはマーカーをサポートします。 これらは、情報を含むことができるマップ上に配置されたインジケーターです。 これは、地図上のランドマークと目的地を強調表示する方法を提供します。
注:これは、AngularとLeafletの使用に関する4部構成のシリーズのパート2です。
このチュートリアルでは、サービスを使用してマーカーロジックを管理することにより、マップにマーカーを追加する方法を学習します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- このチュートリアルは、前のパーツのインストールと手順に直接基づいています。
ステップ1—GeoJSONデータをダウンロードする
このチュートリアルでは、アメリカ合衆国の州都のGeoJSONデータをプロットします。 また、州名、首都名、人口に関する追加のメタデータも含まれます。
assetsディレクトリの下に新しいdataサブディレクトリを作成します。
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を開き、次の変更を加えます。
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 { 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をコンストラクターに追加します。
src / app / marker.service.ts
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データをロードし、マーカーを作成する新しい関数を作成します。 この関数は、リーフレットマップをパラメーターとして受け取ります。
marker.service.tsを変更してリーフレットをインポートし、makeCapitalMarkers関数を宣言します。
src / app / marker.service.ts
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を取得して結果を取得します。
データを取得したら、各フィーチャをループしてマーカーを作成し、それをマップに追加します。
src / app / marker.service.ts
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からこのメソッドを呼び出す必要があります。
src / app / map / map.component.ts
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);
}
}
この時点でアプリケーションを実行すると、コンソールで次の2つのエラーが発生します。
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)
marker-icon-2x.pngおよびmarker-shadow.pngイメージファイルを参照するには、Leafletのアセットをプロジェクトにインポートする必要があります。
angular.jsonファイルを開き、リーフレットimagesディレクトリを追加します。
angle.json
{
// ...
"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"
}
このコードは、リーフレットのマーカー画像をローカルにコピーします。
次に、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';
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メソッドを使用します。
src / app / marker.service.ts
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でこの関数を呼び出します。
src / app / map / map.component.ts
ngAfterViewInit(): void {
this.initMap();
// this.markerService.makeCapitalMarkers(this.map);
this.markerService.makeCapitalCircleMarkers(this.map);
}
これらの変更を保存し、Webブラウザ(localhost:4200)でアプリケーションを開きます。
アイコンが円に置き換えられました。
circleMarkerは、3番目のオプションのパラメーターを受け入れます。 このオブジェクトには、radiusプロパティを含めることができます。 MarkerServiceで、半径20を使用するようにmakeCapitalCircleMarkers関数を変更します。
const circle = L.circleMarker([lat, lon], { radius: 20 }).addTo(map);
このコードは、すべての半径を同じ値(20)になるようにサイズ設定します。
次に、州都の人口を反映するように半径を変更します。
static scaledRadius(val: number, maxVal: number): number {
return 20 * (val / maxVal);
}
この関数は、値(母集団)、最大値(最大母集団)を受け取り、[0〜20]の範囲の半径を返します。
Spread-operatorとmapを使用して、人口が最も多い首都を見つけます。
const maxPop = Math.max(...res.features.map(x => x.properties.population), 0);
GeoJSONデータから、最大の人口は「アリゾナ州フェニックス」(1626078)になります。
最後に、半径関数としてScaledRadiusを使用して、すべてをまとめます。
コードエディタでMarkerServiceを開き、次の変更を加えます。
src / app / marker.service.ts
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の2種類のマーカーを作成する方法を学びました。 最後に、半径の関数を渡すことにより、各円マーカーのサイズを定義する方法を学びました。
AngularとLeafletの使用に関するこのシリーズのパート3に進みます。