GoogleMapに0個~1000個のマーカー設置を切り替えるのをマーカーの追加/削除で対応していたらクラスターの再描画が重くて使い物にならなかったのでその対応方法。
結論
- マーカーの表示/消去はマーカーの追加/削除ではなくvisibleプロパティを使用する。
- クラスターにはignoreHidden=trueを設定する。
環境
- Angular: 12.2.0
- @agm/core: 3.0.0-beta.0
- @agm/markercluster: 3.0.0-beta.0
- @google/markerclusterplus
修正概要
改善前
<agm-map [latitude]="lat" [longitude]="lng" [zoom]="zoom" [minZoom]="minZoom" [maxZoom]="maxZoom">
<agm-marker-cluster imagePath="(クラスタ画像パス)">
<agm-marker *ngFor="let marker of markerList" [latitude]="marker.lat" [longitude]="marker.lng" iconUrl="(マーカー画像パス)"></agm-marker>
</agm-marker-cluster>
</agm-map>
改善前は*ngFor
でマーカー一覧(markerList
)を設定しており表示対象の項目が変わるたびに全マーカー一覧からfilter()
で絞った結果をmarkerList
に設定していた。
この場合markerList
が再設定されるたびに<agm-marker>
のDOMが再構築され、それをトリガーにGoogleMap上に実際に表示されているクラスターのDOMが再構築されるのだが<agm-marker>
が構築/削除されるたびにクラスター描画が行われているのか15秒程度GoogleMapが固まりさらにクラスター表示も一時的に変に重なったりして非常に重い。
改善後
マーカー一覧(markerList
)の再設定をしてはいけないことが分かったのでmarkerList
には全マーカー一覧をまず設定しておく。
そのうえで表示するマーカーにはvisible=true
、表示しないマーカーにはvisible=false
を設定し、クラスター側でもignoreHidden=true
を設定することでvisible=false
のマーカーをクラスター対象外にする。
※表示するマーカー一覧を変更するときはmarkerList
の配列インスタンスを変えずにvisible
プロパティのみを書き換える。
<agm-map [latitude]="lat" [longitude]="lng" [zoom]="zoom" [minZoom]="minZoom" [maxZoom]="maxZoom">
<agm-marker-cluster imagePath="(クラスタ画像パス)" [ignoreHidden]="true">
<agm-marker *ngFor="let marker of markerList" [latitude]="marker.lat" [longitude]="marker.lng" iconUrl="(マーカー画像パス)" [visible]="marker.visible"></agm-marker>
</agm-marker-cluster>
</agm-map>
https://angular-maps.com/api-docs/agm-core/directives/agmmarker#visible
https://angular-maps.com/api-docs/markerclusterer/directives/agmmarkercluster#ignoreHidden
こうすることで<agm-marker>
のDOM再構築がなくなるのでクラスターの再描画回数が減り問題ないレベルになった。
ただし、マーカーのvisibleを変更したらMarkerClusterer.repaint().
もコールするようにと上記ドキュメントに記載されているが<agm-marker-cluster>
ディレクティブのインスタンスをコンポーネント側でどうやって取得するのかがいまだ不明※。
そのため、クラスター画像の更新がされないのでZoom値を強制的に変えるなりして強制再描画を行っている。
※ClusterManagerをDIしてgetClustererInstance()
で取得できそうだったが取得しても別のインスタンスっぽくてrepaint()しても再描画されなかったがやり方がよくなかったか。。
https://angular-maps.com/api-docs/markerclusterer/injectables/clustermanager#getClustererInstance
まあ、使用しているAgmMapライブラリは2年近くアップデートされていないのでこちらより@angular/google-maps
を使用したほうがよいとは思う。
以下のサイトは大変参考になりました。上記のライブラリを使っているようでrepaint()も実施できている模様。