技術情報ブログ
Angular
2021.10.27

AngularでGoogle Maps マーカークラスタリングライブラリの利用(2)

AngularでGoogle Maps マーカークラスタリングライブラリの利用(2)

こんにちは。アーティサン株式会社の木戸です。

前回に引き続き、Angular で Google Maps を利用した時の、大量のマーカー表示によるユーザーエクスペリエンスの低下を回避する方法についてご紹介します。

前編では、マーカークラスタリングライブラリの Angular への導入、設定方法等、基本的な部分に触れました。
本記事では、より実践的な内容としてクラスターマーカーの表示・非表示の切り替え、マーカーアニメーション使用時の注意点を記載致します。

Angular でマーカークラスタリングライブラリ(js-markerclustererplus)を利用し、クラスターマーカーの表示・非表示の切り替えを行いたい方に向けた記事となります。

 

Google Maps マーカークラスタリングライブラリ
(js-markerclustererplus)とは

表示されている Google Maps を一定のサイズの正方形で区切り、各正方形内に含まれているマーカーを統合し、1 つのクラスターマーカーで表示するライブラリです。

マーカーを統合して表示する事によって、ユーザーエクスペリエンスを改善する事ができます。 また、大量のマーカーを一度に扱わずにすむため、処理負荷を軽減する事もできます。

 

環境

  • Node: 14.17.0
  • npm: 6.14.13
  • Angular: 12.1.1
  • @angular/google-maps: 12.1.1
  • @googlemaps/markerclustererplus: 1.2.0
  • TypeScript: 4.3.5

 

クラスターマーカーの表示・非表示の切り替え

クラスターマーカーを表示しているコンポーネント自体に表示切り替えの設定がないため、下記の実装手順で切り替えを行います。
今回の例ではマップのクリックイベントにマーカーの表示切り替えを行う関数を設定する形で実装します。

 

実装手順

  • クラスターマーカーの ignoreHidden プロパティを true に設定
  • クラスターマーカー内にある、各マーカーコンポーネントの visible プロパティを更新
  • クラスターマーカーの repaint メソッドを呼び出す

 

クラスターマーカーに ignoreHidden を設定

ignoreHidden プロパティを true に設定します。(6 行目)

ignoreHidden とは

クラスターマーカー内にある、非表示のマーカーコンポーネント(visible プロパティが false)を無視するかどうかを設定します。
true に設定する事によって、visible プロパティが false のマーカーコンポーネントがクラスターマーカーに含まれなくなります。

<!-- sample.component.html -->
<google-map (mapClick)="toggleMarkers()">
  <map-marker-clusterer
    #markerClusterer="mapMarkerClusterer"
    imagePath="assets/images/m"
    [ignoreHidden]="true"
  >
    <ng-container *ngFor="let position of markerPositions">
      <map-marker [position]="position"></map-marker>
    </ng-container>
  </map-marker-clusterer>
</google-map>

 

クラスタマーカー内にある、各マーカーコンポーネントの visible を更新

typescript ファイル内で@ViewChild を使用し、html ファイルにある map-marker-cluster コンポーネントを取得します。(10 行目)

クラスターマーカー内にある各マーカーコンポーネントの visible プロパティを更新し、表示切り替えを行います。(15, 16 行目)

// sample.component.ts
import { Component } from "@angular/core";

@Component({
  selector: "app-sample",
  templateUrl: "./sample.component.html",
  styleUrls: ["./sample.component.scss"],
})
export class SampleComponent {
  @ViewChild("markerClusterer") markerClusterer!: MapMarkerClusterer;

  public markerPositions: google.maps.LatLngLiteral[] = [];

  public toggleMarkers(): void {
    const markers = this.markerClusterer?.markerClusterer?.getMarkers() ?? [];
    for (const marker of markers) marker.setVisible(!marker.getVisible());
    this.markerClusterer?.markerClusterer?.repaint();
  }
}

 

クラスターマーカーの repaint メソッドを呼び出す

各マーカーコンポーネントの visible プロパティ更新後、画面表示の更新をするため、repaint メソッドを呼び出します。(17 行目)

全てのマーカーを非表示にする事によって、クラスターマーカーにマーカーが含まれなくなり、画面表示の更新後クラスターマーカー自体が表示されなくなります。

下図は「repaint メソッド呼び出し前」と「repaint メソッド呼び出し後」の画像になります。

repaint メソッド呼び出し前
repaint メソッド呼び出し前
repaint メソッド呼び出し後
repaint メソッド呼び出し後
// sample.component.ts
import { Component } from "@angular/core";

@Component({
  selector: "app-sample",
  templateUrl: "./sample.component.html",
  styleUrls: ["./sample.component.scss"],
})
export class SampleComponent {
  @ViewChild("markerClusterer") markerClusterer!: MapMarkerClusterer;

  public markerPositions: google.maps.LatLngLiteral[] = [];

  public toggleMarkers(): void {
    const markers = this.markerClusterer?.markerClusterer?.getMarkers() ?? [];
    for (const marker of markers) marker.setVisible(!marker.getVisible());
    this.markerClusterer?.markerClusterer?.repaint();
  }
}

 

マーカーアニメーション使用時の注意点

マーカーアニメーションを利用している場合に visible プロパティの変更や、クラスタリングライブラリを利用してクラスターマーカーとの表示切り替えを行うと、再表示時にアニメーションが再生されません。

そのため、下記のような形で明示的にアニメーションを再設定する必要があります。

 

マーカーアニメーションとは

マーカーコンポーネントの options.animation プロパティにgoogle.maps.Animation.BOUNCE等の値を代入することにより、マーカーをアニメーションさせる機能です。

google.maps.Animation.BOUNCEを代入した場合、マーカーが上下に動きます。

 

実装手順

  • マーカーコンポーネントの visibleChanged イベント、クラスターマーカーコンポーネントの clusteringend イベントにアニメーションを再設定する関数を設定
  • 設定した関数内で setAnimation メソッドを呼び出す

 

マーカーコンポーネントの visibleChanged イベント、クラスターマーカーコンポーネントの clusteringend イベントに関数を設定

visibleChanged イベント、clusteringend イベントにアニメーションを再設定する関数を呼び出す処理を設定します。(7、13 行目)

visible プロパティが変更される、またはクラスタリングの処理が終了した際に、設定した関数が呼び出されます。

<!-- sample.component.html -->
<google-map>
  <map-marker-clusterer
    #markerClusterer="mapMarkerClusterer"
    imagePath="assets/images/m"
    [ignoreHidden]="true"
    (clusteringend)="setMarkersAnimation()"
  >
    <ng-container *ngFor="let position of markerPositions">
      <map-marker
        #marker="mapMarker"
        [position]="position"
        (visibleChanged)="setMarkerAnimation(marker)"
      ></map-marker>
    </ng-container>
  </map-marker-clusterer>
</google-map>

 

設定した関数内で setAnimation メソッドを呼び出す

typescript ファイル内で@ViewChild を使用し、html ファイルにある map-marker コンポーネント、map-marker-clusterer コンポーネントを取得します。(10、11 行目)

マーカーに対して setAnimation メソッドを呼び出し、アニメーションを再設定します。(16、22 行目)

// sample.component.ts
import { Component } from "@angular/core";

@Component({
  selector: "app-sample",
  templateUrl: "./sample.component.html",
  styleUrls: ["./sample.component.scss"],
})
export class SampleComponent {
  @ViewChild("markerClusterer") markerClusterer!: MapMarkerClusterer;
  @ViewChild("mapMarker") marker!: MapMarker;

  public markerPositions: google.maps.LatLngLiteral[] = [];

  public setMarkerAnimation(marker: MapMarker): void {
    this.marker.marker?.setAnimation(google.maps.Animation.BOUNCE);
  }

  public setMarkersAnimation(): void {
    const markers = this.markerClusterer?.markerClusterer?.getMarkers() ?? [];
    for (const marker of markers)
      marker.setAnimation(google.maps.Animation.BOUNCE);
  }
}

 

あとがき

本記事でご紹介した設定以外にクラスターマーカーのフォント等、表示面でも細かく設定することが可能です。 下記関連リンクのClusterIconStyleから確認できますので、ぜひ試してみて下さい。

 

にTypeScriptでのフロントエンド開発を担当:木戸裕貴

木戸裕貴

私は主にTypeScriptでのフロントエンド開発を担当しております。

シェアする
記事カテゴリ
最新記事
2024.04.17

Power Apps・Power Automateの勉強方法(1)

2024.04.03

非エンジニア【(元)自治体職員】が半年間ローコード開発をしてみたら

2024.03.27

Power Automateのベストプラクティス・アンチパターン(5)【Apply to each×コンカレンシー×変数の設定はNG】

2024.03.20

Power Apps×Teams:Teams上からPower Appsを実行する方法

2024.03.13

Power Apps:SharePointリストと連携したカレンダーアプリを自作してみよう

モデル駆動型アプリPower AppsPower PlatformSharePointExcelPower AutomateC#attributevalidationローコードAngularAccessInfoPathMatTableAngular Materialデータ構造SortByColumns関数TypeScriptHTMLEF CoreマイグレーションFramework CoreAttribute directivesO/Rマッパーazure sql databaseCase式HTTP RequestCSSxUnit.Net Core 3.1VSCode.Net Core Test ExplorerDataverse for Teamsitem関数Google MapsMarker ClustererRANK()関数Dynamics 365 SalesMicrosoft TranslatorマーカークラスタリングライブラリtailwindcssマルチテナントドロップダウンメニューBreakpointObserverメディアクエリスマホPCレスポンシブ入門初心者中級者キャンバスアプリDatePickerDropdownviewビューアクセス制限承認リマインドSetForAllUpdateContextロードマップ技術It情報技術メッセージIDメールfirst()関数nest入れ子動的リストcollectionコレクション複数の添付ファイル承認フローformエクスポートインポートカスタマイズcomponentダイアログコンポーネントdialogTips新機能変数検索Microsoft 365グループセキュリティグループ送信元メールの送信差出人インスタントクラウドフロー自動化したクラウドフロー委任VBAエラーエクセルerror復元restorePower BI個人列ユーザー列SharePoint Onlineリスト非表示アプリ[市民開発者構築自動化したクラウド フローフローの種類インスタント クラウド フロースケジュール済みクラウド フローレスポンシブ レイアウトresponsive layoutデータ行の制限引き継ぎ退職所有者を変更異動LoopMicrosoftdesignJSONデザインtemplateテンプレート運用選択肢列参照列ChatGPTOpenAIオープンAIチャットGPTgalleryギャラリースクロールコンテナショートカットキーshortcut keyconcat関数文字制限フロー実行開発環境環境本番環境ライセンス環境構築手順pipelineCI/CDパイプラインDevOpsMicrosoft 365簡易在庫管理時間外通知ファイルフィルター クエリドキュメント ライブラリfilter querysortソートmultiple item複数項目シェアポイント便利機能カレンダーCalendarTeamsローコード開発非エンジニア体験談勉強内製化
PageTop
ページトップに戻る