Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google maps infowindow scrolling bug: How to solve for all cases?

It's a known bug that the Google Maps API shows the scrollbar for the first (time) clicked infowindow,

The issue, first time:

enter image description here

Rest of the times:

enter image description here

So I found out that adding maxWidth solved the problem,

For me, it Doesn't; If I set the maxWidth to 200px, the scrollbar dissapears, but its smaller than I need,

enter image description here

If I set 250px (size I need), the scrollbar persists

enter image description here

Any idea what could I try?

jsfiddle: http://jsfiddle.net/e0x20tvs/3/

$sescam_ventana = {
  init: function() {
    this.mapa();
  },
  mapa: function() {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = '//maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=$sescam_ventana.mapSetup';
    document.body.appendChild(script);
  },
  mapSetup: function() {
    var styles = [
      /*
			{
				stylers: [
					{ saturation: -100 }
				]
			},{
				featureType: "road",
				elementType: "geometry",
				stylers: [
					{ visibility: "simplified" }
				]
			},{
				featureType: "poi.business",
				elementType: "labels",
				stylers: [
					{ visibility: "simplified" }
				]
			}
		*/
    ];
    var styledMap = new google.maps.StyledMapType(styles, {
      name: "SESCAM"
    }); //
    var mapOptions = {
      zoom: 16,
      scrollwheel: false,
      center: new google.maps.LatLng(39.6177074, 4.9725879),
      mapTypeControlOptions: {
        mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'map_style']
      }
    }
    var handleMarkerClick = function(marker, index) {
      var $navigationMenu = jQuery('<div>');
      jQuery('.menu-item').each(function(i) {
        var $button = jQuery('<button>');
        $button.text(jQuery(this).text());
        $button.addClass(jQuery(this).data('class'));
        $navigationMenu.append($button);
      });
      if (typeof infowindow === 'undefined') {
        infowindow = new google.maps.InfoWindow({
          height: 380
        });
      }
      var centro = infoCentros[index] //helpful data
      infowindow.setContent(
        '<div class="sescam-info-window">' +
        '<h3>' + centro.nombre + '</h3>' +
        '<p>' + centro.lugar + '</h3>' +
        '<p class="titulo">Coordinador</p>' +
        '<p><strong>' + centro.coordinador.nombre + '</strong></p>' +
        '<p><a href="mailto:' + centro.coordinador.email + '">' + centro.coordinador.email + '</a></p>' +
        '<p class="titulo">Responsable</p>' +
        '<p><strong>' + centro.responsable.nombre + '</strong></p>' +
        '<p><a href="mailto:' + centro.responsable.email + '">' + centro.responsable.email + '</a></p>' +
        '<div class="menu">' + $navigationMenu.html() + '</div>' + '</div>'

      );
      infowindow.open(marker.getMap(), marker);
    }
    var handleMenu = function() {
      jQuery('body').on('click', '.menu button', function() {
        var itemClass = jQuery(this).attr('class');
        jQuery('.listado.' + itemClass).stop(true, true).slideDown().siblings('.listado').stop(true, true).slideUp();
      });
    }
    this.gmap = new google.maps.Map(document.getElementById('mapa'), mapOptions);
    this.gmap.mapTypes.set('map_style', styledMap);
    this.gmap.setMapTypeId('map_style');
    this.mapMarkers = [];
    this.mapInfoWindow = new google.maps.InfoWindow({
      height: 380
    });
    jQuery(window).resize(function() {
      $sescam_ventana.gmap.fitBounds($sescam_ventana.mapBounds);
    });
    for (var i = 0; i < this.mapMarkers.length; i++) {
      // primero eliminamos todos los markers que pudiera haber de una visualización anterior
      this.mapMarkers[i].setMap(null);
    }
    this.mapMarkers.length = 0; // reseteamos el array
    this.mapBounds = new google.maps.LatLngBounds();
    var c = 0; // de inicio no sabemos cuantos elementos tienen realmente latitud y longitud, este contador nos lo chivará
    var latlon; // lo guardamos fuera del each para poder verlo después, si resulta que es el único elemeto a mostrar
    for (var i = 0; i < infoCentros.length; i++) {
      var centro = infoCentros[i];
      var lat = centro.cordenadas.lat;
      var lon = centro.cordenadas.long;
      if (lat && lon) {
        c++;
        latlon = new google.maps.LatLng(lat, lon);
        var moptions = {
          position: latlon,
          map: $sescam_ventana.gmap
        }
        moptions.icon = 'http://icons.iconarchive.com/icons/icons-land/vista-map-markers/256/Map-Marker-Marker-Outside-Pink-icon.png';
        var marker = new google.maps.Marker(moptions);
        $sescam_ventana.mapMarkers.push(marker);
        //google.maps.event.addListener(marker, 'click', handleMarkerClick);
        google.maps.event.addListener(marker, 'click', handleMarkerClick.bind(undefined, marker, i));

        $sescam_ventana.mapBounds.extend(latlon);
      }
    }
    if (c > 1) {
      $sescam_ventana.gmap.fitBounds(this.mapBounds);
    } else {
      // si solo hay uno el fitbounds no hace un zoom ni un centrado correctos
      $sescam_ventana.gmap.setCenter(latlon);
    }
    handleMenu();
  }
}
jQuery(function() {
  $sescam_ventana.init();
});
.gmapa {
  position: relative;
  padding-bottom: 50%;
}
#mapa {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gmapa">
  <script>
    var infoCentros = [{
      "nombre": "El nombre 0",
      "texto": "Lorem ipsum sit met hamet amid0",
      "lugar": "Toledo",
      "coordinador": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "responsable": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "cordenadas": {
        "lat": 39.150544196,
        "long": -4.8019412125
      }
    }, {
      "nombre": "El nombre 1",
      "texto": "Lorem ipsum sit met hamet amid1",
      "lugar": "Toledo",
      "coordinador": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "responsable": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "cordenadas": {
        "lat": 39.150544196,
        "long": -4.7019412125
      }
    }, {
      "nombre": "El nombre 2",
      "texto": "Lorem ipsum sit met hamet amid2",
      "lugar": "Toledo",
      "coordinador": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "responsable": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "cordenadas": {
        "lat": 39.150544196,
        "long": -4.6019412125
      }
    }, {
      "nombre": "El nombre 3",
      "texto": "Lorem ipsum sit met hamet amid3",
      "lugar": "Toledo",
      "coordinador": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "responsable": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "cordenadas": {
        "lat": 39.150544196,
        "long": -4.5019412125
      }
    }, {
      "nombre": "El nombre 4",
      "texto": "Lorem ipsum sit met hamet amid4",
      "lugar": "Toledo",
      "coordinador": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "responsable": {
        "nombre": "Ana M\u00aa del Mar Alonso Fern\u00e1ndez",
        "email": "[email protected]"
      },
      "cordenadas": {
        "lat": 39.150544196,
        "long": -4.4019412125
      }
    }];
  </script>
  <div id="mapa"></div>
</div>
like image 771
Toni Michel Caubet Avatar asked Oct 30 '14 15:10

Toni Michel Caubet


People also ask

How do I change the width of InfoWindow on Google Maps?

maps. InfoWindow({ content: some_text, maxWidth: 200 }); The documentation notes that the "value is only considered if it is set before a call to open. To change the maximum width when changing content, call close, setOptions, and then open."

What is InfoWindow in Google map?

An InfoWindow displays content (usually text or images) in a popup window above the map, at a given location. The info window has a content area and a tapered stem. The tip of the stem is attached to a specified location on the map. Info windows appear as a Dialog to screen readers.

How do I know if InfoWindow is open?

Calling InfoWindow. getOpenedState() returns a boolean which reflects the state (opened/closed) of the infowindow.

What is infowindow in Google Maps?

google.maps. InfoWindow class An overlay that looks like a bubble and is often connected to a marker. This class extends MVCObject . Creates an info window with the given options. An InfoWindow can be placed on a map at a particular position or above a marker, depending on what is specified in the options.

What happens if I do not enable scrolling on the map?

Note that if you do not enable scrolling and the content exceeds the space available in the info window, the content may spill out of the info window. Best practices: For the best user experience, only one info window should be open on the map at any one time.

How do I display multiple infowindow objects on a map?

Multiple info windows make the map appear cluttered. If you only need one info window at a time, you can create just one InfoWindow object and open it at different locations or markers upon map events, such as user clicks. If you do need more than one info window, you can display multiple InfoWindow objects at the same time.

How do I place an infowindow?

An InfoWindow can be placed on a map at a particular position or above a marker, depending on what is specified in the options. Unless auto-pan is disabled, an InfoWindow will pan the map to make itself visible when it is opened.


1 Answers

EDIT

In your specific case, it has to do with the Roboto web font. It is included in the Google Maps API, but nothing is using it at the time on your page before an InfoWindow is opened so the browser has no reason to download it, and doesn't.

When you open the infoWindow, however, the browser at the point realizes it needs the font, and starts to download it, but google maps has measured the infoWindow size before the font is downloaded (see the original answer on how google maps api measures on infoWindow's size). When the font has finished downloading, the content in the infoWindow gets re-painted in the Roboto font which in fact makes the infoWindow a different (larger) size than the size that Google measured it to be before the font was downloaded and it's at this point you'll see scrollbars.

This also explains why you see scrollbars the first time - when google maps measured the infoWindow before the font was downloaded - but you won't see them after - because the font is already downloaded, whatever measurements google maps takes now will be the correct ones.

So, the solution is to

a) Render something in the Roboto font on your page (causing the browser to download that font) before the first infoWindow is open OR

b) Use a different font (one that is used elsewhere on your page, and thus is downloaded on page load) for your infoWindow content.

I'll leave the rest of my answer up because it's a common misunderstanding of how infoWindows work, and, as you pointed out with your google search, a lot of people got hung up on it.

TLDR:

Never use a parent selector (e.g. like #map-canvas) to style the HTML content of your infoWindow.

It's not a bug. Here's how google maps info window styles work:

When you tell google maps API that you want to open an infoWindow with HTML content, google dynamically creates a div element, appends it to your body tag, grabs the measurements of the dynamically created div, and then appends a div with those measurements to the map which is your infoWindow.

Here's where the trick comes into play.

Let's say this is your HTML:

<div id="map-canvas">
</div>

and this is your infoWindow content:

<h1>I'm an infoWindow</h1>
<p>Hi there!</p>

and here is your CSS:

h1 { font-size: 18px; }
#map-canvas h1 { font-size: 24px; }

Google will almost always draw this infoWindow incorrectly - because when it dynamically creates infoWindow div and appends it to the body to get the measurements, the div will have an h1 font-size of 18px. So now google has the measurements and places this div on the map, at which point the h1 font-size increases to 24px so now google is using the wrong measurements and your infoWindow will end up having scrollbars.

I've always found the easiest way to work with infoWindow CSS is to use a wrapper div and always target it, so you're infoWindow HTML content would look like:

<div class="info-window-content">
    <h1>I'm an infoWindow</h1>
    <p>Hi there!</p>
</div>

And then your CSS could look like:

/* global styles */
h1 { font-size: 18px; }
p { line-height: 1.6; }

/* info window styles */
.info-window-content h1 { font-size: 24px; }
.info-window-content p { line-height: 1.2; }

and you wouldn't end up with scrollbars in your infoWindow.

like image 75
Adam Avatar answered Oct 19 '22 19:10

Adam