[Android] Googleマップに表示したマーカーをまとめるマーカークラスタリング
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