Leaflet map not showing properly in bootstrap 3.0 modal
Asked Answered
S

11

26

i have a big problem. i want to open a leaflet map in a modal. but the map is not showing properly. the tiles are not loading.

here is the script:

https://codeply.com/p/TYUqgVvYAQ

<a href="#myModal" role="button" class="btn btn-primary" data-toggle="modal">Open Map</a>

<div id="myModal" class="modal">
<div class="modal-dialog">
  <div class="modal-content">
    <div class="modal-header">
      <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
      <h4 class="modal-title">Map</h4>
    </div>
    <div class="modal-body">
      <div class="modal-body" id="map-canvas"></div>
    </div>
    <div class="modal-footer">
      <button type="button" class="btn" data-dismiss="modal" aria-hidden="true">OK</button>
    </div>
  </div>
</div>
$.getScript('http://cdn.leafletjs.com/leaflet-0.7/leaflet.js',function(){

 /* map settings */
 var map = new L.Map('map-canvas');
 var cloudmade = new    L.TileLayer('http://{s}.tile.cloudmade.com/f1376bb0c116495e8cb9121360802fb0/997/256/{z}/{x} /{y}.png', {
 attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a>   contributors, Imagery © <a href="http://cloudmade.com">CloudMade</a>',
 maxZoom: 18
 });
 map.addLayer(cloudmade).setView(new L.LatLng(41.52, -71.09), 13);


 });

any help much apreciated

Stanfill answered 5/12, 2013 at 13:0 Comment(0)
W
62

I think what is happening is that, when the map is created, the container width/height for your `map-canvas' element has not yet been adjusted to the width/height of the modal dialog. This causes the map size to be incorrect (smaller) than what it should be.

You can fix this by calling map.invalidateSize(). This will work to re-adjust the width/height bounds of the L.Map's container.

You can automatically call this by hooking into the event where the Bootstrap modal becomes shown.

$('#myModal').on('show.bs.modal', function(){
  setTimeout(function() {
    map.invalidateSize();
  }, 10);
 });

Insert this code into your JavaScript. When the modal is shown, the map will then invalidate its size. The timeout is because there may be some animation/transition time for the modal to display and be added to the DOM.

Woad answered 5/12, 2013 at 14:19 Comment(4)
maybe you can help me out with this also: #20404674 :)Stanfill
In some cases 10 milliseconds could be a very small time considering the time that takes the modal to be fully loaded. Its a good idea increase the time before invalidateSize() is called and/or put a refresh button in the modal to call that function when it gets clicked.Virescent
A 'refresh' button would certainly provide a gaurentee.Woad
My issue wasn't modal related but still missing. I had to add a dimension to style. I choose to go with height. <div id='map-canvas' style='height:360px;'></div>Rigadoon
C
25

You should probably avoid using setTimeout with a randomly chosen delay. A better way using the 'shown.bs.modal' event instead of 'show.bs.modal':

modal.on('shown.bs.modal', function(){
    setTimeout(function() {
        map.invalidateSize();
   }, 1);
})

Or use underscore's defer :

modal.on('shown.bs.modal', function(){
    _.defer(map.invalidateSize.bind(map));
})
Coulson answered 6/11, 2014 at 17:55 Comment(2)
^ This should be the accepted answer. Additionally because the 'shown' event is fired once the modal is visible you no longer need to queue the invalidateSize() method do you? You can just use modal.on('shown.bs.modal', function () { map.invalidateSize(); }); (source: getbootstrap.com/javascript/#modals-events)Sleet
Yeah, this is better.Woad
P
8

I use this workaround:

.modal {
  visibility: hidden;
  display: block;
}

.modal[aria-hidden='false'] {
  visibility: visible;
  display: block;
}
Publication answered 25/5, 2015 at 3:57 Comment(0)
A
2

This works for me, you can read here

map.whenReady(() => {
    console.log('Map ready');
    setTimeout(() => {
        map.invalidateSize();
    }, 0);
});
Alister answered 30/11, 2019 at 3:15 Comment(0)
T
2

I tried map.invalidateSize() but not fixed.

finaly it fixed by this:

$('#map-modal').on('shown.bs.modal', function(event) {});

In the function, put the codes related to loading the map.

Thermae answered 7/11, 2022 at 9:13 Comment(2)
This answer to an 8 year old question is not helpful: it speaks of a specific solution for someone else.Ridenour
@Ridenour But after a few hours of searching, I found this answer that was my solution and I'm sure it will be the solution of many others.Thermae
E
0

This worked for me -

 $('#gmap').on('shown.bs.tab', function (e) {
    //call the clear map event first
    clearMap();
    //resize the map - this is the important part for you
   map.invalidateSize(true);
   //load the map once all layers cleared
   loadMap();
})
Erythritol answered 31/10, 2017 at 6:48 Comment(0)
B
0

leaflet map uncorrect display on load can be solved with this :

  var mapid = $(this).find('[id^=leaflet-map]').attr('id');
  var map = settings.leaflet[mapid].lMap;
  map.invalidateSize();
Baro answered 6/1, 2020 at 15:9 Comment(0)
T
0

How I solved this issue: init map in main window. Then move map to opened modal.

Tish answered 7/7, 2020 at 8:23 Comment(0)
P
0

First, create the map in div outside of the Moodle

<div>
  <div class="modal-body" id="map-canvas" style="width: 100%;height: 300px;"></div>
</div>

And write same js code :

 /* map settings */
 var map = new L.Map('map-canvas');
 var cloudmade = new    L.TileLayer('http://{s}.tile.cloudmade.com/f1376bb0c116495e8cb9121360802fb0/997/256/{z}/{x} /{y}.png', {
 attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a>   contributors, Imagery © <a href="http://cloudmade.com">CloudMade</a>',
 maxZoom: 18
 });
 map.addLayer(cloudmade).setView(new L.LatLng(41.52, -71.09), 13);


 });

Then move the map to the Moodle :

$('#map-canvas').appendTo('.modal-body');
Pomiculture answered 13/6, 2023 at 6:31 Comment(0)
L
0

Just add this map.invalidateSize() code inside the shown.bs.modal custom event callback. Then no need any setTimeout() function.

$('#yourModalElementId').on('shown.bs.modal', function(){
    map.invalidateSize();
});
Leicestershire answered 1/2 at 10:29 Comment(0)
I
-1

for vue.js and nuxt.js developers , probably it's because of using v-show or v-if but you shouldn't use v-if and instead use v-show. after that the only thing u need is using client-only tag like this:

<client-only>
<div v-show="someVariable" id="vShowOrVIfExample">
<div id="map-wrap" style="height: 100vh">
   <l-map :zoom=13 :center="[55.9464418,8.1277591]">
     <l-tile-layer url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"></l-tile-layer>
     <l-marker :lat-lng="[55.9464418,8.1277591]"></l-marker>
   </l-map>
 </div>
</div>
</client-only>
Isador answered 19/11, 2021 at 7:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.