### Initialize ClusterManager with Minimal Setup Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Create a typed cluster manager with initial items and a callback for marker updates. This is the most basic configuration. ```dart import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart'; late ClusterManager _manager; // Minimal setup _manager = ClusterManager( items, // Iterable — initial set of items to cluster _updateMarkers, // void Function(Set) — called whenever clusters recompute ); void _updateMarkers(Set markers) { setState(() => this.markers = markers); } ``` -------------------------------- ### Define a Place item with ClusterItem mixin Source: https://github.com/bpillon/google_maps_cluster_manager/blob/master/README.md Items to be clustered must implement the `ClusterItem` mixin and provide a `LatLng location` getter. This example shows a `Place` class with a `name` and `latLng`. ```dart class Place with ClusterItem { final String name; final LatLng latLng; Place({required this.name, required this.latLng}); @override LatLng get location => latLng; } ``` -------------------------------- ### Custom Cluster Marker Builder Source: https://github.com/bpillon/google_maps_cluster_manager/blob/master/README.md Define a `markerBuilder` function to customize the appearance of cluster markers. This example shows how to create a circular marker with an optional count for multiple items. ```dart static Future Function(Cluster) get markerBuilder => (cluster) async { return Marker( markerId: MarkerId(cluster.getId()), position: cluster.location, onTap: () { print(cluster.items); }, icon: await getClusterBitmap(cluster.isMultiple ? 125 : 75, text: cluster.isMultiple? cluster.count.toString() : null), ); }; ``` ```dart static Future getClusterBitmap(int size, {String text?}) async { final PictureRecorder pictureRecorder = PictureRecorder(); final Canvas canvas = Canvas(pictureRecorder); final Paint paint1 = Paint()..color = Colors.red; canvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, paint1); if (text != null) { TextPainter painter = TextPainter(textDirection: TextDirection.ltr); painter.text = TextSpan( text: text, style: TextStyle( fontSize: size / 3, color: Colors.white, fontWeight: FontWeight.normal), ); painter.layout(); painter.paint( canvas, Offset(size / 2 - painter.width / 2, size / 2 - painter.height / 2), ); } final img = await pictureRecorder.endRecording().toImage(size, size); final data = await img.toByteData(format: ImageByteFormat.png); return BitmapDescriptor.fromBytes(data.buffer.asUint8List()); } ``` -------------------------------- ### ClusterItem Mixin Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Apply the `ClusterItem` mixin to your data models to make them clusterable. You must implement the `LatLng get location` getter. The geohash is computed lazily and cached. ```APIDOC ## ClusterItem Mixin ### Description Apply `ClusterItem` as a mixin (or extend it) on any data class and implement the `LatLng get location` getter. The geohash string is computed lazily and cached on first access. ### Usage Example ```dart import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; class Place with ClusterItem { final String name; final bool isClosed; final LatLng latLng; Place({required this.name, required this.latLng, this.isClosed = false}); @override LatLng get location => latLng; // required — tells the library where this item is @override String toString() => 'Place $name (closed: $isClosed)'; } final place = Place(name: 'Eiffel Tower', latLng: LatLng(48.8584, 2.2945)); print(place.location); // LatLng(latitude: 48.8584, longitude: 2.2945) print(place.geohash); // e.g. "u09tunquc0" (auto-computed, precision 20 on native) ``` ``` -------------------------------- ### Initialize ClusterManager with Full Configuration Options Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Configure advanced options like custom marker builders, zoom levels, clustering algorithms, and parameters for the MAX_DIST algorithm. ```dart import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart'; late ClusterManager _manager; // Full setup with all options _manager = ClusterManager( items, _updateMarkers, markerBuilder: _markerBuilder, // Future Function(Cluster) — custom marker appearance levels: [1, 4.25, 6.75, 8.25, 11.5, 14.5, 16.0, 16.5, 20.0], // zoom breakpoints extraPercent: 0.2, // render 20% beyond visible bounds to avoid pop-in stopClusteringZoom: 17.0, // above this zoom, each item gets its own marker clusterAlgorithm: ClusterAlgorithm.GEOHASH, // or ClusterAlgorithm.MAX_DIST maxItemsForMaxDistAlgo: 200, // switch from MAX_DIST to GEOHASH above this count maxDistParams: MaxDistParams(20), // epsilon (pixels) for MAX_DIST algorithm ); void _updateMarkers(Set markers) { setState(() => this.markers = markers); } ``` -------------------------------- ### Initialize ClusterManager Source: https://github.com/bpillon/google_maps_cluster_manager/blob/master/README.md Initialize a `ClusterManager` instance with your items, a method to update markers, and optional parameters for customization. The `markerBuilder` can be used to customize cluster icons. ```dart ClusterManager( _items, // Your items to be clustered on the map (of Place type for this example) _updateMarkers, // Method to be called when markers are updated markerBuilder: _markerBuilder, // Optional : Method to implement if you want to customize markers levels: [1, 4.25, 6.75, 8.25, 11.5, 14.5, 16.0, 16.5, 20.0], // Optional : Configure this if you want to change zoom levels at which the clustering precision change extraPercent: 0.2, // Optional : This number represents the percentage (0.2 for 20%) of latitude and longitude (in each direction) to be considered on top of the visible map bounds to render clusters. This way, clusters don't "pop out" when you cross the map. stopClusteringZoom: 17.0 // Optional : The zoom level to stop clustering, so it's only rendering single item "clusters" ); ``` -------------------------------- ### ClusterManager Constructor Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt The `ClusterManager` is the main entry point for clustering. It takes an iterable of clusterable items and a callback function to update markers. Various optional parameters allow for customization of clustering behavior and appearance. ```APIDOC ## ClusterManager Constructor ### Description The main entry point. Creates a typed cluster manager for items of type `T extends ClusterItem`. All parameters after the first two are optional. ### Parameters - **items** (Iterable) - The initial set of items to cluster. - **updateMarkers** (void Function(Set)) - A callback function called whenever clusters recompute. It receives a `Set`. - **markerBuilder** (Future Function(Cluster)) - Optional. A custom function to build marker appearances for clusters. - **levels** (List) - Optional. Defines the zoom level breakpoints for clustering. - **extraPercent** (double) - Optional. Percentage of visible bounds to render beyond, to avoid marker pop-in. - **stopClusteringZoom** (double) - Optional. The zoom level above which each item gets its own marker. - **clusterAlgorithm** (ClusterAlgorithm) - Optional. The clustering algorithm to use (`GEOHASH` or `MAX_DIST`). Defaults to `GEOHASH`. - **maxItemsForMaxDistAlgo** (int) - Optional. The maximum number of items before switching from `MAX_DIST` to `GEOHASH`. - **maxDistParams** (MaxDistParams) - Optional. Parameters for the `MAX_DIST` algorithm, such as epsilon in pixels. ### Usage Example ```dart import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart'; late ClusterManager _manager; // Minimal setup _manager = ClusterManager( items, // Iterable — initial set of items to cluster _updateMarkers, // void Function(Set) — called whenever clusters recompute ); // Full setup with all options _manager = ClusterManager( items, _updateMarkers, markerBuilder: _markerBuilder, // Future Function(Cluster) — custom marker appearance levels: [1, 4.25, 6.75, 8.25, 11.5, 14.5, 16.0, 16.5, 20.0], // zoom breakpoints extraPercent: 0.2, // render 20% beyond visible bounds to avoid pop-in stopClusteringZoom: 17.0, // above this zoom, each item gets its own marker clusterAlgorithm: ClusterAlgorithm.GEOHASH, // or ClusterAlgorithm.MAX_DIST maxItemsForMaxDistAlgo: 200, // switch from MAX_DIST to GEOHASH above this count maxDistParams: MaxDistParams(20), // epsilon (pixels) for MAX_DIST algorithm ); void _updateMarkers(Set markers) { setState(() => this.markers = markers); } ``` ``` -------------------------------- ### Custom Cluster Marker Appearance with `markerBuilder` Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Implement a custom marker builder to define the appearance of cluster markers. Use `cluster.isMultiple` and `cluster.count` to dynamically adjust the marker's size, text, and color based on the cluster's content. The `_buildBitmap` function assists in creating custom marker icons. ```dart Future Function(Cluster) get _markerBuilder => (cluster) async { return Marker( markerId: MarkerId(cluster.getId()), // stable ID based on location + count position: cluster.location, // weighted centroid of all items onTap: () { // Access all items inside the cluster print('Tapped: $cluster'); // "Cluster of 5 Place (48.85, 2.34)" for (final place in cluster.items) { print(' - ${place.name}'); } }, icon: await _buildBitmap( size: cluster.isMultiple ? 125 : 75, text: cluster.isMultiple ? cluster.count.toString() : null, color: cluster.isMultiple ? Colors.orange : Colors.blue, ), ); }; Future _buildBitmap( {required int size, String? text, required Color color}) async { final recorder = PictureRecorder(); final canvas = Canvas(recorder); canvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, Paint()..color = color); canvas.drawCircle(Offset(size / 2, size / 2), size / 2.2, Paint()..color = Colors.white); canvas.drawCircle(Offset(size / 2, size / 2), size / 2.8, Paint()..color = color); if (text != null) { final painter = TextPainter(textDirection: TextDirection.ltr) ..text = TextSpan( text: text, style: TextStyle( fontSize: size / 3, color: Colors.white, fontWeight: FontWeight.normal)) ..layout(); painter.paint(canvas, Offset(size / 2 - painter.width / 2, size / 2 - painter.height / 2)); } final img = await recorder.endRecording().toImage(size, size); final data = await img.toByteData(format: ImageByteFormat.png) as ByteData; return BitmapDescriptor.fromBytes(data.buffer.asUint8List()); } ``` -------------------------------- ### Track Camera Movement with ClusterManager.onCameraMove() Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Call this on every camera movement to keep the manager's internal zoom level current. Pass `forceUpdate: true` to recompute clusters on every frame, which is expensive but provides real-time updates. ```dart GoogleMap( // ... onCameraMove: (CameraPosition position) { // Update zoom level; clusters will recompute on onCameraIdle _manager.onCameraMove(position); // Or force an immediate re-render on every frame (use sparingly): // _manager.onCameraMove(position, forceUpdate: true); }, onCameraIdle: _manager.updateMap, // recommended: recompute only when camera stops ) ``` -------------------------------- ### ClusterManager.setMapId() Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Connects the `ClusterManager` to a live `GoogleMap` instance. This method must be called within the `onMapCreated` callback to bind the manager to the map and trigger an initial cluster update. ```APIDOC ## ClusterManager.setMapId() ### Description Connecting the manager to a live Google Map. Must be called once inside `onMapCreated` to bind the manager to the map. Triggers an initial cluster update by default. ### Parameters - **mapId** (int) - The ID of the Google Map controller. - **withUpdate** (bool) - Optional. If `true` (default), triggers an initial cluster update. Set to `false` to skip the initial update. ### Usage Example ```dart GoogleMap( initialCameraPosition: CameraPosition( target: LatLng(48.856613, 2.352222), zoom: 12.0, ), markers: markers, onMapCreated: (GoogleMapController controller) { _controller.complete(controller); // Bind manager to this map — triggers first cluster render _manager.setMapId(controller.mapId); // Pass withUpdate: false to skip the initial update // _manager.setMapId(controller.mapId, withUpdate: false); }, onCameraMove: _manager.onCameraMove, onCameraIdle: _manager.updateMap, ) ``` ``` -------------------------------- ### Connect ClusterManager to Google Map in onMapCreated Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Bind the cluster manager to the map's ID within the `onMapCreated` callback. This triggers an initial cluster render by default. You can optionally skip the initial update. ```dart GoogleMap( initialCameraPosition: CameraPosition( target: LatLng(48.856613, 2.352222), zoom: 12.0, ), markers: markers, onMapCreated: (GoogleMapController controller) { _controller.complete(controller); // Bind manager to this map — triggers first cluster render _manager.setMapId(controller.mapId); // Pass withUpdate: false to skip the initial update // _manager.setMapId(controller.mapId, withUpdate: false); }, onCameraMove: _manager.onCameraMove, onCameraIdle: _manager.updateMap, ) ``` -------------------------------- ### ClusterManager.setItems() Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Replaces the entire item set and immediately triggers a new cluster render. Use this for full data refreshes. ```APIDOC ## ClusterManager.setItems() ### Description Replaces the entire item set and immediately triggers a new cluster render. Use this for full data refreshes (e.g., after a network fetch). ### Method Signature ```dart setItems(List items) ``` ### Parameters - **items** (List) - Required - The new list of items to cluster. ### Usage Example ```dart // Replace all markers with a fresh data set Future _refreshPlaces() async { final List newPlaces = await fetchPlacesFromApi(); _manager.setItems(newPlaces); // updates map immediately } // Example: replace with 30 dynamically generated places _manager.setItems([ for (int i = 0; i < 30; i++) Place( name: 'New Place $i', latLng: LatLng(48.858265 + i * 0.01, 2.350107), ), ]); ``` ``` -------------------------------- ### Max-Distance Clustering Algorithm Configuration Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Configures the ClusterManager to use the MAX_DIST algorithm, which groups items based on screen proximity. This algorithm is suitable for smaller datasets and automatically falls back to GEOHASH when the item count exceeds a specified threshold. ```dart // MAX_DIST algorithm: groups items that appear within `epsilon` pixels of each // other on screen. Automatically falls back to GEOHASH when item count exceeds // maxItemsForMaxDistAlgo. _manager = ClusterManager( items, _updateMarkers, clusterAlgorithm: ClusterAlgorithm.MAX_DIST, maxDistParams: MaxDistParams(20), // merge clusters within 20 screen-pixels maxItemsForMaxDistAlgo: 150, // use GEOHASH above 150 visible items ); ``` -------------------------------- ### Manually Trigger Cluster Recompute with ClusterManager.updateMap() Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Forces an immediate recalculation of clusters based on the current viewport and zoom. This is useful after programmatic map changes or after updating items without moving the camera. ```dart // Force refresh after a programmatic camera animation Future _animateToLocation(LatLng target) async { final controller = await _controller.future; await controller.animateCamera(CameraUpdate.newLatLngZoom(target, 14.0)); // Camera idle fires automatically, but you can also call manually: _manager.updateMap(); } ``` -------------------------------- ### ClusterManager.onCameraMove() Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Tracks camera movements to keep the manager's internal zoom level current. Can optionally force a recomputation of clusters on every frame. ```APIDOC ## ClusterManager.onCameraMove() ### Description Call this on every camera movement to keep the manager's internal zoom level current. Pass `forceUpdate: true` to recompute clusters on every frame (expensive but real-time). ### Method Signature ```dart onCameraMove(CameraPosition position, {bool forceUpdate = false}) ``` ### Parameters - **position** (CameraPosition) - Required - The current camera position. - **forceUpdate** (bool) - Optional - If true, forces cluster recomputation on every frame. ### Usage Example ```dart GoogleMap( // ... onCameraMove: (CameraPosition position) { // Update zoom level; clusters will recompute on onCameraIdle _manager.onCameraMove(position); // Or force an immediate re-render on every frame (use sparingly): // _manager.onCameraMove(position, forceUpdate: true); }, onCameraIdle: _manager.updateMap, // recommended: recompute only when camera stops ) ``` ``` -------------------------------- ### Multiple Cluster Managers on One Map Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Manage distinct sets of items with separate `ClusterManager` instances on the same map. Each manager can have its own item set, marker style, and update callback. Merge the resulting `Set` from each manager before passing it to the `GoogleMap` widget. ```dart late ClusterManager _managerRed; late ClusterManager _managerBlue; Set markersRed = {}; Set markersBlue = {}; @override void initState() { super.initState(); _managerRed = ClusterManager( restaurantsAndBars, (m) => setState(() => markersRed = m), markerBuilder: _getMarkerBuilder(Colors.red), ); _managerBlue = ClusterManager( hotelsAndPlaces, (m) => setState(() => markersBlue = m), markerBuilder: _getMarkerBuilder(Colors.blue), ); } // In build(): GoogleMap( markers: {...markersRed, ...markersBlue}, // merge both sets onMapCreated: (controller) { _managerRed.setMapId(controller.mapId); _managerBlue.setMapId(controller.mapId); }, onCameraMove: (position) { _managerRed.onCameraMove(position); _managerBlue.onCameraMove(position); }, onCameraIdle: () { _managerRed.updateMap(); _managerBlue.updateMap(); }, ) ``` -------------------------------- ### ClusterManager.getMarkers() Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Retrieves the list of computed Cluster objects for the current viewport. Useful for programmatic processing of clusters. ```APIDOC ## ClusterManager.getMarkers() ### Description Returns the list of `Cluster` objects for the current viewport. Useful when you need to process clusters programmatically rather than (or in addition to) rendering them. ### Method Signature ```dart Future>> getMarkers() ``` ### Return Value - **List>** - A list of cluster objects representing the current map view. ### Usage Example ```dart Future _logClusterStats() async { final List> clusters = await _manager.getMarkers(); for (final cluster in clusters) { if (cluster.isMultiple) { print('Cluster at ${cluster.location} — ${cluster.count} items'); // Output: Cluster at LatLng(48.856, 2.345) — 7 items } else { final place = cluster.items.first; print('Single marker: ${place.name} at ${cluster.location}'); } } print('Total clusters/markers rendered: ${clusters.length}'); } ``` ``` -------------------------------- ### ClusterManager.updateMap() Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Manually triggers an immediate recalculation of clusters based on the current viewport and zoom. Useful after programmatic map changes. ```APIDOC ## ClusterManager.updateMap() ### Description Forces an immediate recalculation of clusters based on the current viewport and zoom. Useful after programmatic map changes or after updating items without moving the camera. ### Method Signature ```dart updateMap() ``` ### Usage Example ```dart // Force refresh after a programmatic camera animation Future _animateToLocation(LatLng target) async { final controller = await _controller.future; await controller.animateCamera(CameraUpdate.newLatLngZoom(target, 14.0)); // Camera idle fires automatically, but you can also call manually: _manager.updateMap(); } ``` ``` -------------------------------- ### Retrieve Computed Clusters Directly with ClusterManager.getMarkers() Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Returns the list of `Cluster` objects for the current viewport. This is useful when you need to process clusters programmatically rather than (or in addition to) rendering them. ```dart Future _logClusterStats() async { final List> clusters = await _manager.getMarkers(); for (final cluster in clusters) { if (cluster.isMultiple) { print('Cluster at ${cluster.location} — ${cluster.count} items'); // Output: Cluster at LatLng(48.856, 2.345) — 7 items } else { final place = cluster.items.first; print('Single marker: ${place.name} at ${cluster.location}'); } } print('Total clusters/markers rendered: ${clusters.length}'); } ``` -------------------------------- ### Geohash Clustering Algorithm Configuration Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Configures the ClusterManager to use the GEOHASH algorithm, which is the default and recommended for large datasets. It groups items based on geohash prefixes derived from zoom level breakpoints. ```dart // GEOHASH algorithm (default): groups by geohash prefix length derived from // the zoom breakpoints in `levels`. Best for large datasets. _manager = ClusterManager( items, _updateMarkers, clusterAlgorithm: ClusterAlgorithm.GEOHASH, levels: [1, 4.25, 6.75, 8.25, 11.5, 14.5, 16.0, 16.5, 20.0], stopClusteringZoom: 17.0, // render individual items above zoom 17 ); ``` -------------------------------- ### ClusterManager.addItem() Source: https://context7.com/bpillon/google_maps_cluster_manager/llms.txt Appends one new item to the existing set and triggers a map update. Efficient for single additions. ```APIDOC ## ClusterManager.addItem() ### Description Appends one new item to the existing set and triggers a map update. Efficient for single additions without replacing the whole dataset. ### Method Signature ```dart addItem(T item) ``` ### Parameters - **item** (T) - Required - The item to add. ### Usage Example ```dart // Add a newly created place without reloading everything void _onNewPlaceCreated(String name, LatLng position) { final newPlace = Place(name: name, latLng: position); _manager.addItem(newPlace); // clusters update automatically } // Example usage: _manager.addItem( Place(name: 'New Restaurant', latLng: LatLng(48.8606, 2.3376)), ); ``` ``` -------------------------------- ### Load Dart Application with Service Worker Source: https://github.com/bpillon/google_maps_cluster_manager/blob/master/example/web/index.html This script manages service worker registration for a Dart application. It attempts to load the main Dart script via the service worker and falls back to a direct script load if the service worker fails or is not supported. Ensure 'flutter_service_worker.js' is available. ```javascript var serviceWorkerVersion = null; var scriptLoaded = false; function loadMainDartJs() { if (scriptLoaded) { return; } scriptLoaded = true; var scriptTag = document.createElement('script'); scriptTag.src = 'main.dart.js'; scriptTag.type = 'application/javascript'; document.body.append(scriptTag); } if ('serviceWorker' in navigator) { // Service workers are supported. Use them. window.addEventListener('load', function () { // Wait for registration to finish before dropping the