Home > front end >  How to correctly display 3 thousand coordinate points on the map in Flutter?
How to correctly display 3 thousand coordinate points on the map in Flutter?

Time:10-07

I created a map on which I want to place 3k points from my API. I wrote an algorithm that should do this. The problem is that it loads the map and points for a very long time, although I can see from the stack trace that the process is running. Can someone suggest how best to deal with this algorithm and display all the points I need on the map? Maybe I'm doing everything wrong. I'll be very thankful. Thanks!

The EDIT: now my map is loading, the process is also running and my http-request is being processed correctly and the data is coming from the server. But the problem is that the coordinates are displayed somewhere in the Atlantic Ocean, not in my city. How to fix it?

The code:

class _MapState extends State<Map> {
  @override
  void initState() {
    futureStops = fetchStops();
    super.initState();
  }

  List<Stop> listStops = [];
  Future<List<Stop>> futureStops;
  List<Marker> allMarkers = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: FutureBuilder<List<Stop>>(
          future: futureStops,
          builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
            if (snapshot.hasData) {
              listStops = snapshot.data;
              print('xdecf');
              listStops.forEach((Stops) {
                print('bedcbjhefc');
                allMarkers = listStops
                    .map(
                      (e) => Marker(
                          width: 0.2,
                          height: 0.2,
                          point: latLong.LatLng(e.stLat, e.stLat),
                          builder: (_) => Icon(
                                Icons.person_pin,
                                color: Colors.red,
                              )),
                    )
                    .take(3)
                    .toList();
                print(allMarkers);
                print('object');
              });
            }
            return FlutterMap(
                options: MapOptions(
                  center: latLong.LatLng(my coords),
                  zoom: 13.0,
                ),
                layers: [
                  TileLayerOptions(
                      urlTemplate:
                          "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
                      subdomains: ['a', 'b', 'c']),
                  MarkerLayerOptions(markers: allMarkers),
                ]);
            return Center(child: CircularProgressIndicator());
          }),

the stacktrace shows this:

I/flutter (12320): [Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance o
I/chatty  (12320): uid=10461(com.example.fl_app) 1.ui identical 41 lines
I/flutter (12320): [Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance of 'Marker', Instance o

CodePudding user response:

3K markers are way too many for performance consuming on map, both populating and displaying. You can do either way or both for better performance:

  1. populate your fetchStops() with compute (isolate)
  2. display your marker with cluster, google_maps_cluster_manager

CodePudding user response:

I solve this issue (but still don't know what was going wrong with my code yesterday, may be just device had strange behaviour)

So, I want to thank @JimChiu for his his advice on using clusters for so many markers on a map. It really works.

Before code, I want to mention which pligins I've used. For their perfomance you should have sdk: ">=2.12.0 <3.0.0"

flutter_map_marker_popup: ^1.0.0
  flutter_map: ^0.14.0
  flutter_map_marker_cluster: ^0.4.0
  latlong2: ^0.8.1 

So my task was: to show 3k coordinates (markers) on map at the same time and also to show the pop-up above them with additional info about coords. Also in my work I have to use only an open source map, so my choice fell on the OSM-map (Leaflet). And so, first, we need to create two arrays: one with your coordinates, the second with markers. When using the Future builder, in order to avoid the error "method such and such was called on null", we need to check if there is any data inside the Future builder at all. Then we use two methods: forEach and map.

  1. We use forEach for looping our coordinates
  2. We use map for populatig all the data on map.

After that we need to be careful, because if we were trying to make the return inside forEach method, the map wouldn't load. We should do it outside.

class MapPage extends StatefulWidget {
  const MapPage({Key key}) : super(key: key);

  @override
  _MapPageState createState() => _MapPageState();
}

class _MapPageState extends State<MapPage> {


  final PopupController _popupController = PopupController();

  @override
  void initState() {
    futureStops = fetchStops();
    super.initState();
  }

  Future<List<Stop>> futureStops;
  List<Marker> allMarkers = [];
  List<Stop> listStops = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: FutureBuilder<List<Stop>>(
            future: fetchStops(),
            builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
              if (snapshot.hasData) {
                listStops = snapshot.data;
                print('POINT 1');
                listStops.forEach((element) {
                  allMarkers = listStops
                      .map((e) =>
                      Marker(
                          point: latLong.LatLng(e.stLat, e.stLong),
                          builder: (_) => Icon(Icons.person_pin)))
                      .toList(growable: true);
                });
              }
              return FlutterMap(
                options: new MapOptions(
                  center: latLong.LatLng(your coords here),
                  zoom: 13,
                  plugins: [
                    MarkerClusterPlugin(),
                  ],

                  //HERE IS ON TAP OPTIONS
                ),
                layers: [
                  TileLayerOptions(
                    urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
                    subdomains: ['a', 'b', 'c'],
                  ),
                  MarkerClusterLayerOptions(
                    maxClusterRadius: 120,
                    size: Size(40, 40),
                    markers: allMarkers,
                    polygonOptions: PolygonOptions(
                        borderColor: Colors.blueAccent,
                        color: Colors.black12,
                        borderStrokeWidth: 3),
                    popupOptions: PopupOptions(
                      popupSnap: PopupSnap.mapTop,
                      popupController: _popupController,
                      popupBuilder: (_, allMarkers) => Container(
                        width: 200,
                        height: 100,
                        color: Colors.white,
                        child: GestureDetector(
                          onTap: () => debugPrint('on marker tapped'),
                          child: Text('Container popup for marker at ${allMarkers.point}'),
                        ),
                      )
                    ),
                    builder: (context, markers) {
                      return FloatingActionButton(
                        child: Text(markers.length.toString()),
                        onPressed: null,
                      );
                    },
                  ),
                ],
              );
            }
        ));
  }
}

Hope it is helpful for someone if someone also struggling.

  • Related