Google Maps InfoWindow width is overwritten even when set correctly

AlexB picture AlexB · Feb 18, 2015 · Viewed 14.7k times · Source

I'm using Google Maps API and I have some troubles about InfoWindow.

Here is a summary :

  • I'm loading the InfoWindow's content when user clicks on a marker
  • The content is a partial view, loaded thanks to an Ajax call
  • In the .done callback, I call an asynchronous method which will insert data into the InfoWindow content. I need to do this because I want the InfoWindow main content to be displayed immediately, whereas this "bonus" information could be displayed after some tenths of seconds.

This perfectly works ; but I have a white strip on the right of my InfoWindow I can't remove (see the picture below)

However, the content I load is included in a <div> with a fixed width :

<div id="div-main-infoWindow">
    <!-- All my content -->
</div>

And in my CSS, I wrote :

#div-main-infoWindow {
    width:342px !important;
}


The loading of the InfoWindow, with more details, looks like this :

$.ajax({  
            url         :    "/my-url",
            async       :    false,
            contentType :    "application/json; charset=utf-8",
            dataType    :    "json",
            type        :    "POST",
            data        :    JSON.stringify(myModel)
        }).done(function(response) {

             MarkerContent = response.Content; //The HTML content to display

             MyAsyncMethod().then(function(response) {
                 //do some formatting with response
                 return result;  //result is just a small HTML string 
             }).done(function(result1, result2) {
                 //do some formatting with result1 and result2
                 $("#myNode").html(/*formatted result*/);
             })

            //info is a global variable defined as new google.maps.InfoWindow()
            info.setOptions({
                content: MarkerContent,
                maxWidth: 342 //To be sure 
            });

            info.open(map, marker);
        });
});

The content is perfectly OK, the problem is all about this white strip.

Looking at my browser console (I reproduced it in ALL browsers), I can see this :

IW

As you can see there, my <div> containing all my data loaded from my ajax call is OK with the good size (green rectangle, corresponding to the greyed zone in the screenshot), BUT the above divs (from Google API itself, into the red rectangles) have a bigger size, from which the problem is.

The only way I found is running this jQuery script modifying the InfoWindow internal structure :

$(".gm-style-iw").next().remove();
$(".gm-style-iw").prev().children().last().width(342);
$(".gm-style-iw").prev().children(":nth-child(2)").width(342);

$(".gm-style-iw").width(342);
$(".gm-style-iw").children().first().css("overflow", "hidden");
$(".gm-style-iw").children().first().children().first().css("overflow", "hidden");
$(".gm-style-iw").parent().width(342);

Note : gm-style-iw is the class name given by Google of the div containing all the content of the InfoWindow, the one hovered on the above screenshot. I also add this rule in my CSS :

.gm-style-iw {
    width: 342px !important; //also tried with 100% !important, not better
} 

It works in the console, however, it has no effect when written in the code itself, in the .done callback, or in the domready Google Maps' event...
However, in this late case, if I encapsulate the above jQuery script in a setTimeout(), it works !! I commented the asynchronous method, so it's not this one which is guilty, but it seems domready is executed whereas 100% of the InfoWindow is not still displayed - which is contrary to the doc.

I also tried to move my info.setOptions outside the .done callback and put it at after it, no effect.

So, how can I display a "normal" InfoWindow without this white strip on the right ?
I don't want to implement InfoBubble or other custom InfoWindow library. It's a personal project and I want to understand why and where the problem is. And of course, find a solution.

Thank you for your help !

Answer

Dr.Molle picture Dr.Molle · Feb 19, 2015

It's a little bit more complex than you think.

Just some things:

  • did you notice that there is a close-button? Even when you remove the button the space will be there, because the API calculates the size of the other nodes based on this space
  • the tip must be in the center
  • there are additional containers for rounded borders and shadows
  • the size of the infoWindow will be calculated so that it fits into the viewport
  • the content must be scrollable when needed
  • the position of the infowindow must be set(therefore it's required to calculate the exact height of the infowindow)

Basically: all these things require to calculate exact sizes and positions, most of the nodes in the infowindow are absolute positioned, it's rather a technique like it will be used in DTP than you would use it in a HTML-document.

Additionally: the InfoWindows will be modified very often to fix bugs, a solution which works today may be broken tomorrow.

However, an approach which currently works for me:

  1. set the maxWidth of the infowindow to the desired width - 51 (would be 291 in this case)
  2. It's not possible to apply !important-rules via $.css , so it must be done via a stylesheet directly. To be able to access all the elements set a new class for the root-node of the infowindow(note that there may be infoWindows which you can't control, e.g. for POI's):

    google.maps.event.addListener(infowindow,'domready',function(){ 
      $('#div-main-infoWindow')//the root of the content
       .closest('.gm-style-iw')
        .parent().addClass('custom-iw');
    });
    
  3. the CSS:

  .custom-iw .gm-style-iw {
      top:15px !important;
      left:0 !important;
      border-radius:2px;
  }
  .custom-iw>div:first-child>div:nth-child(2) {
      display:none;
  }
  /** the shadow **/
  .custom-iw>div:first-child>div:last-child {
      left:0 !important;
      top:0px;
      box-shadow: rgba(0, 0, 0, 0.6) 0px 1px 6px;
      z-index:-1 !important;
  }

  .custom-iw .gm-style-iw, 
  .custom-iw .gm-style-iw>div, 
  .custom-iw .gm-style-iw>div>div {
      width:100% !important;
      max-width:100% !important;
  }
  /** set here the width **/
  .custom-iw, 
  .custom-iw>div:first-child>div:last-child {
      width:342px !important;
  }


  /** set here the desired background-color **/
  #div-main-infoWindow, 
  .custom-iw>div:first-child>div:nth-child(n-1)>div>div, 
  .custom-iw>div>div:last-child, 
  .custom-iw .gm-style-iw, 
  .custom-iw .gm-style-iw>div, 
  .custom-iw .gm-style-iw>div>div {
      background-color:orange !important;
  }

  /** close-button(note that there may be a scrollbar) **/
  .custom-iw>div:last-child {
      top:1px !important;
      right:0 !important;
  }

  /** padding of the content **/
  #div-main-infoWindow {
      padding:6px;
  }

Demo(as I said, may be broken tomorrow): http://jsfiddle.net/doktormolle/k57qojq7/