2022-03-18
クラスターを自分好みにしたい時は、osmbonuspackで提供されているMarkerClustererを継承した
サブクラスを使うことでクラスターの画像をカスタマイズすることができます。
必要なもの
変数:ズームレベル、クラスターに表示するテキスト、マーカー等
protected int mMaxClusteringZoomLevel = 17; protected int mRadiusInPixels = 100; protected double mRadiusInMeters; protected Paint mTextPaint; private ArrayList<Marker> mClonedMarkers; /** cluster icon anchor */ public float mAnchorU = Marker.ANCHOR_CENTER, mAnchorV = Marker.ANCHOR_CENTER; /** anchor point to draw the number of markers inside the cluster icon */ public float mTextAnchorU = Marker.ANCHOR_CENTER, mTextAnchorV = Marker.ANCHOR_CENTER;
コンストラクタ(値の初期値)
テキストに表示する基本データになります。osmdroidを使ったことがある人なら
すぐ分かるはずw
public CustomMarkerClusterer(Context ctx) { super(); mTextPaint = new Paint(); mTextPaint.setColor(Color.BLACK); mTextPaint.setTextSize(40.0f); mTextPaint.setFakeBoldText(true); mTextPaint.setTextAlign(Paint.Align.CENTER); mTextPaint.setAntiAlias(true); }
buildClusterMarkerメソッド
クラスターをカスタマイズためのポイントがこのメソッドです。
引数として取れるgetSize()から取得したマーカーの集まりが取得できるので
この数に応じてクラスターの種類を切り替えることができます。
osmbonuspackのgitにMarkerClustererの基本メソッドがあるので
最初はそれを丸ごとコピーして後にcluster.getSize()などを使って
臨機応変にクラスターを変更するというのが主な動きになります。
@Override public Marker buildClusterMarker(StaticCluster cluster, MapView mapView) { Marker m = new Marker(mapView); m.setPosition(cluster.getPosition()); m.setInfoWindow(null); m.setAnchor(mAnchorU, mAnchorV); Bitmap icon = null; if (cluster.getSize() < 10 && cluster.getSize() >= 5) { Drawable clusterIconD = mapView.getContext().getResources().getDrawable(R.drawable.yellowmarker); icon = ((BitmapDrawable) clusterIconD).getBitmap(); } else if(cluster.getSize() >= 10){ Drawable clusterIconD = mapView.getContext().getResources().getDrawable(R.drawable.orangemarker); icon = ((BitmapDrawable) clusterIconD).getBitmap(); } else { Drawable clusterIconD = mapView.getContext().getResources().getDrawable(R.drawable.greenmarker); icon = ((BitmapDrawable) clusterIconD).getBitmap(); } Bitmap mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true); Canvas iconCanvas = new Canvas(mutableBitmap); String text = "" + cluster.getSize(); int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent()); iconCanvas.drawText(text, mTextAnchorU * icon.getWidth(), mTextAnchorV * icon.getHeight() - textHeight / 2, mTextPaint); m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap)); return m; }
全体のコードはこちら。
public class CustomMarkerClusterer extends MarkerClusterer { protected int mMaxClusteringZoomLevel = 17; protected int mRadiusInPixels = 100; protected double mRadiusInMeters; protected Paint mTextPaint; private ArrayList<Marker> mClonedMarkers; /** cluster icon anchor */ public float mAnchorU = Marker.ANCHOR_CENTER, mAnchorV = Marker.ANCHOR_CENTER; /** anchor point to draw the number of markers inside the cluster icon */ public float mTextAnchorU = Marker.ANCHOR_CENTER, mTextAnchorV = Marker.ANCHOR_CENTER; public CustomMarkerClusterer(Context ctx) { super(); mTextPaint = new Paint(); mTextPaint.setColor(Color.BLACK); mTextPaint.setTextSize(40.0f); mTextPaint.setFakeBoldText(true); mTextPaint.setTextAlign(Paint.Align.CENTER); mTextPaint.setAntiAlias(true); } /** If you want to change the default text paint (color, size, font) */ public Paint getTextPaint(){ return mTextPaint; } /** Set the radius of clustering in pixels. Default is 100px. */ public void setRadius(int radius){ mRadiusInPixels = radius; } /** Set max zoom level with clustering. When zoom is higher or equal to this level, clustering is disabled. * You can put a high value to disable this feature. */ public void setMaxClusteringZoomLevel(int zoom){ mMaxClusteringZoomLevel = zoom; } @Override public ArrayList<StaticCluster> clusterer(MapView mapView) { ArrayList<StaticCluster> clusters = new ArrayList<StaticCluster>(); convertRadiusToMeters(mapView); mClonedMarkers = new ArrayList<Marker>(mItems); //shallow copy while (!mClonedMarkers.isEmpty()) { Marker m = mClonedMarkers.get(0); StaticCluster cluster = createCluster(m, mapView); clusters.add(cluster); } return clusters; } private StaticCluster createCluster(Marker m, MapView mapView) { GeoPoint clusterPosition = m.getPosition(); StaticCluster cluster = new StaticCluster(clusterPosition); cluster.add(m); mClonedMarkers.remove(m); if (mapView.getZoomLevel() > mMaxClusteringZoomLevel) { //above max level => block clustering: return cluster; } Iterator<Marker> it = mClonedMarkers.iterator(); while (it.hasNext()) { Marker neighbour = it.next(); int distance = (int) clusterPosition.distanceToAsDouble(neighbour.getPosition()); if (distance <= mRadiusInMeters) { cluster.add(neighbour); it.remove(); } } return cluster; } @Override public Marker buildClusterMarker(StaticCluster cluster, MapView mapView) { Marker m = new Marker(mapView); m.setPosition(cluster.getPosition()); m.setInfoWindow(null); m.setAnchor(mAnchorU, mAnchorV); Bitmap icon = null; if (cluster.getSize() < 10 && cluster.getSize() >= 5) { Drawable clusterIconD = mapView.getContext().getResources().getDrawable(R.drawable.yellowmarker); icon = ((BitmapDrawable) clusterIconD).getBitmap(); } else if(cluster.getSize() >= 10){ Drawable clusterIconD = mapView.getContext().getResources().getDrawable(R.drawable.orangemarker); icon = ((BitmapDrawable) clusterIconD).getBitmap(); } else { Drawable clusterIconD = mapView.getContext().getResources().getDrawable(R.drawable.greenmarker); icon = ((BitmapDrawable) clusterIconD).getBitmap(); } Bitmap mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true); Canvas iconCanvas = new Canvas(mutableBitmap); String text = "" + cluster.getSize(); int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent()); iconCanvas.drawText(text, mTextAnchorU * icon.getWidth(), mTextAnchorV * icon.getHeight() - textHeight / 2, mTextPaint); m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap)); return m; } @Override public void renderer(ArrayList<StaticCluster> clusters, Canvas canvas, MapView mapView) { for (StaticCluster cluster : clusters) { if (cluster.getSize() == 1) { //cluster has only 1 marker => use it as it is: cluster.setMarker(cluster.getItem(0)); } else { //only draw 1 Marker at Cluster center, displaying number of Markers contained Marker m = buildClusterMarker(cluster, mapView); cluster.setMarker(m); } } } private void convertRadiusToMeters(MapView mapView) { Rect mScreenRect = mapView.getIntrinsicScreenRect(null); int screenWidth = mScreenRect.right - mScreenRect.left; int screenHeight = mScreenRect.bottom - mScreenRect.top; BoundingBox bb = mapView.getBoundingBox(); double diagonalInMeters = bb.getDiagonalLengthInMeters(); double diagonalInPixels = Math.sqrt(screenWidth * screenWidth + screenHeight * screenHeight); double metersInPixel = diagonalInMeters / diagonalInPixels; mRadiusInMeters = mRadiusInPixels * metersInPixel; } }