How to Customize Your Cluster Markers on Flutter Google Maps

Customize Your Cluster Markers on Flutter Google Maps

If you’ve been following our blog and read our recent posts about Flutter and the Google Maps package, I’m sure you now know how to cluster markers, but how do you customize or make them dynamic?

This is a follow-up article of How to Cluster Markers on Google Maps using Flutter so I will not get into the details about clustering the markers. Instead, I will tell you how I was able to customize the cluster markers by adding a dynamic child counter that updates depending on the zoom level.

This was missing in the previous article, and since some of you asked for it here I am! 😎 Without further wait, let’s get into it! 💪

So, how do you customize the markers? Unfortunately, the official Google Maps package doesn’t support clusters and the markers aren’t event widgets so we must resort to drawing on the canvas… wait! Isn’t that scary? 😱

Flutter makes it easy so it’s nothing to be afraid of. The following code contains the solution I found:

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

Future<BitmapDescriptor> getClusterMarker(
  int clusterSize,
  Color clusterColor,
  Color textColor,
  int width,
) async {
  final PictureRecorder pictureRecorder = PictureRecorder();
  final Canvas canvas = Canvas(pictureRecorder);
  final Paint paint = Paint()..color = clusterColor;
  final TextPainter textPainter = TextPainter(
    textDirection: TextDirection.ltr,
  );

  final double radius = width / 2;

  canvas.drawCircle(
    Offset(radius, radius),
    radius,
    paint,
  );

  textPainter.text = TextSpan(
    text: clusterSize.toString(),
    style: TextStyle(
      fontSize: radius - 5,
      fontWeight: FontWeight.bold,
      color: textColor,
    ),
  );

  textPainter.layout();
  textPainter.paint(
    canvas,
    Offset(
      radius - textPainter.width / 2,
      radius - textPainter.height / 2,
    ),
  );

  final image = await pictureRecorder.endRecording().toImage(
    radius.toInt() * 2,
    radius.toInt() * 2,
  );

  final data = await image.toByteData(format: ImageByteFormat.png);

  return BitmapDescriptor.fromBytes(data.buffer.asUint8List());
}

First, we set up the PictureRecorder, Canvas, Paint, and TextPainter with proper colors and text direction, then we simply get the radius and draw a circle on the canvas.

Next is the text, we want it to be the cluster size counter text and we add some style to it. In the end, we simply end the picture recorder and convert it to an image and then to a bitmap descriptor needed for the marker icon.

And that’s it! Pretty simple isn’t it? To end this article, I will tell you what more has changed from the latest How to Cluster Markers on Google Maps using Flutter post and we’re finished 🙌.

We just need to update the way we’re generating the markers like this:

return Future.wait(clusterManager.clusters(
  [-180, -85, 180, 85], currentZoom.toInt(),
).map((mapMarker) async {
  if (mapMarker.isCluster) {
    mapMarker.icon = await _getClusterMarker(
      mapMarker.pointsSize,
      Colors.blue,
      Colors.white,
      80,
    );
  }

  return mapMarker.toMarker();
}).toList());

We’re checking if the map marker is a cluster and if it is we generate the cluster icon with the updated point size to have the correct counter text inside the circle marker. We also tell it which colors we want to use and the width. Just keep in mind that this is now an async operation.

There are a few more small changes that you can see on our flutter google maps clusters repo. Go on and check it out!

Thank you for reading!

Thank you so much for reading, it means a lot to us! Also don’t forget to follow Coletiv on Twitter and LinkedIn as we keep posting more and more interesting articles on multiple technologies.

In case you don’t know, Coletiv is a software development studio from Porto specialised in Elixir, Web, and App (iOS & Android) development. But we do all kinds of stuff. We take care of UX/UI design, software development, and even security for you.

So, let’s craft something together?