Leaflet: getBounds()/fitBounds() + lots of markers = renders the map grey/unusable

Created on 8 May 2014  路  14Comments  路  Source: Leaflet/Leaflet

Hello,

Intro

First thank you for the awesome plugin, we use it at quite some projects over here. :-)

At one of our projects we make use of the marker cluster plugin (the markercluster plugin is not the problem, read below):

marker[markersData[i][0]] = L.marker([_lat, _lng], {icon: icon});
markers.addLayer(marker[markersData[i][0]]);

Then we use:

var bounds = markers.getBounds(); // [1]
map.fitBounds(bounds); // [2]
map.addLayer(markers);

Problem

Okay this usually works perfectly fine until we have a case where we want to spawn lots of markers (2000-5000 markers). For some reason, doing this renders a grey map and it's unusable. The map works just fine with less than 500 markers.

By unusable I mean the following: the map can't be dragged with the mouse, nor scroll-zoomed, the zoom buttons don't work, etc... I do can see the markers, but neither the popups open or anything.

With the .fitBounds() [2] code in (from the above code), the map gets rendered like this:
leaflet-not-ok

What we've tried

If I remove [2] (from the above code) the maps renders OK (but highly unzoomed which is what we don't want).
leaflet-ok

The .getBounds() function returns coherent data:

o.LatLngBounds
    _northEast: o.LatLng
        lat: 42.0468718
        lng: 2.7438793000000032
    _southWest: o.LatLng
        lat: 41.219172
        lng: 1.6023217

We know the problem doesn't come from the markercluster because we've tried removing it and the same issue happens.
leaflet-not-ok-2

So we're out of ideas how we might fix this by ourselves. We hope you can help us :-).

Thanks in advance!

All 14 comments

The problem is not in markers, but in several view-setting methods called consecutively. Just reduce that to one call and you'll be OK. This bug is also fixed in master and stable branches.

Could you elaborate a little bit more please?

Do you mean I should not do:

map.fitBounds(bounds);
map.addLayer(markers);

but rather something like:

map.fitBounds(bounds).addLayer(markers);

You say

If I remove 2 the maps renders OK (but highly unzoomed which is what we don't want).

That means that before fitBounds call, you have a setView or something similar earlier. There's a known Leaflet issue where if you call two view-setting methods in the same code (e.g. first setView and then immediately fitBounds), it freezes.

I'm unsure what you're talking about as I don't (at least conciously) do any setView. To clearify I'll better post a simplified version of the code:

L.tileLayer('https://tiles.lyrk.org/ls/{z}/{x}/{y}?apikey=asdf', {
    attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
    maxZoom: 18
}).addTo(map);

var markers = new L.MarkerClusterGroup();
var marker = new Array();

var markersData = [ this is full with random data ];

if(markersData.length > 0) {
    for(var i = 0; i < markersData.length; i++) {
        var _lat = markersData[i][1];
        var _lng = markersData[i][2];

        var icon = '';
        if(markersData[i][3] === 1) {
            if(markersData[i][10] === 1)
                icon = icon_inactive;
            else
                icon = icon_inactive_not;
        }
        else {
            if(markersData[i][10] === 1)
                icon = icon_active;
            else
                icon = icon_active_not;
        }

        var popup = markersData[i][4];

        if(setDistance) {
            marker_distance[markersData[i][0]] = L.latLng(mapcenter).distanceTo(L.latLng(_lat, _lng));

            if(marker_distance[markersData[i][0]] <= parseInt(distance)) {
                marker[markersData[i][0]] = L.marker([_lat, _lng], {icon: icon})
                    .bindPopup(popup);
                markers.addLayer(marker[markersData[i][0]]);
            }
        }
        else {
                marker[markersData[i][0]] = L.marker([_lat, _lng], {icon: icon})
                    .bindPopup(popup);
                markers.addLayer(marker[markersData[i][0]]);
        }
    }

    var bounds = markers.getBounds();
    map.fitBounds(bounds);
    map.addLayer(markers);
}

If you remove the fitBounds call, how does the map know what place to show?

Thank you very much for pointing me in the right direction :-).

Btw you said this is fixed in master but we're using a copy of master from 5th of May. Just out of curiousity, has the fix been added after that? I couldn't find anything looking through the commit log for the past week.

That's weird. Can you make a minimal JSFiddle test case with the master version (http://leaflet-cdn.s3.amazonaws.com/build/master/leaflet.js)? Minimal means remove as much code as possible while keeping the issue reproducible.

Hi, so I went to jsfiddle trying to reproduce it and I couldn't. So I downloaded the file to local and saw that jsfiddle puts the <script> inside the <head> and it encloses the code within a $(windows).load.

At our project we have our <script> just before the </body> and I noticed we had a small bug in our code blocking the $(windows).load line in that exact page so the code wasn't enclosed.

tl;dr -> if I enclose the code within $(windows).load it works, otherwise it shows what I said in my OP.

@Phr33d0m your map container probably doesn't have defined height at the moment of the view setting call. You need to either call map.invalidateSize() or set the height beforehand.

I have

#lfmap {
    height: 400px;
}

If that's what you mean.

I'm seeing this same sort of behavior with version 0.7.3. I am also setting the height: style="margin-top: 20px; height: 465px;" This is still happening with the master from (http://leaflet-cdn.s3.amazonaws.com/build/master/leaflet.js).

It works fine in Firefox 32.0.1 and 32.0.2, but not in Chrome 37 or 39.

adding a timeout before calling fitbounds might be a solution , it was in my case.

Whats the status of this issue? I still get this problem with 2 markers and v0.7.7

A bit of and old issue, but I had strange grouping problems with just a dozen markers. Without the call to fitBounds everything worked fine. But the fitBounds call really messed things up.

After a lot of searching without any really good solution I had a great idea (if I may say so ;):
First initialize the map with zoomlevel 1 (or 2) (zooming out as far as you can)
Then you have all your markers bundled in just one group, then in stead of calling the fitBounds function, you do:
$('#'+container.id+' .marker-cluster').first().click();

Et voila ! You use the "bult in fitBounds" of the markerCluster plugin!

PS: assuming you you are using jquery

Was this page helpful?
0 / 5 - 0 ratings