序章

リーフレットはマーカーをサポートします。 これらは、情報を含むことができるマップ上に配置されたインジケーターです。 これは、地図上のランドマークと目的地を強調表示する方法を提供します。

注:これは、AngularとLeafletの使用に関する4部構成のシリーズのパート2です。

このチュートリアルでは、サービスを使用してマーカーロジックを管理することにより、マップにマーカーを追加する方法を学習します。

前提条件

このチュートリアルを完了するには、次のものが必要です。

  • このチュートリアルは、前のパーツのインストールと手順に直接基づいています。

ステップ1—GeoJSONデータをダウンロードする

このチュートリアルでは、アメリカ合衆国の州都のGeoJSONデータをプロットします。 また、州名、首都名、人口に関する追加のメタデータも含まれます。

新しいを作成します data 下のサブディレクトリ assets ディレクトリ:

  1. mkdir src/assets/data

次に、を保存します usa-capitals.geojson このディレクトリ内のファイル。

ステップ2—マーカーサービスの作成

この時点で、AngularアプリケーションにLeafletの実装が機能しているはずです。

ターミナルウィンドウを使用して、プロジェクトディレクトリに移動します。 次に、次のコマンドを実行して、新しいサービスを生成します。

  1. 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: '&copy; <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つのエラーが発生します。

Output
marker-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.pngmarker-shadow.png 画像ファイル。

を開きます 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: '&copy; <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() 関数。 リーフレットのインスタッド 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、変更します 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 コードエディタで、次の変更を加えます。

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)そして州都の新しいスケーリングされた円マーカーを観察します。

これで、マーカーをサポートするマップができました。

結論

この投稿では、データを読み込んでマーカーを作成するマーカーサービスを作成しました。 2種類のマーカーを作成する方法を学びました。 L.markerL.circleMarker. 最後に、半径の関数を渡すことにより、各円マーカーのサイズを定義する方法を学びました。

AngularとLeafletの使用に関するこのシリーズのパート3に進みます。