first render works, second render is not centered

3,751 views
Skip to first unread message

logicalcat

unread,
May 8, 2012, 4:38:33 PM5/8/12
to leafl...@googlegroups.com
Hello all, I have a mysterious problem where a simple map (just a single marker) renders fine the first time, but a second try on the same page (via ajax without page refresh) does not center the marker and fails to load some of the tiles. The point seems to be rendering in the NW corner just out of view.

I have tried making the map and layer global and removing the layer between renders (e.g. map.removeLayer(cloudmade) ) and just deleting/re-adding the whole containing div. Makes no difference. 

The exact setup is a bit complex but goes something like this:

1. page is rendered with a hidden modal dialog containing the map div (#leaflet_map)
2. user clicks a table row
3. ajax callback retrieves Lat/Lon pair
4. a function is called to create the map with the lat/lon (just like the simple London example)
5. modal dialog show() method make the modal dialog with map visible

Thanks for any suggestions.


Charles Bedrosian

unread,
May 8, 2012, 4:44:01 PM5/8/12
to leafl...@googlegroups.com
Can you share the static files?

Sent from my iPhone

Jason Sanford

unread,
May 8, 2012, 4:52:50 PM5/8/12
to leafl...@googlegroups.com
After showing the map you might want to trigger a map resize.

myMap.invalidateSize();

logicalcat

unread,
May 8, 2012, 5:48:39 PM5/8/12
to leafl...@googlegroups.com
Calling invalidateSize() had no effect. I did notice that although getCenter() stayed the same on the second render, getBounds() had a different lat/lon pair. However, when I saved the bounds and tried to force it using map.fitBounds(bounds) I got some weird results--it looked like it went to maximum zoom (fuzzy pixels) and I couldn't unzoom. Trying to force the new/old zoom didn't have any effect.

The bounds weirdness is in the attached screenshot file. The first pair are correct, the second pair are wrong. Maybe it's a zoom thing?


On Tuesday, May 8, 2012 1:52:50 PM UTC-7, Jason wrote:
After showing the map you might want to trigger a map resize.

myMap.invalidateSize();
Screenshot from 2012-05-08 14:46:48.png

logicalcat

unread,
May 8, 2012, 5:50:17 PM5/8/12
to leafl...@googlegroups.com
Not sure what you mean, Charles. The javascript itself?


On Tuesday, May 8, 2012 1:44:01 PM UTC-7, charles wrote:
Can you share the static files?

Sent from my iPhone

logicalcat

unread,
May 8, 2012, 5:57:32 PM5/8/12
to leafl...@googlegroups.com
Here's the full map function. The only thing happening "offstage" is that the leaflet_map div is getting removed via jQuery before this gets called.

   function map_point(lat,lon){
      
      console.log("rendering map with "+lat+" "+lon);
  
      if (lat === undefined || lon === undefined){
        var msg = "<div class='well'><br><br>Sorry, not enough data (lat/lon points or polygon) to render a map.</d    iv>"
        $('#col_r').html(msg);
        return;
      }
  
      var a_point = new L.LatLng(lat,lon);
  
      var map = new L.Map('leaflet_map',{
        center: a_point,
        zoom: 13
      });
  
      var cloudmadeAttribution = '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>, Imagery © <a href="http://cloudmade.com"    >CloudMade</a>'
  
      var cloudmade = new L.TileLayer(cloudmadeURL, {
        attribution: cloudmadeAttribution,
        maxZoom: 18
      });
  
      var bounds = map.getBounds();
      var zoom = map.getZoom();
  
      console.log(bounds);
  
      //map.removeLayer(cloudmade); 
     map.addLayer(cloudmade);
     //map.setView(a_point,13,true)
     //map.fitBounds(bounds);
     //map.setZoom(zoom);
     map.invalidateSize();
 
     var a_marker = new L.Marker(a_point);
     map.addLayer(a_marker);
 
   }

logicalcat

unread,
May 8, 2012, 8:11:40 PM5/8/12
to leafl...@googlegroups.com
So...after much searching, the map.getSize() method is returning valid points the first time and (0,0) the second time. The documentation says that getSize() represents the "current size of the map container" which I'm guessing is the top-level div id ("leaflet_map" in my case).

I inspected the entire dom of the first and second render and the only differences are that:

1. the first render contains more tiles than the second one (obviously)
2. the marker point transform coordinates are zeros on the second run. Not sure what that means.

<div class="leaflet-marker-pane"><img src="http://localhost:3000/assets/images/marker.png" class="leaflet-marker-icon leaflet-clickable" style="margin-left: -13px; margin-top: -41px; width: 25px; height: 41px; -webkit-transform: translate3d(190px, 243px, 0px); z-index: 243; ">

<div class="leaflet-marker-pane"><img src="http://localhost:3000/assets/images/marker.png" class="leaflet-marker-icon leaflet-clickable" style="margin-left: -13px; margin-top: -41px; width: 25px; height: 41px; -webkit-transform: translate3d(0px, 0px, 0px); z-index: 0; ">

Is this a bug? Under what circumstances would getSize() return zeros?

Thanks!

logicalcat

unread,
May 9, 2012, 7:21:28 PM5/9/12
to leafl...@googlegroups.com
SOLVED (sort of)...

The complexity of my twitter bootstrap modal dialog + ajax was somehow preventing the getSize (and related initialization) to get the correct dimensions of the map container. In my case, I have to deal with the possibility that an entity might not be mappable and adjust the map-container height if it is. It was cleaner to do it all in one ajax call where I was dynamically inserting a map container only when needed; this was causing the pain. I'm not sure why the first render was fine but not subsequent renders (maybe bootstrap adding block styling?) but the solution was to:

1. move the map initialization to a global variable
2. leave a map-container div on the page even if an entity is not mappable
3. add something like: $('#map-container').css('height','300px') to deal with dynamic height before calling map.setView

It's a bit messier, but seemed like the best option since map.invalidateSize() wasn't working for me. There's no real cost since tiles never get rendered.

Anyway leaflet is still SOOOO much cooler than the other stuff I've seen.




On Tuesday, May 8, 2012 1:38:33 PM UTC-7, logicalcat wrote:

Jordan B

unread,
Feb 6, 2013, 8:14:34 PM2/6/13
to leafl...@googlegroups.com
Thanks for this, logicalcat.
I was having the exact same problem when using multiple maps and hiding them. When I showed them again, the map would be zoomed out in the northwest corner, and when zooming in, tiles were missing or the whole map would disappear. I am using bootstrap modals as well though I don't know if that had anything to do with it.
Interestingly, invalidateSize() DID work for me, and .css({height:'300px'}) did not. I did not need to call setView or set the css height, I just ran invalidateSize() and the map would retain its state when being shown again. I'm using the master branch version of leaflet.
Anyway, your post lead me to the right solution, so thank you.

Qman

unread,
Jun 9, 2013, 9:47:17 PM6/9/13
to leafl...@googlegroups.com
Hi,

I have a similar issue to show a leaflet map on a larger modal window when a button is clicked. It used to work with Bootstrap-2.2 like this (with map.invalidateSize):


However when I upgrade to bootstrap-2.3, it shows similar behavior like that you described(on Chrome and IE, fine on Firefox) : when the modal window is opened for the second time, map tiles are not displayed within the full modal window. Resizing the window brings the map to normal but couldn't achieve this with any map functions:


tried your suggestions without success, what version of bootstrap/leaflet are you using?

Thanks,

Qman

notio...@gmail.com

unread,
Jan 5, 2014, 12:56:13 PM1/5/14
to leafl...@googlegroups.com
I also have something similar at work (not using bootstrap).  The issue only occurs when the container is not visible. 

When the map is initialized I can typically use a very simple 

gisApp.map.setView([35.3486655, -98.6767351],7);

and the map looks fine (see file whenMapInitializedVisible.PNG)

When the container is not visible, this does not work even when using invalidateSize();

I've tried the suggested manipulation of the css, but without success (with FF and Chrome).

The setView is working because I can see the top-left partial tile, but the rest of the map is not displayed (see file whenMapInitializedNotVisible.PNG).
whenMapInitializedVisible.PNG
whenMapInitializedNotVisible.PNG
Reply all
Reply to author
Forward
0 new messages