今日はAngularで複数の地図を表示する方法を紹介します。
(とはいえこの方法が必要となるシチュエーションはあまりないのかなとは思います笑。が、必要となった時参考にしてください)
地図を表示したい
まず、地図を表示するにはleafletというOpenMapStreetのAngularライブラリを使います。
leafletの使い方は以下を参考にしてください。
https://qiita.com/uedayou/items/30f88d88238f648e8ee6
ここから先はleafletは使える前提で話を進めます。
複数の地図を表示する
ページに一つだけ地図を表示する場合は何も問題ありません。
上記のURLを参考に地図を表示できます。
問題は地図を複数表示する場合です。
複数の地図を表示する場合以下2つのパターンが考えられます。
- html文に<div id=”map”></map>を地図の数分追加する
- 地図を表示するコンポーネントを別で定義し、コンポーネントを地図の数分追加する
1番は大丈夫ですが、2番は工夫が必要になります。
そもそも何が問題になるかというと、leafletの以下の文
1 |
<code>this.map = L.map('map').setView([34.702485,135.495951], 13);</code> |
のmap関数の引数’map’はhtmlの「map」というidの要素を指すことです。
map関数はHTMLElement型の引数も受け取れますが、HTMLlElement型の要素は、javascript標準装備のDOM関数document.getElememntById関数でしか取得できません。
つまり、htmlのあるidと地図オブジェクトを結びつけているわけです。
idは一意なので、複数の地図を表示するにはidを地図分用意しなくてはいけません。
1番について考えてみましょう。
htmlに直接ダグを増やせる場合は問題ないですね。
1 2 3 4 5 6 7 |
<code><div id="map1"></map> <div id="map2"></map> <div id="map3"></map> <div id="map4"></map> <div id="map5"></map> <div id="map6"></map> ・・・</code> |
上記のようにidを被らないようにするだけです。
map関数も地図の数分実行します。
問題が起きるケースとは。。。
2番はどうでしょう。
以下のような構造を考えてみます。
地図を表示するコンポーネントは別で定義したい。
↓
地図を表示するコンポーネント:map.component.ts
上記コンポーネントを追加するコンポーネント:app.component.ts
↓
表示したい地図の数分app.compoennt.htmlにセレクターを追加すると表示できるはず?
map.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<code>import { Component, OnInit } from '@angular/core'; import * as L from 'leaflet'; @Component({ selector: 'map-component', template: '<div class="map" id="map"></div>' }) export class MapComponent implements OnInit { map: any; ngOnInit(){ this.map = L.map('map').setView([34.702485,135.495951], 13); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(this.map); } }</code> |
app.component.html
1 2 3 4 5 6 7 8 |
<code><div class="container"> <map-component></map-component> <map-component></map-component> <map-component></map-component> <map-component></map-component> <map-component></map-component> <map-component></map-component> </div></code> |
実行してみます。

左上の一つしか表示されていません。
これは、6つのdiv要素に同じmapというidが付けられ、6つのマップがmapというidに紐づけられているからです。
idは一意なので左上のdiv要素でidが引っかかり、他のdiv要素にマップが結びつけられなかったためだと思われます。
解決方法
map.component.tsのクラス変数(静的プロパティ)を利用する方法を紹介します。
map.component.tsに以下の赤文字部分を追加します。
map.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<code>import { Component, OnInit } from '@angular/core'; import * as L from 'leaflet'; @Component({ selector: 'map-component', template: '<div class="map" <s><span class="has-inline-color has-vivid-red-color">id="map"</span></s> ・・・①></div>' }) export class MapComponent implements OnInit { <span class="has-inline-color has-vivid-red-color"> static number: number = 0;</span> ・・・② map: any; ngOnInit(){ <span class="has-inline-color has-vivid-red-color">MapComponent.number++; </span><span class="has-inline-color has-black-color">・・・③</span><span class="has-inline-color has-vivid-red-color"> document.getElementsByClassName('map')[MapComponent.number-1].id = 'map' + MapComponent.number;</span> ・・・④ this.map = L.map('map'<span class="has-inline-color has-vivid-red-color"> + MapComponent.number</span> ・・・⑤).setView([34.702485,135.495951], 13); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(this.map); } } </code> |
①id=”map”削除
idに「map+識別番号」を割り振るので削除しておきます。
②static number: number = 0 の追加
静的プロパティを定義します。これでMapComponentのインスタンス作成時に初期化されないプロパティを使用できます。
最初は0を入れておきます。
③MapComponent.number++; の追加
ngOnInitが実行されるたび(MapComponentインスタンスが生成されるたび)に静的プロパティをインクリメント(+1すること)します。
④document.getElementsByClassName(‘map’)[MapComponent.number-1].id = ‘map’ + MapComponent.number; の追加
document.getElementsByClassName(‘map’)でmapというクラスのhtml要素を全て取得します。ここで所得される要素はElement型の配列です。Element要素はmap関数にそのままぶち込むことはできません。
取得した配列の「MapComponent.number-1」の要素のidに「map○」を設定します。(○は1から始まる整数)
①から④のコードで、
1 2 3 4 5 6 |
<code><div id="map1"></map> <div id="map2"></map> <div id="map3"></map> <div id="map4"></map> <div id="map5"></map> <div id="map6"></map></code> |
のようなidの割り振りになります。
⑤‘map’ + MapComponent.number
「map○」を指定してマップ関数を実行します。
実行結果は以下です。

6つとも地図が表示されました!(安心)
まとめ
今回複数の地図を表示する方法を紹介しました。
idを重複しないようにするというだけですが、原因がわからないと時間を食ってしまったところでもあります。
みなさんはこちら参考に好きなだけ地図を表示してもらいたいです。
ちなみに、ViewContainerRefなどで動的にMap.component.tsを追加する場合も今回のような方法で大丈夫です。

Thanks for the good article, I hope you continue to work as well.