Google マップ Android マーカー クラスタリング ユーティリティ

マーカーをクラスタリングすることで、マップを見づらくすることなく、マップ上に多数のマーカーを配置できます。

はじめに

このビデオでは、マップ上に多数のデータポイントが必要な場合のマーカー クラスリングの使用について説明しています。

マーカー クラスタリング ユーティリティを使うと、異なるズームレベルにある複数のマーカーを管理できます。正確には、「マーカー」はこの時点では実際には「アイテム」で、レンダリングされるときに初めて「マーカー」になります。ただし、わかりやすくするために、このドキュメントでは一貫してこれらを「マーカー」と呼びます。

ユーザーが高いズームレベルでマップを表示すると、個別のマーカーがマップ上に表示されます。ユーザーがズームアウトすると、マーカーがまとまってクラスタになり、マップが見やすくなります。マーカー クラスタリング ユーティリティは、Maps SDK for Android ユーティリティ ライブラリに含まれています。ライブラリをまだセットアップしていない場合は、このページの残りを読む前に、設定ガイドに従ってセットアップしてください。

クラスタリングされたマーカーのあるマップ
クラスタリングされたマーカー

マーカー クラスタリング ユーティリティを使用するには、マーカーを ClusterItem オブジェクトとして ClusterManager に追加します。ClusterManager はマーカーを Algorithm に渡し、これによりマーカーが一連のクラスタに変換されます。ClusterRenderer は、クラスタと個別のマーカーを追加および削除することで、レンダリングを行います。ClusterRendererAlgorithm はプラグ可能で、カスタマイズできます。

ユーティリティ ライブラリには、マーカー クラスタリング ユーティリティのサンプル実装を提供するデモアプリが付属しています。デモアプリの実行方法については、設定ガイドをご覧ください。デモアプリには、次のマーカー クラスタリング サンプルが含まれています。

  • ClusteringDemoActivity: マーカー クラスタリングを示す単純なアクティビティ。
  • BigClusteringDemoActivity: 2,000 個のマーカーのクラスタリング。
  • CustomMarkerClusteringDemoActivity: クラスタリングされたマーカーのカスタム デザインの作成。

単純なマーカー クラスタを追加する

次のステップに従って、10 個のマーカーからなる単純なクラスタを作成します。結果は以下のようになります。ただし、表示またはクラスタリングされているマーカーの数は、ズームレベルによって異なります。

クラスタリングされた 10 個のマーカーを含むマップ
クラスタリングされた 10 個のマーカー

必要なステップの概要は次のとおりです。

  1. マップ上のマーカーを表すために、ClusterItem を実装します。クラスタ アイテムにより、マーカーの位置が LatLng オブジェクトとして返され、必要に応じてタイトルまたはスニペットが返されます。
  2. ズームレベルに基づいてクラスタ アイテム(マーカー)をグループ化するために、新しい ClusterManager を追加します。
  3. ClusterManager はリスナーを実装するため、マップの OnCameraIdleListener()ClusterManager に設定します。
  4. マーカー クリック イベントへのレスポンスで特定の機能を追加する場合は、マップの OnMarkerClickListener()ClusterManager に設定します。これは、ClusterManager がリスナーを実装するためです。
  5. マーカーを ClusterManager に入力します。

次に、各ステップの詳細を示します。10 個のマーカーからなる単純なクラスタを作成するには、まず、ClusterItem を実装する MyItem クラスを作成します。

Java

public class MyItem implements ClusterItem {
    private final LatLng position;
    private final String title;
    private final String snippet;

    public MyItem(double lat, double lng, String title, String snippet) {
        position = new LatLng(lat, lng);
        this.title = title;
        this.snippet = snippet;
    }

    @Override
    public LatLng getPosition() {
        return position;
    }

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public String getSnippet() {
        return snippet;
    }
}
      

Kotlin

inner class MyItem(
    lat: Double,
    lng: Double,
    title: String,
    snippet: String
) : ClusterItem {

    private val position: LatLng
    private val title: String
    private val snippet: String

    override fun getPosition(): LatLng {
        return position
    }

    override fun getTitle(): String? {
        return title
    }

    override fun getSnippet(): String? {
        return snippet
    }

    init {
        position = LatLng(lat, lng)
        this.title = title
        this.snippet = snippet
    }
}
      

マップのアクティビティで、ClusterManager を追加し、これにクラスタ アイテムを入力します。ClusterManagerMyItem 型であることを宣言する型引数 <MyItem> に注目してください。

Java

// Declare a variable for the cluster manager.
private ClusterManager<MyItem> clusterManager;

private void setUpClusterer() {
    // Position the map.
    map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.503186, -0.126446), 10));

    // Initialize the manager with the context and the map.
    // (Activity extends context, so we can pass 'this' in the constructor.)
    clusterManager = new ClusterManager<MyItem>(context, map);

    // Point the map's listeners at the listeners implemented by the cluster
    // manager.
    map.setOnCameraIdleListener(clusterManager);
    map.setOnMarkerClickListener(clusterManager);

    // Add cluster items (markers) to the cluster manager.
    addItems();
}

private void addItems() {

    // Set some lat/lng coordinates to start with.
    double lat = 51.5145160;
    double lng = -0.1270060;

    // Add ten cluster items in close proximity, for purposes of this example.
    for (int i = 0; i < 10; i++) {
        double offset = i / 60d;
        lat = lat + offset;
        lng = lng + offset;
        MyItem offsetItem = new MyItem(lat, lng, "Title " + i, "Snippet " + i);
        clusterManager.addItem(offsetItem);
    }
}
      

Kotlin

// Declare a variable for the cluster manager.
private lateinit var clusterManager: ClusterManager<MyItem>

private fun setUpClusterer() {
    // Position the map.
    map.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(51.503186, -0.126446), 10f))

    // Initialize the manager with the context and the map.
    // (Activity extends context, so we can pass 'this' in the constructor.)
    clusterManager = ClusterManager(context, map)

    // Point the map's listeners at the listeners implemented by the cluster
    // manager.
    map.setOnCameraIdleListener(clusterManager)
    map.setOnMarkerClickListener(clusterManager)

    // Add cluster items (markers) to the cluster manager.
    addItems()
}

private fun addItems() {

    // Set some lat/lng coordinates to start with.
    var lat = 51.5145160
    var lng = -0.1270060

    // Add ten cluster items in close proximity, for purposes of this example.
    for (i in 0..9) {
        val offset = i / 60.0
        lat += offset
        lng += offset
        val offsetItem =
            MyItem(lat, lng, "Title $i", "Snippet $i")
        clusterManager.addItem(offsetItem)
    }
}
      

ズームインとズームアウト時のクラスタリング アニメーションを無効にすることもできます。 アニメーションをオフにすると、クラスタへの移行が切り替わるのではなく、マーカーが所定の位置に切り替わります。 アニメーションを無効にするには、以下のように ClusterManagersetAnimation() を使用します。

Java

clusterManager.setAnimation(false);
      

Kotlin

clusterManager.setAnimation(false)
      

クラスタ化した個別のマーカー用の情報ウィンドウを追加する

クラスタ化した特定のマーカー用の情報ウィンドウを追加するには、ClusterItem の実装のコンストラクタにタイトルとスニペットの文字列を追加します。

以下の例では、タイトルとスニペットを設定して、情報ウィンドウを含むマーカーを addItems() メソッドに追加しています。

Java

// Set the lat/long coordinates for the marker.
double lat = 51.5009;
double lng = -0.122;

// Set the title and snippet strings.
String title = "This is the title";
String snippet = "and this is the snippet.";

// Create a cluster item for the marker and set the title and snippet using the constructor.
MyItem infoWindowItem = new MyItem(lat, lng, title, snippet);

// Add the cluster item (marker) to the cluster manager.
clusterManager.addItem(infoWindowItem);
      

Kotlin

// Set the lat/long coordinates for the marker.
val lat = 51.5009
val lng = -0.122

// Set the title and snippet strings.
val title = "This is the title"
val snippet = "and this is the snippet."

// Create a cluster item for the marker and set the title and snippet using the constructor.
val infoWindowItem = MyItem(lat, lng, title, snippet)

// Add the cluster item (marker) to the cluster manager.
clusterManager.addItem(infoWindowItem)
      

マーカー クラスタをカスタマイズする

ClusterManager コンストラクタでは DefaultClusterRendererNonHierarchicalDistanceBasedAlgorithm を作成します。ClusterRendererAlgorithm は、ClusterManagersetAlgorithm(Algorithm<T> algorithm) メソッドと setRenderer(ClusterRenderer<T> view) メソッドを使って変更できます。

ClusterRenderer を実装すると、クラスタのレンダリングをカスタマイズできます。DefaultClusterRenderer は、開始点として適しています。DefaultClusterRenderer をサブクラス化することで、デフォルトをオーバーライドできます。

カスタマイズの詳細な例については、ユーティリティ ライブラリに付属のデモアプリにある CustomMarkerClusteringDemoActivity をご覧ください。

クラスタリングされたカスタム マーカーを含むマップ
クラスタリングされたカスタム マーカー

CustomMarkerClusteringDemoActivity は独自のクラスタ アイテムである Person を定義し、DefaultClusterRendererPersonRenderer として拡張することで、このアイテムをレンダリングします。

デモでは、ClusterManager.OnClusterClickListener<Person> インターフェースを実装して、クラスタがクリックされたときに、その人に関する詳細情報を表示する方法も示されています。ClusterManager.OnClusterItemClickListener<Person> も同様の方法で実装できます。

デモアプリの実行方法については、設定ガイドをご覧ください。