Lee Hambley
Lee Hambley

Reputation: 6370

Google Map in Twitter Bootstrap Popver

I'm using Twitter's Bootstrap, and want to show a Google Map in a popover.

The way it works right now I'm doing something like this

$ ->
  $('.thumbnails a.js-popover').popover
    html: true,
    content: ->
      uid = $(this).data('profileUid')
      popover_container = $('.popover-contents:data(profileUid=' + uid + ')')
      _.each window.Maps, (map) ->
        google.maps.event.trigger map, 'resize' // I hoped this would re-draw the map
      popover_container.html()

The popover loads it's content from a .popover-contents div which is hidden, and connected to the a with data attributes (so that I can find the correct popover to show)

The map works perfectly, when not in a popover

The map works perfectly when not in a popover, and I think it's connected with being copied via html() in jQuery to another DOM element. Twitter's bootstrap doesn't provide a modal opened callback, and I'm genuinely not sure how to make the maps work.

enter image description here

As you can see the map works correctly on the full profile page, the markup is the same (rails partial), and the javascript is shared, too - I can only assume the GoogleMaps API really doesn't like having it's dom messed with, and is thus causing issues.

Upvotes: 2

Views: 5677

Answers (3)

Roman86
Roman86

Reputation: 2309

The problem is that google maps api requires visible element for container, so you should call the api inside the shown.bs.modal event handler. Something like this:

$picker.popover({
    html: true,
    content: '<div class="superPopover">'
});

$picker.on('shown.bs.popover', function () {
    var $container = $('.superPopover');
    new google.maps.Map($container[0]);
});

Upvotes: 0

rjz
rjz

Reputation: 16510

If you're using popovers, your best bet might be to use google's static API and avoid the headaches associated with an interactive map. Borrowing a very simple case from the documentation, you might do something like this:

var options = { content: '<img src="http://maps.googleapis.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=14&size=512x512&maptype=roadmap&sensor=false">' };

$('#example').popover(options)

Wrapping it up into a reusable function yields:

var getMap = function(opts) {
  var src = "http://maps.googleapis.com/maps/api/staticmap?",
      params = $.extend({
        center: 'New York, NY',
        zoom: 14,
        size: '512x512',
        maptype: 'roadmap',
        sensor: false
      }, opts),
      query = [];

  $.each(params, function(k, v) {
    query.push(k + '=' + encodeURIComponent(v));
  });

  src += query.join('&');
  return '<img src="' + src + '" />';
}

var content = getMap({center: 'Fritz-Walter Stadion, Kaiserslautern'});
$('#example').popover({ content: content })

Upvotes: 6

Lee Hambley
Lee Hambley

Reputation: 6370

*Another valid answer might be found here, but it's not the solution I took. *

It seems to be widely accepted that rendering a Google map in an invisible DOM element leads to rendering bugs, and the solution (cribbed from http://sethmatics.com/articles/classipress-hidden-map-tab-and-redraw-google-map-canvas/ ) appears to look something like this:


jQuery('.tabprice ul.tabnavig li a').click(function() {
    if(jQuery(this).attr('href') == '#priceblock1') {
        //the element has to be visible on the page for google maps to render properly
        jQuery('#priceblock1').show();
        //rebuild the google map canvas to the proper size
        google.maps.event.trigger(map, 'resize'); 
        //ClassiPress javascript function to build map at address
        codeAddress(); 
    }
});

I do think it might be worth moving the dom element a long way off the left/right/bottom of the screen in order to avoid it flashing to the user, or doing something with Z-Indexing to make sure that the user doesn't see an unwelcome popup.

In my case, however the static maps API as suggested by rjz was perfect.

Upvotes: 1

Related Questions