Preventing Google Maps Move After Displaying Infowindow

16,271

Solution 1

In your declaration for setting the info window options infowindow.setOptions, add the following option to disable the panning of the map when the infowindow is displayed, disableAutoPan : true.

However this will also mean you'll need to calculate the real estate you have available to display the infowindow on your map and give it a position using the position option. Otherwise it won't be guaranteed that your infowindow will be completely visible on the map.

https://developers.google.com/maps/documentation/javascript/reference#InfoWindowOptions

EDIT: How to calculate screen real estate

I realize I was pretty vague with my suggestion to calculate the screen real estate available to set the position of your infowindow, when part of your question was to actually set the infowindow's position. So I've provided an update to my answer on how you can calculate the screen real estate and adjust your infowindow's position.

The key is to first convert your points from LatLng to pixels, and find out the pixel coordinate of the marker on the map with relation to the pixel coordinate of the map's center. The following snippet demonstrates how this can be done.

getPixelFromLatLng: function (latLng) {
    var projection = this.map.getProjection();
    //refer to the google.maps.Projection object in the Maps API reference
    var point = projection.fromLatLngToPoint(latLng);
    return point;
}

Once you've got your pixel coordinates, you'll need to find out which quadrant of the map canvas the marker is currently residing in. This is achieved by comparing the X and Y coordinates of the marker to the map, like so:

quadrant += (point.y > center.y) ? "b" : "t";
quadrant += (point.x < center.x) ? "l" : "r";

Here, I'm determining if the point is in the bottom right, bottom left, top right or top left quadrant of the map based on it's relative position to the map's center. Keep in mind this is why we use pixels as opposed to LatLng values, because LatLng values will always yield the same result - but reality is the marker can be in any quadrant of the map canvas depending on panning.

Once you know which quadrant the marker is in, you can give offset values to the infowindow to position it so it's visible on the map - like so:

if (quadrant == "tr") {
    offset = new google.maps.Size(-70, 185);
} else if (quadrant == "tl") {
    offset = new google.maps.Size(70, 185);
} else if (quadrant == "br") {
    offset = new google.maps.Size(-70, 20);
} else if (quadrant == "bl") {
    offset = new google.maps.Size(70, 20);
}
//these values are subject to change based on map canvas size, infowindow size

Once the offset value is determined you can just adjust the pixelOffset of your infowindow on whatever listener you have invoking the infoWindow.open() method. This is done by using the setOptions() method for infowindows:

infowindow.setOptions({pixelOffset : self.getInfowindowOffset(self.map, marker)}); 

Here is a working JSFiddle example of the solution described above.

Note: You will notice the annoying "arrow" on the infowindow displaying desbite the position of your infowindow, this is part of the default Google Map's setting for infowindows and I could not find a proper way of getting rid of it. There was a suggestion here, but I couldn't get it to work. Alternatively you can use the infobox library or the infobubble library - which gives you more styling options.

Solution 2

Suvi Vignarajah's answer is great, what I didn't like about it was how unpredictable the position of the window is near the edges.

I tweaked it so that the bubble glues to the wall as it should be expected: http://jsfiddle.net/z5NaG/5/

The only condition is that you need to know the width & height of the infoWindow, you can position it quite nicely. You would work it out through the maps' pixels. If you don't know it you could initialize the InfoWindow offscreen, get it's size and proceed opening it again at the right spot. Ugly but would work.

First initialize on overlay at time of map initialization by running this function:

    ourOverlay:null,
    createOverlay:function(){
        this.ourOverlay = new google.maps.OverlayView();
        this.ourOverlay.draw = function() {};
        this.ourOverlay.setMap(this.map);
    },

Then at open event adjust the offset like so:

getInfowindowOffset: function (map, marker) {
    // Settings
    var iwWidth = 240; // InfoWindow width 
    var iwHeight = 190; // InfoWindow Height
    var xOffset = 0;
    var yOffset = 0;

    // Our point of interest
    var location = this.ourOverlay.getProjection().fromLatLngToContainerPixel(marker.getPosition()); 

    // Get Edges of map in pixels: Sout West corner and North East corner
    var swp = this.ourOverlay.getProjection().fromLatLngToContainerPixel(map.getBounds().getSouthWest()); 
    var nep = this.ourOverlay.getProjection().fromLatLngToContainerPixel(map.getBounds().getNorthEast()); 

    // Horizontal Adjustment
    if(location.x<iwWidth/2){
        xOffset= iwWidth/2-location.x;
    }else if(location.x>nep.x-iwWidth/2){
        xOffset = (nep.x-iwWidth/2)-location.x ;
    }

    // Vertical Adjustment
    if(location.y<iwHeight){
        yOffset = location.y + iwHeight-(location.y-nep.y);
    }

    // Return it
    return new google.maps.Size(xOffset, yOffset);

},

And the result is pretty nice, but this triangle seems out of place now.

You can use InfoBox to remove the pointy arrow on bottom:

            GmapsManager.infowindow = new InfoBox({
            content:'',
            alignBottom: true,
            closeBoxURL: "",
        });

and style the bubble with the following code:

.infobox-popup{
    background: #fff;
    -webkit-border-radius: 3px;
    border-radius: 3px;
    padding: 5px;
    margin-left: -100px;
    margin-bottom: 30px;
    width: 200px;
    -webkit-box-shadow: 0 0 1px 0 #595959;
    box-shadow: 0 0 1px 0 #595959;
}
Share:
16,271

Related videos on Youtube

Dan NoNeed
Author by

Dan NoNeed

I'm a frontend and backend developer living in Istanbul, Turkey. I like to use Codeigniter, Laravel, jQuery, HTML5, CSS3 and lots of other web techniques. I spend most of the time on Internet, but on my spare times I like to compose digital music.

Updated on June 05, 2022

Comments

  • Dan NoNeed
    Dan NoNeed almost 2 years

    I'm trying to display a infowindow on a Google Maps. It displays perfect, when you hover over a marker it loads up a infowindow but the map jumps to fit in the window. I don't want the map to move but rather infowindow set its position according to map. Booking.com has something like this.

    EDIT: Added my code

    Here is the stripped down version of my code. I'm getting all the info from an AJAX service and this service returns response (which holds some more info too).

    $.ajax({
        url: 'URL',
        dataType: "json",
        type: "GET",
        success: function(response) {
            // delete all markers
            clearOverlays();
    
            var infowindow = new google.maps.InfoWindow();
    
            for (var i = 0; i < response.length; i++) {
                item = response[i];
    
                var marker = new google.maps.Marker({
                    position: new google.maps.LatLng(item.lat, item.lng),
                    map: map,
                    url: item.detail_url
                });
    
                markersArray.push(marker);
    
                // display infowindow
                google.maps.event.addListener(marker, "mouseover", (function(marker, item) {
                    return function() {
                        infowindow.setOptions({
                            content: 'SOME CONTENT HERE FOR INFOWINDOW'
                        });
    
                        infowindow.open(map, marker);
                    }
                })(marker, item));
    
                // remove infowindow
                google.maps.event.addListener(marker, 'mouseout', function() {
                    infowindow.close();
                });
    
                // marker click
                google.maps.event.addListener(marker, 'click', function() {
                    window.location.href = marker.url;
                });
            }
        }
    });
    

    As you can see below, the first image shows the infowindow displayed at bottom of marker while second one shows the infowindow displayed on top of the marker. The map doesn't move but infowindow sets its position within the boundries of the map.

    Infowindow bottom of marker Infowindow on top of marker

  • Jordi Castilla
    Jordi Castilla almost 8 years
    buddy you saved my day, if you can fix the broken links will be amazing (I already fixed infobox one)