Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fit markers on the screen with flutter google maps

I'm playing around with Google Maps for Flutter. I want the map view to fit all the markers on the screen. Basically, I want to do same as here for android.

I assumed that cameraTargetBounds describes the area that should fit inside screen boundaries. But in fact it doesn't fit this area entirely, focusing somewhere in between.

What I've done so far:

  @override
  Widget build(BuildContext context) {
    final bloc = Provider.of<BlocMap>(context);
    return SafeArea(
      child: Container(
        child: Stack(
          children: <Widget>[
            Positioned.fill(
              child: StreamBuilder<MapData>(
                  stream: bloc.mapData,
                  builder: (context, snap) {
                    final mapData = snap.data;
                    print("mapData: $mapData");
                    return GoogleMap(
                      padding: EdgeInsets.only(bottom: 42),
                      mapType: _mapType,
                      cameraTargetBounds: mapData?.markers == null
                          ? CameraTargetBounds.unbounded
                          : CameraTargetBounds(_bounds(mapData?.markers)),
                      initialCameraPosition: _cameraPosition,
                      myLocationEnabled: true,
                      myLocationButtonEnabled: true,
                      gestureRecognizers: _buildGestureRecognizer(),
                      onMapCreated: (GoogleMapController controller) {
                        _controller.complete(controller);
                      },
                      markers: mapData?.markers,
                      polylines: mapData?.polylines,
                      polygons: mapData?.polygons,
                      onLongPress: (latLng) {
                        print("LatLng: $latLng");
                      },
                    );
                  }),
            ),
            Positioned(
              left: 0,
              right: 0,
              bottom: 0,
              child: _buildBtnBar(),
            )
          ],
        ),
      ),
    );

    LatLngBounds _bounds(Set<Marker> markers) {
    if (markers == null || markers.isEmpty) return null;
    return _createBounds(markers.map((m) => m.position).toList());
  }


 LatLngBounds _createBounds(List<LatLng> positions) {
    final southwestLat = positions.map((p) => p.latitude).reduce((value, element) => value < element ? value : element); // smallest
    final southwestLon = positions.map((p) => p.longitude).reduce((value, element) => value < element ? value : element);
    final northeastLat = positions.map((p) => p.latitude).reduce((value, element) => value > element ? value : element); // biggest
    final northeastLon = positions.map((p) => p.longitude).reduce((value, element) => value > element ? value : element);
    return LatLngBounds(
        southwest: LatLng(southwestLat, southwestLon),
        northeast: LatLng(northeastLat, northeastLon)
    );
  }

What is the intended way of achieving this basic functionality in flutter? Any suggestions?

like image 830
AlexKost Avatar asked Sep 25 '19 08:09

AlexKost


3 Answers

Use this code to do what you wish.

onMapCreated: (GoogleMapController controller) {
   _controller.complete(controller);

   setState(() {
      controller.animateCamera(CameraUpdate.newLatLngBounds(_bounds(markers), 50));
   });
}
like image 185
Bruno Zaranza Avatar answered Oct 17 '22 04:10

Bruno Zaranza


Try using the controller to move the camera to the new bounds, eg (from the plugin example):

mapController.moveCamera(
  CameraUpdate.newLatLngBounds(
    LatLngBounds(
      southwest: const LatLng(-38.483935, 113.248673),
      northeast: const LatLng(-8.982446, 153.823821),
    ),
    10.0,
  ),
);
like image 37
Nick Avatar answered Oct 17 '22 02:10

Nick


first make a list of latlng and pass it to the given method

List<LatLng> latlonList = [LatLng(125.75,87.00),LatLng(165,46.76),LatLng(175.87,86.00),];

    final GoogleMapController googleMapController = await widget.completer.future;
        googleMapController.moveCamera(CameraUpdate.newLatLngBounds(
          MapUtils.boundsFromLatLngList(latlonList),
            4.0,
            ),
          );

after that your map move to all the pointer . but to show more marker decent way we use another method which give us the center point of all the markers

 var centerPoint =  computeCentroid(latlonList);

  var  zoom = await googleMapController.getZoomLevel();

this.updateLocation(centerPoint.latitude, centerPoint.longitude,zoom -2);  

Now simply copy these method..and every ting work perfectly fine

LatLng computeCentroid(Iterable<LatLng> points) {
  double latitude = 0;
  double longitude = 0;
  int n = points.length;

  for (LatLng point in points) {
    latitude += point.latitude;
    longitude += point.longitude;
  }

  return LatLng(latitude / n, longitude / n);
}


    class MapUtils {
       static LatLngBounds boundsFromLatLngList(List<LatLng> list) {
        double? x0, x1, y0, y1;
        for (LatLng latLng in list) {
          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!));
      }
    }
  updateLocation(double latitude,double longitude,double zoom) async {

    final GoogleMapController googleMapController = await widget.completer.future;
     print("zoom$zoom");
    googleMapController.animateCamera(CameraUpdate.newCameraPosition(
      CameraPosition(
        bearing: 0,
        target: LatLng(latitude,longitude),
        zoom:zoom,
      ),
    ));
    
  }
like image 2
benten Avatar answered Oct 17 '22 02:10

benten