google_maps_cluster_manager icon indicating copy to clipboard operation
google_maps_cluster_manager copied to clipboard

[Feature] Zoom in to decluster

Open cedvdb opened this issue 3 years ago • 8 comments

On the vanilla google cluster API when you click on a cluster the map will zoom in until some of the points are markers (stand by themselves).

https://developers.google.com/maps/documentation/javascript/marker-clustering

It has a method getMaxZoom() which allows the client to zoom into the cluster without losing any marker.

It would be nice if this plugin supported such a feature, or at least made it easier to implement.

cedvdb avatar Nov 15 '21 17:11 cedvdb

I'm trying to work on it,

inside the property onTap of the markerBuilder function I implemented this code:

onTap: cluster.isMultiple
          ? () async {
              var gMapController = await gMapCompleter.future;
              var actualZoom = await gMapController.getZoomLevel();
              var startingClusterCount = cluster.count;
              while (cluster.count == startingClusterCount) {
                actualZoom =
                    manager.levels.firstWhere((level) => level > actualZoom);
                gMapController.animateCamera(
                  CameraUpdate.newLatLngZoom(
                    cluster.location,
                    actualZoom,
                  ),
                );
              }
            }
          : () => showModalBottomSheet(
                backgroundColor: Colors.amber.withOpacity(0.90),
                shape: const RoundedRectangleBorder(
                  borderRadius: BorderRadius.vertical(top: Radius.circular(30)),
                ),
                context: context,
                builder: (BuildContext context) {
                  return const SizedBox(
                    width: double.infinity,
                    height: 350,
                  );
                },
              ),

The interesting part is the cluster.isMultiple branch.

The problem is that it continues to zoom till the last level, it's like if the cluster.count doesn't update.

Any suggestion?

baldax95 avatar Dec 02 '21 09:12 baldax95

yes your while loop is problematic because it is synchronous so count will always be the same.

What you'd want is somehting like this


    // pseudo code
    int getClusterZoomLevel() async {
             final startingCount = cluster.count;
             var endCount = startingCount;
             var endZoom = await getCurrentZoomLevel();
             while(endCount == startingCount && endZoom <= maxZoomLevel) {
                endZoom++;
                endCount = await getClusterCountForZoomLevel(endZoom)
             }
             return endZoom;
    }

Therefor you need a way to calculate the end zoom before animation even starts.

cedvdb avatar Dec 02 '21 11:12 cedvdb

The problem is that there isn't a way to calculate the cluster count for a certain zoom level before actually zooming the map.

Or am I wrong?

baldax95 avatar Dec 02 '21 11:12 baldax95

As far as I know there is no public method in the package that does it. A Pull request would certainly help to resolve this issue if that's not the case

cedvdb avatar Dec 02 '21 18:12 cedvdb

@Jollastro @cedvdb any updates!

masreplay avatar Dec 11 '21 11:12 masreplay

I don't think either of us are working on that, feel free to implement it.

cedvdb avatar Dec 11 '21 15:12 cedvdb

Any updates?

jonasPfeifhofer avatar Jan 05 '22 14:01 jonasPfeifhofer

I implemented this by zooming to the LatLngBounds of the markers in the cluster:

...

LatLngBounds boundsFromLatLngList(List<LatLng> list) {
    double? x0, x1, y0, y1;
    for (LatLng latLng in list) {
      if (x0 == null || x1 == null || y0 == null || y1 == 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!));
  }

...

onTap: () async {
            if (cluster.isMultiple) {
              final controller = await _mapsController.future;
              controller.animateCamera(CameraUpdate.newLatLngBounds(
                  boundsFromLatLngList(
                      cluster.items.map((e) => e.location).toList()),
                  100));
            }
...

tuoku avatar Jul 30 '22 12:07 tuoku