Coder Social home page Coder Social logo

bpillon / google_maps_cluster_manager Goto Github PK

View Code? Open in Web Editor NEW
119.0 3.0 92.0 4.75 MB

Simple Flutter clustering library for Google Maps

Home Page: https://pub.dev/packages/google_maps_cluster_manager

License: MIT License

Dart 85.41% Kotlin 0.99% Ruby 3.27% Swift 1.13% Objective-C 0.09% HTML 9.11%

google_maps_cluster_manager's Introduction

pub package

Flutter Cluster Manager for Google Maps

Screenshot

A Flutter package to cluster items on a Google Maps widget based on Geohash. Highly inspired by clustering_google_maps

Usage

To use this package, add google_maps_cluster_manager as a dependency in your pubspec.yaml file.

Getting Started

Your map items has to use ClusterItem as a mixin (or extends this class) and implements the LatLng location getter.

class Place with ClusterItem {
  final String name;
  final LatLng latLng;

  Place({required this.name, required this.latLng});

  @override
  LatLng get location => latLng;
}

To start with Cluster Manager, you have to initialize a ClusterManager instance.

ClusterManager<Place>(
    _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"
);

When your GoogleMapController is created, you have to set the mapId with the setMapId method :

_manager.setMapId(controller.mapId);

You are able to add an new item to the map by calling addItem method on your ClusterManager instance. You can also completely change the items on your maps by calling setItems method.

You can customize the icon of a cluster by using Future<Marker> Function(Cluster<T extends ClusterItem>) markerBuilder parameter.

static Future<Marker> 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),
  );
};

static Future<BitmapDescriptor> 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());
}

Every cluster (even one item clusters) is rendered by the library as a Cluster<T extends ClusterItem> object. You can differentiate single item clusters from multiple ones by using the isMultiple variable (or the count variable). This way, you can create different markers icon depending on the type of cluster.

You can create multiple managers for a single map, see the multiple.dart example.

Complete Basic Example

See the example directory for a complete sample app.

google_maps_cluster_manager's People

Contributors

bpillon avatar buntagonalprism avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

google_maps_cluster_manager's Issues

Disable clustering

Hi,

Would it be possible to turn off clustering on the go? e.g., clusterManager.disableClustering()

New Future please

Thank you for package!!
I neew an InfoWindow for marker. Or could be clickable markers.

possibility to exclude from clustering in certain zoom value

So I have this case that my markers are almost at the same location (they are in the same building).
And if I would turn off clustering they would be placed very close to each other but now one on another (tested this on zoom levels 19+), but when clustering the makers I'm not able to show them.

Is there any possibility to add such an option that for x number of items you would not cluster them above a given zoom value one would see all items?

UnCluster markers when zoomed

  • When user click on Clustered marker, the markers at that spot should Unflustered and camera should zoom to it and when zoomed out the cluster should again appear.
    OpenStreetMap has this feature
    How to do this?
    Screenshot_20221130-151944

How to cluster near by Markers?

Hi @bpillon,

In the current implementation, is it possible to cluster only nearby markers?

E.g. Markers having a distance difference only of 50m and on ultra-zoom, we can split them.

Thanks.

[sample code] Using Custom markers

I need to display custom marker when cluster is not multiple.
In that case I would like to display my own widget based on Image and Text.
I have tried to use the MarkerGenerator widget as follow:
But the marker for simple cluster is not displayed.
Any idea ?

 Future<Marker> Function(Cluster) get _markerBuilder => (cluster) async {
        var beacon;
        if (!cluster.isMultiple) {
          beacon = cluster.items.first as Beacon;
          final productImage = await ProductsRepository.instance
            .imageFromProductName(beacon.product.name);
          final beaconMarker = Container(
            width: 120,
            height: 120,
            child: Stack(
              children: <Widget>[
                Align(
                  alignment: Alignment.center,
                  child: Image.asset(
                    'assets/images/marker.png', 
                  ),
                ),
                Align(
                    alignment: Alignment.center,
                    child: Container(
                      padding: EdgeInsets.only(bottom: 10),
                      width: 80,
                      height: 80,
                      child: productImage
                    ))
              ],
            ),
          );

          final markerCompleter = Completer<Marker>();
          MarkerGenerator([beaconMarker], (bitmaps) {
            final marker = Marker(
              markerId: MarkerId(cluster.getId()),
              position: cluster.location,
              infoWindow: InfoWindow(
                title: beacon.name,
              ),
              icon: BitmapDescriptor.fromBytes(bitmaps.first),
            );
            markerCompleter.complete(marker);
          }).generate(context);
          return markerCompleter.future;
        } else {
          return Marker(
            markerId: MarkerId(cluster.getId()),
            position: cluster.location,
            icon: await _getMarkerBitmap(125, text: cluster.count.toString()),
          );
        }
      };

Dynamically change Cluster marker icon

I can change the single Cluster easily by adding isSelected field into Place. When it comes to multiple Cluster, I found a workaround for now.

Future<Marker> Function(Cluster<Place>) get _markerBuilder => (cluster) async {
        return Marker(
          markerId: MarkerId(cluster.getId()),
          position: cluster.location,
          onTap: () => onMarkerPressed(cluster),
          icon: await _getMarkerBitmap(
            cluster.isMultiple,
            text: cluster.isMultiple ? cluster.count.toString() : null,
            isSelected: cluster.items.map((element) => element.isSelected).contains(true),
          ),
        );
      };

In my opinion, Cluster<T> should have a field called isSelected and ClusterManager<T extends ClusterItem> should have a function that updates the cluster by Cluster id. This way it would be easier to update Cluster. Does it make sense? If not, what would be the best practice here?

Minimum cluster size

Is it possible to set a minimum cluster size? so if the zoom level dictated 10 markers needed to be clustered together, but i had set a minimum cluster size of 5 i would see two 5 clusters instead of 1 cluster for the 10?

Get zoom level when cluster is created as a property

Hi All i want to uncluster the cluster when clicking on it, i think the best way is to get the exact zoom leevel when the cluster was created then zoom at that level and add a bit.
i was wondering if anyone have tried it.
thx

Marker not always displayed (_mapController.getVisibleRegion does not return the right value)

It seems the _updateMarkers functions is called on the onMapCreated / setMapController call.
This call is then trigerring the getMarkers function from the clusterManager class.
In this method, the _mapController.getVisibleRegion is called.

But the current Visible region does not seems updated / available at this time.

To make it works, I'm obliged to add a delay before calling the _manager.setMapController(controller);

Any idea / solution ?

onMapCreated: (GoogleMapController controller) {
            _controller.complete(controller);
            _manager.setMapController(controller);
          },
Future<List<Cluster<T>>> getMarkers() async {
    if (_mapController == null) return List();

    LatLngBounds latLngBounds = await _mapController.getVisibleRegion();

map markers not getting updated during runtime

Thanks for this great package,I am having a weird issue I tried your sample code and it seems to work well but during the runtime when I try to update the list I am getting only 1 Item on the map.
e.g I am getting a List<T> items which I am mapping to a List<ClusterItem<T>> kItems and then when I do

_manager.setItems(kItems); /// total kItems length equals 20 here

but when I see the length of markers in _updateMarkers(Set markers) its always 1 rest 19 are null or getting lost
It always updates only 1 item from the kItems list and I only see 1 marker on the map

let me know if you need any additional info.

Syntax question about markerBuilder

Hi,

First of all, awesome plugin, thank you !

I managed to make it work but I don't understand the following syntax :
static Future<Marker> Function(Cluster) get markerBuilder => (cluster) async

I search on Dart documentation, stackoverflow for answers but could find a thing. Could you please explain me the getter syntax, especially why does it returns Future<Marker> Function(Cluster) and what does it means ?

Best

The sample code in README doesn't work

The sample code in README does not work at all.

import "package:latlng/latlng.dart";
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';

class Place with ClusterItem {
  final String name;
  final LatLng latLng;

  Place({required this.name, required this.latLng});

  @override
  LatLng get location => latLng;
}

The below is the problem text

'Place.location' ('LatLng Function()') isn't a valid override of 'ClusterItem.location' ('LatLng Function()').dart[invalid_override](https://dart.dev/diagnostics/invalid_override)

cluster_item.dart(5, 14): The member being overridden.

So I cannot use this package.
Please fix this problem!

Dificutly setting up the lib when using providers.

My App uses the provider concept which fetches data. Now, if I understand the tool correctly, it's main idea is to update the stateful widgets state when updating/setting the GooglesMaps markers, which will refresh the widget and reload the ClusterItems with proper Markers. In a provider concept this is not advised and the whole widget works in a totally different way.

I'm trying to adapt your concept to handle the ClusterManager and build it with the data when the provider will return my items but this approach does not display any clusters on the screen, it only appears when I force a Hot Refresh.

Could you please help here?

This is my Widget:

class MapWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MapWidgetState();
}

class MapWidgetState extends State<MapWidget> {
  ClusterManager<RestaurantItem> _manager;

  Set<Marker> _mapMarkers = HashSet();
  List<ClusterItem<RestaurantItem>> _restaurantItems = List();
  GoogleMapController _controller;

  @override
  Widget build(BuildContext context) {
    return Consumer<RestaurantsData>(
      builder: (innerContext, restaurantsData, __) {
        if (restaurantsData.dataNotLoaded) {
          logger.i("Initializing primary data!");
          return _buildMapDetails(innerContext);
        }
        buildRestaurantMarkers(restaurantsData);
      
        var locationProv = Provider.of<LocationProvider>(context, listen: false);
        _manager = ClusterManager<RestaurantItem>(_restaurantItems, _updateMarkers, markerBuilder: _markerBuilder, initialZoom: locationProv.currentZoom);

        _onLoadingContent(restaurantsData);

        if (restaurantsData.filteringApplied && restaurantsData.getRestaurants().isNotEmpty) {
          Timer(Duration(milliseconds: 1000), () => _controller.animateCamera(CameraUpdate.newLatLngBounds(boundsFromLatLngList(), 30)));
        }
        return _buildMapDetails(innerContext);
      },
    );
  }

  Widget _buildMapDetails(BuildContext context) {
    return Stack(
      children: <Widget>[
        Scaffold(
          body: _manager != null ? _googleMaps() : Container(),
          ..... < rest of widget contents > .......
        ),
      ],
    );
  }

  Widget _googleMaps() {
    LocationProvider locationProvider = Provider.of<LocationProvider>(context, listen: false);
    return GoogleMap(
      mapType: MapType.normal,
      myLocationEnabled: true,
      myLocationButtonEnabled: false,
      mapToolbarEnabled: false,
      zoomGesturesEnabled: true,
      rotateGesturesEnabled: true,
      initialCameraPosition: CameraPosition(
        zoom: locationProvider.currentZoom,
        target: locationProvider.currentPosition,
      ),
      onMapCreated: (GoogleMapController controller) {
        _controller = controller;
        _manager.setMapController(controller, withUpdate: true);
      },
      markers: _mapMarkers,
      onCameraMove: (CameraPosition cameraPosition) {
        _manager.onCameraMove(cameraPosition, forceUpdate: true);
        locationProvider.setZoom(cameraPosition.zoom);
        locationProvider.setPosition(cameraPosition.target);
      },
      onCameraIdle: _manager.updateMap,
    );
  }

  void buildRestaurantMarkers(RestaurantsData restaurantsData) {
    logger.d("Creating map markers");
    var restaurantItems = restaurantsData.getRestaurants().map((item) => ClusterItem(item.latLng, item: item)).toList();
    this._restaurantItems = restaurantItems;
//    _manager.setItems(restaurantItems);
    logger.d("Cluster Items has been set = ${restaurantItems.length}");
  }

  void _updateMarkers(Set<Marker> markers) {
    logger.d("Markers have been updated, size: ${markers.length}");
    _mapMarkers = markers;
  }

  void _onLoadingContent(RestaurantsData restaurantsData) {
    var contentLoading = Provider.of<LoadingContentProvider>(context, listen: false);
    if (contentLoading.isLoading) {
      Timer(Duration(milliseconds: 0), () {
        logger.d("Notify LoadingContentProvider GoogleMap data loading finished!");
        contentLoading.update(false);
      });
    }
  }

  LatLngBounds boundsFromLatLngList() {
    double x0, x1, y0, y1;
    List<LatLng> positions = _mapMarkers.map((marker) => marker.position).toList();
    for (LatLng latLng in positions) {
      if (x0 == null) {
        x0 = x1 = latLng.latitude;
        y0 = y1 = latLng.longitude;
      } else {
        if (latLng.latitude > x1) x1 = latLng.latitude;
        if (latLng.latitude < x0) x0 = latLng.latitude;
        if (latLng.longitude > y1) y1 = latLng.longitude;
        if (latLng.longitude < y0) y0 = latLng.longitude;
      }
    }
    return LatLngBounds(northeast: LatLng(x1, y1), southwest: LatLng(x0, y0));
  }

  Future<Marker> Function(Cluster<RestaurantItem>) get _markerBuilder => (cluster) async {
        if (cluster.isMultiple) {
          return Marker(
            markerId: MarkerId("cluster|${cluster.getId()}"),
            position: cluster.location,
            icon: await _getMarkerBitmap(cluster),
          );
        }

        var item = cluster.items.first;
        var mapMarkerProvider = Provider.of<MapMarkerProvider>(context, listen: false);
        return Marker(
          position: item.latLng,
          markerId: MarkerId("${item.id}|${item.name}"),
          icon: mapMarkerProvider.forObject(item),
          onTap: () async {
            logger.i("Marker clicked: ${item.id}, ${item.name}");
            showRestaurantDetails(item);
//          restaurantsData.selectOne(item);
            if (_controller != null) _controller.animateCamera(CameraUpdate.newLatLng(item.latLng));
          },
        );
      };

  Future<BitmapDescriptor> _getMarkerBitmap(Cluster<RestaurantItem> clusterOfItems) async {
    int size = 125;

    if (clusterOfItems.isMultiple) {
      final PictureRecorder pictureRecorder = PictureRecorder();
      final Canvas canvas = Canvas(pictureRecorder);
      final Paint paint1 = Paint()..color = CustomColor.green;
      final Paint paint2 = Paint()..color = Colors.white;

      canvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, paint1);
      canvas.drawCircle(Offset(size / 2, size / 2), size / 2.2, paint2);
      canvas.drawCircle(Offset(size / 2, size / 2), size / 2.8, paint1);
      TextPainter painter = TextPainter(textDirection: TextDirection.ltr);
      painter.text = TextSpan(
        text: clusterOfItems.count.toString(),
        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());
    } else {
      return Provider.of<MapMarkerProvider>(context, listen: false).forObject(clusterOfItems.items.first);
    }
  }
}

Define custom method to define MarkerId

I need to use the mapController.showMarkerInfoWindow(MarkerId(selectedMarker.getId()));
My pb is that the function used to set MarkerId in the cluster manager is private.
It would be nice to define our own method to define the markerId and use the same function to open the Info window.

Zoom levels

I am trying to cluster such that when zoomed out all the way, I can get totals by country. However, what I find it when zoomed out completely the zoom level is only 2.069159507751465. So clusters from the eastern USA are still separate from the western USA.

I get the current zoom level by listening to onCameraMove and getting the zoom level from the camera position. I can verify that the zoom range is between 2.069159507751465 and 21.0.

Any ideas of why the zoom won't go to 1.0 when fully zoomed out?

Simulator Screen Shot - iPhone 12 Pro Max - 2021-07-22 at 13 59 03

GoogleMapsFlutter 1.0 not suported

When I try to update google_maps_flutter plugin, I get the following error:

Because no versions of google_maps_cluster_manager match >0.1.0 <0.2.0 and google_maps_cluster_manager 0.1.0 depends on google_maps_flutter ^0.5.22, google_maps_cluster_manager ^0.1.0 requires google_maps_flutter ^0.5.22.

Can you please update this plugin ?

Support for latest google maps

the google maps flutter plugin has been updated to 1.0.2
In order to use this plugin in a flutter project which uses the latest google maps,this plugin must update the google maps version it uses.
I would be glad to take up this issue if someone could guide me on what changes needs to be made.

Overlapping clusters at lower zoom levels...

How can I avoid clusters overlapping? (I need clustering for my clusters :-) )

I've had a look at setting levels, but can't quite understand what levels are actually doing and whatever I do seems to make it worse, not better.
Any pointers greatly received.

screen

[Question] Zoom / Unzoom: Cluster / non cluster

I have attached a video to show my pb.
I have a cluster of 2 points
If I zoom the Cluster is broken in 2 points
BUT the 2 points are not displayed on the map (are out of the current map view)
I need to zoom out to see the 2 points coming from the cluster
What need to be done to avoid this ?

Code:

return ClusterManager<_HistoryLocationInfo>( items, _updateMarkers, markerBuilder: _markerBuilder, extraPercent: 0.3, levels: [1, 3.5, 5, 8.25, 11.5, 14.5, 16, 16.5, 20], );

RPReplay_Final1594719365

create different markers icon

I have 4 different types of markers that I need to show on the map.

I am aware that I can create different markers icon, depending on the isMultiple property,

This means that a marker can be multiple or single. (This means maximum 2 marker icons)

My question is,
How can I create multiple marker icons for single clusters?

Should I rather create 4 instances of cluster managers?

Something like this
policeClusterManager = _initClusterManagerPolice();
carsClusterManager = _initClusterManagerCars();
accidentClusterManager = _initClusterManagerAccident();
storeClusterManager = _initClusterManagerstore();

how to zoom to center marker ?

is it possible to zoom to a marker on certain location.
some calculation to zoom in cluster to show one marker not cluster set.

setMapId should check if mounted

setMapId should check if mounted. The below code from the lib can create error in some edge scenarios.

  void setMapId(int mapId, {bool withUpdate = true}) async {
    _mapId = mapId;
    _zoom = await GoogleMapsFlutterPlatform.instance.getZoomLevel(mapId: mapId);
    if (withUpdate) updateMap();
  }

related flutter/flutter#101387

Force update needed after changing items list

Hi, thanks for your effort.

I'm haunted by a weird bug where after I update my items list, the initial new clusters are being updated but when zooming in, they aren't being unfolded anymore. They basically stay there until I again update the list.

So I digged into your code and found the forceUpdate setting, which seems to work. I'm not sure how performance intense this is but it's the only way to make it work.

Part of the widget

@override
Widget build(BuildContext context) {
  _ctx = context;

  return new StoreConnector<AppState, AppState>(
    onInit: (store) {
      // Set cluster items
      _items = store.state.companies.map((e) => ClusterItem(LatLng(e.lat, e.lon), item: e)).toList();
      // Set the manager
      _manager = ClusterManager<Company>(
        _items,
        _updateMarkers,
        markerBuilder: _markerBuilder,
        levels: [1, 3, 5, 7, 9, 12, 13, 15, 17, 20],
        initialZoom: _currentZoom,
      );   
    },
    onDidChange: (state) {
        // Pass new companies as items to manager
        _updateItems(state.companies); // <----------------
    },
  );
}

Update Items function

void _updateItems(List<Company> companies) {
  setState(() {
    _items = companies.map((e) => ClusterItem(LatLng(e.lat, e.lon), item: e)).toList();
    _manager.setItems(_items);
  });
}

Widget build part /w map

GoogleMap _map = GoogleMap(
  mapType: MapType.normal,
  myLocationButtonEnabled: false,
  initialCameraPosition: CameraPosition(...),
  markers: _markers,
  onMapCreated: (GoogleMapController controller) {
    _controller.complete(controller);
    _manager.setMapController(controller);
  },
  onCameraMove: (CameraPosition position) {
    _currentZoom = position.zoom;
    _manager.onCameraMove(position, forceUpdate: true);
  },
  onCameraIdle: _manager.updateMap,
);

isCluster: true or false

Can you add some thing like isCluster: true or false.

Sometime I don't want certain map markers to cluster

Where by that particular marker wont ever cluster.

I have a situation were by a user current location is on the map,
But soon as the user moves close enough to another marker, then that user marker will cluster.

Resulting in user not seeing their marker on the map anymore

Update cluster

Hi! I'm having a problem calling the _initClusterManager () method again to display new clusters again. How can I update the view of the clusters according to the items that I pass to it?

Markerbuilder network images enhancement / question

For each marker / cluster visible on the map I am converting a unique network image to a BitMapDescriptor for the Marker icon parameter. This operation can take a bit of time, I was wondering if there is a way to show a placeholder icon in some way?

If this is currently not possible, I'd like to propose the following feature: a new parameter for ClusterManager called placeholderMarkerBuilder, which is ran before markerBuilder if not null, and of which the markers are removed upon completion of markerBuilder. If there is a better way, I'd look forward to hearing it too.

Thanks for this package by the way, it's by far the best clustering package I've found on Flutter so far!

Unexpected Close

When I use this plugin it unexpectedly close the app from iphone 13 simulator.

onCameraIdle: _manager.updateMap remove all the clusters

Hi, thank you for the great library!
I was following the readme, and it seems my code is not working properly.

At first, clusters are shown with no problem, but once I move the map, all of them disapprear.
I could not find any relative issue on anywhere..

This is my code.

class SaunaMapState extends State<SaunaMap> {
  final Completer<GoogleMapController> _controller = Completer();
  BitmapDescriptor? pinLocationIcon;

  late ClusterManager _manager;

  CameraPosition kGooglePlex = const CameraPosition(
    target: LatLng(37.5, 134.5),
    zoom: 5,
  );
  Set<Marker> markers = Set();

  @override
  void initState() {
    super.initState();
    _manager = _initClusterManager();
  }

  ClusterManager _initClusterManager() {
    print('_initClusterManager ${saunaLocs.length}');
    return ClusterManager<Place>(
      [<locations>],
      _updateMarkers,
      markerBuilder: _markerBuilder,
      stopClusteringZoom: 17.0
    );
  }

  void _updateMarkers(Set<Marker> markers) {
    print('Updated ${markers.length} markers');
    setState(() {
      this.markers = markers;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: GoogleMap(
            mapType: MapType.normal,
            markers: markers, //_createMarker(),
            initialCameraPosition: kGooglePlex,
            onMapCreated: (GoogleMapController controller) {
              _controller.complete(controller);
              _manager.setMapId(controller.mapId);
            },
            onCameraMove: _manager.onCameraMove,
            onCameraIdle: _manager.updateMap
            ),
            floatingActionButtonLocation: FloatingActionButtonLocation.startDocked,
        floatingActionButton: Button.image(
            const Icon(
              Icons.list,
              color: Colors.white,
            ), () {
          Navigator.pop(context);
        }));
  }

  Future<Marker> Function(Cluster<Place>) get _markerBuilder =>
      (cluster) async {
        return Marker(
          markerId: MarkerId(cluster.getId()),
          position: cluster.location,
          onTap: () {
            print('---- ${cluster.items}');
            cluster.items.forEach((p) => print(p));
          },
          icon: await _getMarkerBitmap(cluster.isMultiple ? 125 : 75,
              text: cluster.isMultiple ? cluster.count.toString() : null),
        );
      };

  Future<BitmapDescriptor> _getMarkerBitmap(int size, {String? text}) async {
   ..copied from readme
  }
}

Geohash | Value Not In Range

Hi,

I'm getting this crash that stops showing clusters:

I/flutter ( 6428): Error FROM OUT_SIDE FRAMEWORK
I/flutter ( 6428): --------------------------------
I/flutter ( 6428): Error : RangeError: Value not in range: 14
I/flutter ( 6428): StackTrace : #0 _StringBase.substring (dart:core-patch/string_patch.dart:393:7)
I/flutter ( 6428): #1 ClusterManager._computeClusters (package:google_maps_cluster_manager/src/cluster_manager.dart:142:48)
I/flutter ( 6428): #2 ClusterManager.getMarkers (package:google_maps_cluster_manager/src/cluster_manager.dart:102:15)
I/flutter ( 6428):
I/flutter ( 6428): #3 ClusterManager._updateClusters (package:google_maps_cluster_manager/src/cluster_manager.dart:58:41)
I/flutter ( 6428): #4 ClusterManager.updateMap (package:google_maps_cluster_manager/src/cluster_manager.dart:54:5)
I/flutter ( 6428): #5 ClusterManager.setItems (package:google_maps_cluster_manager/src/cluster_manager.dart:69:5)

Is there a way to either make it so if a certain level of geohash is surpassed and starts crashing, use the latest available level? Or increasing a percision of a LatLng so that the generated geoHash would be more precise (not sure if possible) ?

[Question] ClusterAlgorithm MAX_DIST

Hi @bpillon I have a question about using the MAX_DIST algorithm for clustering the markers. I know it isn't in master yet, but trying tu using it I've figured out that all the movement I do in the map (move without zoom in/out, just in all directions), causes an inestability in clustering the markers. I will put here an example of it:
1643980554716

I did the same using the GEOHASH algorithm and is everything okey. The clusters are all with the same amount of markers all the time when I move around the map:
1643981527301 (1)

Lag when number of markers increases

As the number of markers increases the map begins to lag and unresponsive. And finally, the app crashes.

/// my map
GoogleMap(
mapToolbarEnabled: false,
zoomControlsEnabled: false,
onMapCreated: _onMapCreated,
myLocationEnabled: false,
myLocationButtonEnabled: false,
minMaxZoomPreference: MinMaxZoomPreference(1.0, 14.0),
initialCameraPosition: CameraPosition(
target: widget.initialPosition,
zoom: _defaultZoom,
),
markers: _updateMarker(
Provider.of(context).userDetailsList),
onCameraMove: _onCameraMove,
onCameraIdle: _onCameraIdle,
),

/// update marker
Set _updateMarker(List userDetailsList) {
_manager.setItems(<ClusterItem>[
for (UserDetails userDetails in userDetailsList)
ClusterItem(LatLng(userDetails.lat, userDetails.long),
item: Place(name: userDetails.name))
]);
_manager.updateMap();
return _markers;
}

/// cluster manager
ClusterManager _initClusterManager() {
return ClusterManager(items, _updateMarkers,
markerBuilder: _markerBuilder, initialZoom: _defaultZoom);
}
List<ClusterItem> items = [];

Not able to figure out what's causing the issue, can it be the package issue or flutter issue? Any help will be appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.