In V1 of Google Maps for Android I implemented a form of clustering using the ItemizedOverlay class. Each cluster has a center point (lat/lon), radius (in miles) and a count of the number of items in the cluster. I used ItemizedOverlay.draw(Canvas, MapView, shadow) to draw the clusters using Canvas object methods such as drawCircle() and drawText(). Each cluster consisted of a filled circle (sized according to the space required for the count) containing the count and a circle showing the radius.
After reading the docs on V2 and playing with the demo app, I see no equivalent to ItemizedOverlay, and no obvious alternative. I suspect that the only way to do this is to maintain a list of clusters myself, and then subclass MapView and provide an implementation of its onDraw() method.
Have I missed something in the V2 API that would be better than subclassing MapView?
Thanks,
Mark
July 18, 2022 The Maps SDK for Android version 18.1. 0 is now available. See the Release Notes for information about this release and for all previous releases. If you are a new user, see Set Up in the Google Cloud Console to start the installation process.
With the Maps SDK for Android, add maps to your Android app including Wear OS apps using Google Maps data, map displays, and map gesture responses. You can also provide additional information for map locations and support user interaction by adding markers, polygons, and overlays to your map.
After some research, I haven't found any better option than creating Bitmap for Marker on the fly either. But I'm also creating circle with polygon on the map. Be aware that this is not really high-performance solution, but for my case it is a decent option. Code sample:
private static final int CIRCLE_POLYGON_VERTICES = 16;
private static final double EARTH_RADIUS = 6378.1d;
private List<LatLng> createCirclePolygon(LatLng center, double r) {
List<LatLng> res = new ArrayList<LatLng>(CIRCLE_POLYGON_VERTICES);
double r_latitude = MathUtils.rad2deg(r/EARTH_RADIUS);
double r_longitude = r_latitude / Math.cos(MathUtils.deg2rad(center.latitude));
for (int point = 0; point < CIRCLE_POLYGON_VERTICES + 1; point++) {
double theta = Math.PI * ((double)point / (CIRCLE_POLYGON_VERTICES / 2));
double circle_x = center.longitude + (r_longitude * Math.cos(theta));
double circle_y = center.latitude + (r_latitude * Math.sin(theta));
res.add(new LatLng(circle_y, circle_x));
}
return res;
}
private Bitmap getClusteredLabel(String cnt, Context ctx) {
Resources r = ctx.getResources();
Bitmap res = BitmapFactory.decodeResource(r, R.drawable.map_cluster_bg);
res = res.copy(Bitmap.Config.ARGB_8888, true);
Canvas c = new Canvas(res);
Paint textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setTypeface(Typeface.DEFAULT_BOLD);
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(21);
c.drawText(String.valueOf(cnt), res.getWidth()/2, res.getHeight()/2 + textPaint.getTextSize() / 3, textPaint);
return res;
}
public void createClusteredOverlay(MapPinData point, GoogleMap map, Context ctx) {
if (point.getCount() > 1) {
map.addMarker(new MarkerOptions().position(point.getLatLng()).anchor(0.5f, 0.5f).icon(BitmapDescriptorFactory.fromBitmap(getClusteredLabel(String.valueOf(point.getCount()), ctx))));
map.addPolygon(new PolygonOptions()
.addAll(createCirclePolygon(point.getLatLng(), point.getRadius()))
.fillColor(Color.argb(50, 0, 0, 10))
.strokeWidth(0)
);
} else {
map.addMarker(new MarkerOptions().position(point.getLatLng()).title(point.getTitle()));
}
}
My MathUtils methods:
public static double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
}
public static double rad2deg(double rad) {
return (rad * 180.0 / Math.PI);
}
If you have radius in miles, you should change EARTH_RADIUS constant to miles, 3963 AFAIK.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With