cluster_marker_style 0.3.0
cluster_marker_style: ^0.3.0 copied to clipboard
Beautiful, count-aware, cached cluster marker icons for Google Maps. A drop-in styling/rendering layer for any map clustering algorithm.
cluster_marker_style #
Beautiful, count-aware, cached cluster marker icons for Google Maps — a one-line drop-in for any clustering algorithm.
This is a styling/rendering layer, not a clustering algorithm. You keep
using your clustering package of choice (e.g.
google_maps_cluster_manager_2);
this package supplies the cluster icon — rendered sharply, cached, and
good-looking by default.
GIF placeholder: clean count bubbles staying smooth while panning a dense map. Record it from the included
example/app.
The problem #
Clustering packages decide which markers group together, then hand you an
empty markerBuilder slot and walk away. To draw the cluster you end up
re-writing ~40 lines of PictureRecorder / Canvas / TextPainter
boilerplate — every project — with no caching (so the map janks on every camera
move), wrong device-pixel-ratio handling (blurry on high-DPI screens), and one
hardcoded color (a cluster of 5 looks identical to a cluster of 5000).
This is the still-open Flutter issue flutter/flutter#153092 ("Add support for custom cluster icon"). This package fills that gap.
Before / after #
| Before — ~40 lines, no cache, hardcoded | After — one line |
|---|---|
|
|
Why it's worth a dependency #
Drawing a circle is trivial. The value is everything around it that developers re-implement badly or skip:
- Caching — keyed on the visual outcome, not the raw count, so a cluster of 47 and 48 share one bitmap. This is the single biggest factor in a smooth map.
- Device-correct rendering — rasterized at native resolution via
imagePixelRatio, sharp on every screen, on Android, iOS, and web. - Count-aware defaults — color and size change with the count automatically, with zero tuning.
- Beautiful defaults — clearly better out of the box than the red/blue circle everyone hand-writes.
Quick start (with google_maps_cluster_manager_2) #
Add the dependencies:
dependencies:
cluster_marker_style: ^0.3.0
google_maps_flutter: ^2.9.0
google_maps_cluster_manager_2: ^3.0.0
Wire it up:
import 'package:cluster_marker_style/cluster_marker_style_gmcm.dart';
// 1. Pick a style and create a renderer (reuse it — it holds the cache).
final renderer = ClusterRenderer(
ClusterStyle.soft(
tiers: const [
CountTier(upTo: 10, color: Colors.blue),
CountTier(upTo: 100, color: Colors.orange),
CountTier(upTo: 1000, color: Colors.red),
],
),
);
// 2. Hand the one-line builder to your ClusterManager.
ClusterManager<Place>(
places,
_updateMarkers,
markerBuilder: clusterMarkerBuilder(
renderer: renderer,
devicePixelRatio: MediaQuery.of(context).devicePixelRatio,
onTap: (cluster) => debugPrint('Tapped ${cluster.count}'),
// singleItemBuilder: (cluster) async => ... // optional override
),
);
Omit tiers entirely to get the polished default ramp. See the runnable
example/ app, which clusters a few thousand points and switches
between styles live. (Add your own Google Maps API key — placeholders are in
example/android/.../AndroidManifest.xml and example/web/index.html.)
Named styles #
Three polished, zero-config looks that read on both light and dark maps:
| Style | Look |
|---|---|
ClusterStyle.soft() |
Cool→warm ramp, white text, thin translucent ring, soft shadow. |
ClusterStyle.flat() |
Solid Material colors, crisp, no ring or shadow. |
ClusterStyle.outlined() |
White fill with a bold count-aware colored ring + matching text. |
Each is fully overridable, or build a ClusterStyle(...) from scratch with your
own tiers, ClusterTextStyle, ClusterBorder, ClusterShadow, padding,
and CountFormatter.
Scope (and what this is not) #
This package styles cluster icons. Bring your own clustering algorithm. It is deliberately small and does exactly one thing well.
It is not a clustering algorithm, not a map widget, not an animation
system, and not a viewport/diff manager. The core renderer depends only on
google_maps_flutter (for BitmapDescriptor) — importing
package:cluster_marker_style/cluster_marker_style.dart does not pull in any
clustering package. The google_maps_cluster_manager_2 bridge lives in a
separate library
(package:cluster_marker_style/cluster_marker_style_gmcm.dart).
There's also a fluster adapter
(package:cluster_marker_style/cluster_marker_style_fluster.dart). fluster only
runs the clustering algorithm — it hands back a flat list where isCluster
marks an aggregate and gives you no rendering at all — so flusterMarkers(...)
styles + caches those aggregates and delegates individual points to your builder:
import 'package:cluster_marker_style/cluster_marker_style_fluster.dart';
final markers = await flusterClusterMarkers<MapMarker>(
fluster: fluster,
bounds: [westLng, southLat, eastLng, northLat],
zoom: zoom.round(),
renderer: clusterRenderer,
devicePixelRatio: MediaQuery.of(context).devicePixelRatio,
pointMarkerBuilder: (p) async => Marker(
markerId: MarkerId(p.markerId!),
position: LatLng(p.latitude!, p.longitude!),
),
);
More clustering-tool adapters are planned (e.g. for flutter_map clustering
tools). Because the core is independent, new adapters are thin bridges that don't
touch it.
API surface #
Core (cluster_marker_style.dart): ClusterStyle (+ .soft/.flat/.outlined),
CountTier, ClusterShape, ClusterTextStyle, ClusterBorder,
ClusterShadow, CountFormatter (+ DefaultCountFormatter), ClusterRenderer,
ClusterIconCache, ClusterCacheKey, and the tierFor / sizeFor helpers.
Adapters:
cluster_marker_style_gmcm.dart→clusterMarkerBuilder(...)forgoogle_maps_cluster_manager_2.cluster_marker_style_fluster.dart→flusterMarkers(...)/flusterClusterMarkers(...)forfluster.
License #
MIT — see LICENSE.