Problems with Google Maps API v3 + jQuery UI Tabs
Asked Answered
M

17

70

There are a number of problems, which seem to be fairly well-known, when using the Google Maps API to render a map within a jQuery UI tab. I've seen SO questions posted about similar issues (here and here, for example) but the solutions there only seem to work for v2 of the Maps API. Other references I checked out are here and here, along with pretty much everything I could dig up through Googling.

I've been trying to stuff a map (using v3 of the API) into a jQuery tab with mixed results. I'm using the latest versions of everything (currently jQuery 1.3.2, jQuery UI 1.7.2, don't know about Maps).

This is the markup & javascript:

<body>
    <div id="dashtabs">
        <span class="logout">
            <a href="go away">Log out</a>
        </span>
        <!-- tabs -->
        <ul class="dashtabNavigation">
            <li><a href="#first_tab" >First</a></li>
            <li><a href="#second_tab" >Second</a></li>
            <li><a href="#map_tab" >Map</a></li>
        </ul>

        <!--  tab containers -->
        <div id="first_tab">This is my first tab</div>
        <div id="second_tab">This is my second tab</div>
        <div id="map_tab">
             <div id="map_canvas"></div>
        </div>
    </div>
</body>

and

$(document).ready(function() {
    var map = null;
    $('#dashtabs').tabs();
    $('#dashtabs').bind('tabsshow', function(event, ui) {
        if (ui.panel.id == 'map_tab' && !map)
        {
            map = initializeMap();
            google.maps.event.trigger(map, 'resize');
        }
    });
});

function initializeMap() {
    // Just some canned map for now
    var latlng = new google.maps.LatLng(-34.397, 150.644);
    var myOptions = {
        zoom: 8,
        center: latlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    return new google.maps.Map($('#map_canvas')[0], myOptions);
}

And here's what I've found that does/doesn't work (for Maps API v3):

  • Using the off-left technique as described in the jQuery UI Tabs documentation (and in the answers to the two questions I linked) doesn't work at all. In fact, the best-functioning code uses the CSS .ui-tabs .ui-tabs-hide { display: none; } instead.
  • The only way to get a map to display in a tab at all is to set the CSS width and height of #map_canvas to be absolute values. Changing the width and height to auto or 100% causes the map to not display at all, even if it's already been successfully rendered (using absolute width and height).
  • I couldn't find it documented anywhere outside of the Maps API, but map.checkResize() won't work anymore. Instead, you have to fire a resize event by calling google.maps.event.trigger(map, 'resize').
  • If the map is not initialized inside of a function bound to a tabsshow event, the map itself is rendered correctly but the controls are not - most are just plain missing.

So, here are my questions:

  • Does anyone else have experience accomplishing this same feat? If so, how did you figure out what would actually work, since the documented tricks don't work for Maps API v3?
  • What about loading tab content using Ajax as per the jQuery UI docs? I haven't had a chance to play around with it but my guess is that it's going to break Maps even more. What are the chances of getting it to work (or is it not worth trying)?
  • How do I make the map fill the largest possible area? I'd like it to fill the tab and adapt to page resizes, much in the way that it's done over at maps.google.com. But, as I said, I appear to be stuck with applying only absolute width and height CSS to the map div.

Sorry if this was long-winded but this might be the only documentation for Maps API v3 + jQuery tabs. Cheers!

Module answered 15/9, 2009 at 16:21 Comment(4)
I found the google maps group to be very helpful with I did jquery + maps. I did not use the tabs or jquery ui though.Aureaaureate
All of the problems, as far as I can tell, are a direct result of putting the map into a jQuery UI tab. Though people in the maps group might have experience with this, it didn't seem like the place for this question. I might end up asking around.Module
bummer. They were very helpful with the API part but couldn't help you on the jquery side.Aureaaureate
SOLUTION THAT WORKS!!! :) #12642298Rotarian
R
22

Note: this answer received an invalid 3rd party edit which essentially replaced its content, something that a 3rd party editor should not do. However, the result may be more useful than the original, so both versions are now given below:


  • Original author Anon's version from 2010, after one edit by Anon

    google.maps.event.trigger(map, 'resize'); map.setZoom( map.getZoom() );

is suggested by http://code.google.com/p/gmaps-api-issues/issues/detail?id=1448 as a v3 substitute for v2's checkResize().

Blech - bad google, no cookie.


  • User Eugeniusz Fizdejko's complete rewrite form 2012:

For me works when adding a marker:

var marker = new google.maps.Marker({
    position: myLatlng,
    title:"Hello World!"
});

google.maps.event.addListener(map, "idle", function(){
    marker.setMap(map);
});
Ruphina answered 15/10, 2010 at 22:42 Comment(2)
Awesome. I was having this problem on a jquery mobile / phonegap app, and this fix solved the issue for me!Harpole
This lead me to my answer, the link above to code.google.com was updated a couple days ago with bootstrap tabs and this google maps issue $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { google.maps.event.trigger(map, 'resize'); map.setZoom( map.getZoom() ); })Agalloch
E
13

Actually scratch my answer above. The jQueryUI website has the answer and here it is:

Why does...

...my slider, Google Map, sIFR etc. not work when placed in a hidden (inactive) tab?

Any component that requires some dimensional computation for its initialization won't work in a hidden tab, because the tab panel itself is hidden via display: none so that any elements inside won't report their actual width and height (0 in most browsers).

There's an easy workaround. Use the off-left technique for hiding inactive tab panels. E.g. in your style sheet replace the rule for the class selector ".ui-tabs .ui-tabs-hide" with

.ui-tabs .ui-tabs-hide {
    position: absolute;
    left: -10000px;
}

For Google maps you can also resize the map once the tab is displayed like this:

$('#example').bind('tabsshow', function(event, ui) {
    if (ui.panel.id == "map-tab") {
        resizeMap();
    }
});

resizeMap() will call Google Maps' checkResize() on the particular map.

Extramural answered 18/6, 2010 at 1:50 Comment(3)
Just edit your old answer, please. On top of that, I addressed the fact that the off-left technique suggested by the jQueryUI site doesn't work in this case.Module
My apologies - I didn't know I could edit an existing comment. Being on blogs all the time, I'm just in the habit of thinking "once I spit it, I can't take it back." All I can tell you is that I have maps/streetviews working in the tab perfectly on this page: jackying.brixwork.com/showlisting.php/63/… The best I can do is show you the code, perhaps you can make comparisons and see what's missing/different.. my Streetview did NOT work for serveral days until I found the solution I posted.Extramural
What does #example refer to? Is it the map, or the ID of the tab? Is resizeMap() a V3 function for map?Troupe
R
12

Just redefine the css class for hidden tab:

.ui-tabs .ui-tabs-hide {
    position: absolute !important;
    left: -10000px !important;
    display:block !important;
}
Rutabaga answered 13/8, 2010 at 4:20 Comment(1)
good fix if you're not generating the G map - just add an on("click") to reset the css of the tab div..Herwin
H
9

This is what you can do for Google Maps v3:

google.maps.event.addListenerOnce(map, 'idle', function() {
    google.maps.event.trigger(map, 'resize');
    map.setCenter(point); // be sure to reset the map center as well
});
Hustler answered 28/5, 2012 at 19:41 Comment(1)
Im not sure how the idle event is supposed to be helpful. Even if it triggered, what good is it if the rendering is still messed up before the user decides to drag and then become idle? The resize is useful in the context of a tab show event, or in a timeout/interval though.Membership
S
4

I load the maps after the tab has been shown.

This is hacky but it worked for me. Simply store the url of the map iframe inside the iframes rel attribute like so:

<iframe width="490" height="300" rel="http://maps.google.com/maps?f=q&amp;source=s..."></iframe>

This event will set the iframe src attribute to the url inside the rel.

        $("#tabs").tabs({
            show:function(event, ui) {
                var rel = $(ui.panel).find('iframe').attr('rel');
                $(ui.panel).find('iframe').attr('src',rel);
            }
        });
Saxton answered 21/9, 2010 at 4:51 Comment(1)
ok, and how did you get from the iframe the lat and lon pos coords?Achondrite
E
4

This doesn't answer all your questions, but I've gotten it working and all the other answers are missing one thing -- when you redraw the map with the "resize" event, you will lose the place the map was centered on. So you also need to update the center of the map again with setCenter, if your map is centered on a position.

Also, you don't want to initialize the map every time the tab change is triggered, as that is not efficient and can result in extra geocodes. First, you need to save your centered location, which can be a static lat/long, or if geocoding, may look something like this:

var address = "21 Jump St, New York, NY"; 
var geocoder = new google.maps.Geocoder();    
var myOptions = {
  zoom: 16,      
  mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

var center;

geocoder.geocode( { 'address': address}, function(results, status) {
  if (status == google.maps.GeocoderStatus.OK) {        
    center = results[0].geometry.location;
    map.setCenter(center);
    var marker = new google.maps.Marker({
        map: map, 
        position: results[0].geometry.location
    });
  } else {
    alert("Geocode was not successful for the following reason: " + status);
  }
});

Then

$("#tabs").tabs();

$('#tabs').bind('tabsshow', function(event, ui) {
    if (ui.panel.id == "mapTab") {
        google.maps.event.trigger(map, "resize");
        map.setCenter(center);   // Important to add this!      
    }
});

Where 'mapTab' is the ID of your mapTab, and 'map' is the var name for your map object.

Eparchy answered 4/6, 2012 at 23:1 Comment(1)
This method of triggering the map resize also works for twitter bootstrap tabs by binding it to the tab click event :) your solution is the best one on here imoBricebriceno
M
2

Be sure that the code that initializes your map is called BEFORE the snippet that initializes your tabs.

The only annoyances I had were that a click on the map tab made the browser jump to focus on the map and that it broke out of the default border that jQuery puts around the main tabs container. I added a return false onclick call to the map tab's a tag to handle the first and a simple border-size: 0 on the main tabs div to handle the second.

All of this worked for me.

Good luck!

Maureenmaureene answered 24/3, 2010 at 12:17 Comment(0)
C
1

I've been through every forum searching for the answer to this...they all said to use the

map.checkResize()

solution....nothing seemed to work...then I...why not initialize the tab when the tab is shown so i used this

$("#servicesSlider ").tabs({        
                //event: 'mouseover'
            fx: { height: 'toggle', opacity: 'toggle'},
            show: function(event, ui) {
                  if (ui.panel.id == "service5") {
                      $(ui.panel).css("height","100%")
                    initialize()
                    }}
            });

"service5" is the id of my tab that holds my google map v3.

Hope this works for you!

Compton answered 1/12, 2009 at 19:40 Comment(2)
This worked for me, very simple and elegant. I tried the other solutions, but I suppose because my setup was different than the examples above, it didn't work (specifically the resize method call). But this did, thanks!Anticlimax
I found that this worked better using activate, not show. I'm not sure why but show seemed to freeze my tab and no allow it to ever collape again.Rathbun
C
1

I had this problem too, I was loading the maps through AJAX.

It seems the problem with percentage was to do with the panel not having any set size (the one containing the loaded markup).

Using the following code when creating the tabs helped me a lot:

$("#mainTabs").tabs({'show': function(event, ui){
  $(ui.panel).attr('style', 'width:100%;height:100%;');
  return true;
 }});
Churchwell answered 19/3, 2010 at 16:4 Comment(0)
H
1

Hey guys, this code fixes the error but in IE not working. After searching and searching, I discovered that we must add the following line and everything works to perfection:

< !--[if IE]>
< style type="text/css">
.ui-tabs .ui-tabs-hide { position: relative; }
< /style>
< ![endif]-->
Human answered 3/7, 2010 at 12:40 Comment(0)
A
0

You can call

map.fitBounds(bounds)

that will do the refresh

Armrest answered 21/1, 2010 at 17:54 Comment(1)
Only problem with fitBounds() is the map will snap back to center if you are using markers and the user dragged the map.Lordship
F
0

Very irritating problem but with a bit of a hackaround it's fixable. The key is to make the position relative #tabs adjust to the outerheight of each of the tabs when you select a new one. Here's how I did it:

$('#tabs').tabs({
   selected:0,
   'select': function(event, ui) {
    //this is the href of the tab you're selecting
    var currentTab = $(ui.tab).attr('href');
    //this is the height of the related tab plus a figure on the end to account for padding...
    var currentInner = $(currentTab + '.detail-tab').outerHeight() + 40;
    //now just apply the height of the current tab you're selecting to the entire position:relative #tabs ID
    $('#tabs').css('height', currentInner);
   }
  });

here's the css i used:

#tabs { position: relative; }
/*set the width here to whatever your column width is*/
.ui-tabs-panel{ position:absolute;top:0px; left:0; width:575px;}
.ui-tabs-panel.ui-tabs-hide { display:block !important; position:absolute;  left:-99999em; top:-9999em}
Footstool answered 18/11, 2010 at 0:32 Comment(0)
S
0

I got this working easily by Asynchronously loading the API and then simply calling loadScript from the <a> tag tied to the relevant tab from the onclick event like so:

<li><a href="#tab3" onclick="loadScript();">Maps</a></li>
Superscribe answered 4/9, 2012 at 19:28 Comment(0)
S
0

I had the same problem and none of the answers worked for me. Maybe I didn't know how to use them in my code so I added an onclick event to the tab menu to initialize Google map and it is working. I do not know if it is a good practice though.

jQuery(document).ready(function($) {
$( '#tabs' ).tabs();
var href = $('#tabs').find('a[href="#tabs-4"]');
(href).on('click',function(){
    initialize();
})});
var map;
function initialize() {
  var mapOptions = {
    zoom: 8,
    center: new google.maps.LatLng(-34.397, 150.644),
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  map = new google.maps.Map(document.getElementById('map'),
      mapOptions);
}

<div id="tabs-4">
    <div id="map" style="width:580px;height:380px;">
    </div>
</div>
Smarm answered 16/7, 2013 at 2:27 Comment(0)
S
0

Another solution for Maps API v3 (exp) and jQuery UI 1.10:

var pano = new google.maps.StreetViewPanorama(...);

$('#tabs').tabs({
  'activate': function(event, ui) {
    if (ui.newPanel[0].id == "maps-tabs-id") {
      pano.setVisible(true);
    }
  }
});
Soursop answered 15/11, 2013 at 11:51 Comment(0)
C
0

I did what Keith says and it works for me, in my case I'm using jQuery waypoints for my tabbed navigation, for better understanding here's the code I used:

In the HEAD

<head>

<!-- Google Maps -->
<script>
function initialize() {
  var mapOptions = {
    zoom: 8,
    center: new google.maps.LatLng(-34.397, 150.644)
  };

  var map = new google.maps.Map(document.getElementById('map_canvas'),
      mapOptions);
}

function loadScript() {
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp' + '&signed_in=true&callback=initialize';
  document.body.appendChild(script);
}
window.onload = loadScript;
</script>

</head>

Inside of my tabs:

<li><a href="#MyMap" onclick="loadScript();">My Map</a></li>

Then in the DIV

<div id="map_canvas"></div>

Hope this helps someone, thanks for all!

Cattish answered 30/1, 2015 at 5:7 Comment(0)
V
0

I was facing the same issue in Semantic UI, the problem was fixed while calling init(); function when a tab loads or you can bind it as well.

Venous answered 20/12, 2015 at 15:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.