Skip to content

Map gets super laggy when there are a lot of Markers #824

@TheLastGimbus

Description

@TheLastGimbus

Hi there!

I am currently making an app which will have a lot of markers - around 4000 spread across whole country. After some testing, it got obvious that all of this gets super laggy

When I use all 3.5k markers and zoom on area with no markers at all, and start dragging the map, I get ~12 fps, on phisical Android tablet in profile mode

After some debugging, print()ing and Stopwatch()ing, I traced which parts use the most time:

In lib/src/layer/marker_layer.dart -> MarkerLayer -> build(), there is a for-loop that iterates over all given Markerks:

for (var markerOpt in markerOpts.markers) {

The whole thing was taking ~25ms, and with Stopwatch(), I traced which parts of loop use the most time:

// I did it like this:
int sumStep = 0;
for(var i in list){
  var w = Stopwatch()..start();
  i.someStep();
  sumStep += w.elapsedMicroseconds();
  w.reset();
  // Of course, some precision is lost, because some steps take 1.something microsecond
}
print('Step: $sumStep');  // Summed microseconds

This was taking around 7500 us:

var pos = map.project(markerOpt.point);

This 3600:

pos = pos.multiplyBy(map.getZoomScale(map.zoom, map.zoom)) -
map.getPixelOrigin();

And the rest around 0:

if (!_boundsContainsMarker(markerOpt)) {
continue;
}
markers.add(
Positioned(
width: markerOpt.width,
height: markerOpt.height,
left: pixelPosX,
top: pixelPosY,
child: markerOpt.builder(context),
),
);

So I started to dig into .project():

CustomPoint project(LatLng latlng, [double zoom]) {
zoom ??= _zoom;
return options.crs.latLngToPoint(latlng, zoom);
}

CustomPoint latLngToPoint(LatLng latlng, double zoom) {
try {
var projectedPoint = projection.project(latlng);
var scale = this.scale(zoom);
return transformation.transform(projectedPoint, scale.toDouble());
} catch (e) {
return CustomPoint(0.0, 0.0);
}
}

this.scale() and transformation.transform() don't seem to be expensive - they are only some basic calculations...

So, projection.project:

@override
CustomPoint project(LatLng latlng) {
var point = epsg4326.transform(
proj4Projection, proj4.Point(x: latlng.longitude, y: latlng.latitude));
return CustomPoint(point.x, point.y);
}

https://github.com/maRci002/proj4dart/blob/7eb11da840ce21c78c017e0a89ee0332ba5a60e3/lib/src/classes/projection.dart#L152

Okay... this ^ is big, and not even a part of this repo, so I don't think we can do anything about it...

Conclusions

While re-building MarkerLayer (which happens constantly while dragging the map), we are doing some expensive calculations, which slow down the whole map - that is, calculating some position from LatLng

// I didn't dig into pos.multiply (step which was taking 3600us), and I don't really know what it's doing...

I'm fresh into this project and I don't know much about mapping, but it seems like we could somehow cache just the projection, and apply only scale and transformations - since only them really change when you drag the map

(This generally seems related #768, but discussion there got kinda chaotic, not knowing what issue actually was, so I'm making this separate)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions