LeafletでAngularアプリケーションにマップを統合する

Angular バージョンにLeafletマップを統合する 8
Jim Armstrong
Jim Armstrong

Follow

Oct 17, 2019 – 6 min read

この記事は、Leafletをアプリケーションに統合したいAngular開発者の初心者に向けたものです。 Angular へのサードパーティの依存関係の統合は、些細なものから問題のあるものまで、さまざまです。 Leaflet はより些細なことに向かう傾向がありますが、ブラウザーのサイズに応じて流動的に調整するマップは、Angular のライフサイクルに関連するいくつかのセットアップの問題を提示することができます。

背景

このチュートリアルでは、Leaflet の予備知識を少し仮定しますが、Leaflet クイックスタート ガイドに記載されている以上のことはしません。

ArcGis は、この記事で扱うアプリケーションでタイル化に使用します (esri-leaflet パッケージは npm からインストールします)。 必要な Leaflet スタイルは、angular.json ファイルを通して利用可能になります。

"styles": ,

私は @types/leaflet でさまざまな結果を持っていたので、このアプリケーションは単純化のために typings を利用しません。 Leaflet および ESRI タイルは以下のようにインポートされます。

import * as esri from 'esri-leaflet';
import * as L from 'leaflet';

A Leaflet Map, for example, is temporarily typed as any; feel free to firm up typings as a exercise after you have deconstructed the tutorial.

地図の中心の座標は地図の初期化にとって重要なものです。 多くのデモでは、この情報をハードコードしています。

座標は、緯度と経度で表される、地図上の 2 次元の点です。 座標の InjectionToken は、/src/app/tokens.ts ファイルに示されているように作成することができ、

import { InjectionToken } from '@angular/core';
export const INIT_COORDS = new InjectionToken<{lat: number, long: number}>('INIT_COORDS');

INIT_COORDS は /src/app/app.module.

providers: ,

これにより、マップ センターの定義が Angular アプリケーションの最も高いレベル (簡単に見ることができ、ほぼ自己文書化できる場所) に移動します。

この座標をアプリケーションに注入するために、トークン ファイルから INIT_COORDS をインポートし、クラス コンストラクターから注入します。 これは、/src/app/map.component.ts ファイル (このチュートリアルの主要なマップ コンポーネント) に示されています。

constructor( @Inject(INIT_COORDS) protected _initCoords: {lat: number, long: number} )

Map Component

この記事で取り上げたアプリケーションは、ブラウザ ウィンドウ全体に広がる幅で固定高さのマップを表示しています。 マップはウィンドウのサイズ変更に伴って再描画されます。 いくつかのマーカーはマップ タイルの上にも表示されます。

マップは、以下に示すように、メイン アプリ コンポーネントのテンプレートを通じてアプリケーションに統合されます。ts .

マップは、現在マップ コンポーネントのテンプレートにあるコンテナー (DIV) にレンダリングされます。

/src/app/maps/map.component.html

<div>
<div>
<div #primaryMap ="currentHeight" ="currentWidth"></div>
<map-control class="map-control"></map-control>
<div class="mouse-coords">
<span></span>
<span ="mcText"></span>
</div>
</div>
</div>

含む DIV の幅と高さが固定されていれば、コンポーネント ライフサイクルの早い時点でマップ タイルをレンダリングすることが可能です。 可変の幅と高さを渡すために、アウトサイドインとインサイドアウトという 2 つのアプローチが可能です。 アウトサイドインの方法は、幅と高さのためにAngular Inputsを定義する。 親コンポーネントはマップコンポーネントに対して幅と高さを伝達する責任を負います。 インサイドアウト方式では、マップコンポーネントの内部で幅と高さを定義し、その情報をテンプレートに「渡します」。 ほとんどのアプリケーションはアウトサイドイン方式を使用しています。 このチュートリアルでは、説明のためにインサイドアウト方式を採用しています。

変数の幅と高さは、マップ レンダリングに関連するいくつかの微妙な問題を引き起こします。 リーフレットのセットアップに関連するすべてを on-init ハンドラで実行することは魅力的であり、これは一般的に固定幅と固定高さで動作します。 このチュートリアルでは、マップの幅はブラウザーのサイズによって変化するので、マップの初期化処理を on-init と after-view-init のライフサイクルハンドラで分離する方がよいでしょう。 これは、/src/app/maps/map.component.ts .

First, the identification of a containing DIV for map initialization is offloaded to a ViewChild,

@ViewChild('primaryMap', {static: true}) protected mapDivRef: ElementRef;
protected mapDiv: HTMLDivElement;

マップ設定のほとんどは ngOnInit,

Invalidating the map size is deferred to ngAfterViewInit, when the full width and height necessary for the map tiles to work is available に示されるように、ngOnInitで実行されるようにしました。 map 変数は ngOnInit ハンドラーで作成されたリーフレット マップを参照します。

public ngAfterViewInit(): void
{
this.map.invalidateSize();
this.__initMapHandlers();
}

update map size ハンドラーが、マップ DIV の幅と高さを制御する DIV スタイルにバインドされているクラスの currentWidth と currentHeight 変数を再計算することに注意してください。 Leaflet はその幅/高さの情報を使用して、マップを再タイル化および再描画します。

マップの幅/高さの定義とウィンドウ変更によるマップのサイズ変更はマップ コンポーネントの内部で処理されるので、単純なウィンドウ再サイズハンドラが追加されます。 十分な関心があれば、このテクニックを説明するチュートリアルを提供します。

マップ コントロール

Leaflet では、カスタム コントロールを使用できますが、マップ コントロールとして Angular コンポーネントを使用することもできます。 Angular コンポーネントを作成し、位置決めに CSS を使用します。 私はいくつかのプロジェクトで、高度にカスタマイズされたズーム コントロールにこれを使用しています。 出発点として使用できるスケルトンは /src/app/maps/map-control フォルダを参照してください。

関連するスタイルについては /src/app/maps/map.component.scss を参照してください。

Z-index に注意

Tiling やマップ表示の他の側面でうまくいかない場合、それは Z-index に関する問題であるかもしれません。 過去には、タイル プロバイダーを変更したり、Angular 7 から Angular 8 に移行したりするだけで、Z インデックスを再マッピングしなければなりませんでした。 座標を定義し、それぞれにリーフレット アイコンを作成します。 このチュートリアルのマーカー座標は、メイン アプリ コンポーネント

/src/app/app.component.ts

public markers: {lat: number, long: number}; // Map markers (relevance depends on map center)
constructor()
{
// some map markers
this.markers = ;
}

で定義し、Angular Input として地図コンポーネント

/src/app/app.component.ts に渡します。html

<app-map ="markers"></app-map>

マーカーは、マップ コンポーネント

/src/app/maps/map.component.ts

protected __showMarkers(): void
{
if (this.markers !== undefined && this.markers != null && this.markers.length > 0)
{
// Add markers
const icon = L.icon({
iconUrl: MapIconOptions.mapIcon,
iconSize: MapIconOptions.iconSize,
iconAnchor: MapIconOptions.iconAnchor,
shadowUrl: MapIconOptions.mapShadowIcon,
shadowSize: MapIconOptions.shadowSize,
shadowAnchor: MapIconOptions.shadowAnchor,
});
const n: number = this.markers.length;
let i: number;
let m: L.marker;
let x: number;
let y: number;
for (i = 0; i < n; ++i) {
x = this.markers.lat;
y = this.markers.long;
if (x !== undefined && !isNaN(x) && y !== undefined && !isNaN(y))
{
// okay to add the icon
m = L.marker(, {icon: icon}).addTo(this.map);
}
else
{
// implement your own error handling
console.log('MARKER ERROR, Marker number: ', (i+1), 'x: ', x, ' y: ', y);
}
}
}
}

相互作用

マウス クリックとマウス移動という基本的なマップ インタラクティブ用のいくつかのハンドラが追加されました。 後者は、マウスの位置に基づいて現在のマップの位置 (緯度/経度) を更新します。

/src/app/maps/map.component.ts

protected __onMapMouseMove(evt: any): void
{
const lat: string = evt.latlng.lat.toFixed(3);
const long: string = evt.latlng.lng.toFixed(3);
this.mcText = `Latitude: ${lat} &nbsp; &nbsp; Longitude: ${long}`;
}

現在位置を反映した文字列は、マップ コンポーネントのテンプレートに表示されます。html

<div class="mouse-coords">
<span></span>
<span ="mcText"></span>
</div>

結果

アプリケーションをビルドして、このスクリーンショットのようなものを観察することができます。

これで、Angular と Leaflet を使った作業を始めていただければと思います。 これら 2 つのアプリケーションは非常によく連動し、高度にインタラクティブで魅力的なマップの可能性は無限大です。

Angular の取り組みに幸あれ!

Angular の良さをもっと知りたい方は、The Angular Show podcast の最新エピソードをぜひチェックしてください。 ミュージカルは、2021年4月22日&23日に開催される、ng-confの人々による2日間のカンファレンスです。 ng-conf.org

でチェックしてみてください。

コメントする