リーフレットを使用して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に進みます。