この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Google Maps Android APIを利用してマップ系のアプリを作成し複数のマーカーを表示してみたけれど、ズームレベルによってはマーカーが密集して見づらくなってしまう、というようなことがあると思います。
そのようなときに使える、マーカークラスタリングについて紹介したいと思います。
Google Maps Android API Utility Library を使う
マーカークラスタリングを行うために、Google Maps Android API Utility Libraryをプロジェクトに追加します。
dependencies {
compile 'com.google.maps.android:android-maps-utils:0.4.+'
}
ちなみにGoogle Maps Android API Utility Libraryでは、マーカークラスタリングの他にもGeoJson・KMLのインポート機能やヒートマップの表示機能などがあります。(詳細はこちら)
マップにマーカーを表示する
せっかくなのでGeoJsonのインポート機能を使ってマーカーを表示してみます。以下のようなGeoJsonのサンプルデータを作成し、rawフォルダに配置します。
[geojson]
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
139.77364003658295,
35.69849264621099
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
139.77295339107513,
35.6987409627827
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
139.77405846118927,
35.697965515486835
]
}
},
︙
次に、Google Maps Android API Utility LibraryにあるGeoJsonLayerを利用してGeoJsonを読み込み、addLayerToMap()を呼ぶとマップにマーカーが表示されます。
[MainActivity.java]
private GoogleMap mMap;
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
try {
GeoJsonLayer layer = new GeoJsonLayer(mMap, R.raw.geojson, this);
layer.addLayerToMap();
} catch (IOException | JSONException e) {
e.printStackTrace();
}
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(35.69849264621099, 139.77364003658295), 16));
}
[実行例]
マーカークラスタリング
公式の手順を参考に、マーカークラスタリングを実装します。(Google Maps Android Marker Clustering Utility)
ClusterItemをimplementsしたクラスを作成
上記手順では、コンストラクタの引数が (double lat, double lng) となっていましたが、今回はGeoJsonを使用しているためGeoJsonPointを利用しました。
[MyItem.java]
public class MyItem implements ClusterItem {
private final LatLng mPosition;
public MyItem(GeoJsonPoint point) {
mPosition = point.getCoordinates();
}
@Override
public LatLng getPosition() {
return mPosition;
}
}
ClusterManagerを生成し、MyItemを追加する
先程のMainActivity.javaを以下のように変更しました。
[MainActivity.java]
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
ClusterManager<MyItem> clusterManager = createClusterManager();
mMap.setOnCameraIdleListener(clusterManager);
mMap.setOnMarkerClickListener(clusterManager);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(35.69849264621099, 139.77364003658295), 16));
}
private ClusterManager<MyItem> createClusterManager() {
ClusterManager<MyItem> manager = new ClusterManager<>(this, mMap);
try {
GeoJsonLayer layer = new GeoJsonLayer(mMap, R.raw.geojson, this);
Iterable<GeoJsonFeature> features = layer.getFeatures();
for (GeoJsonFeature feature : features) {
MyItem item = new MyItem((GeoJsonPoint) feature.getGeometry());
manager.addItem(item);
}
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return manager;
}
実行すると、ズームを変更するとマーカーがまとまるようになっていると思います。
おわりに
同様のライブラリがiOSでも提供されているので、Googleマップを採用するのであれば、同じような動作が実装可能だと思います。 Google Maps SDK for iOS Utility Library
参考
- https://developers.google.com/maps/documentation/android-api/utility/?hl=ja
- https://kagamikarasu.net/android/googlemap/geojson_clustermanager