Include open infowindows within bounds of map, when using fitbounds
Asked Answered
M

1

6

I have a map which contains multiple markers with infowindows. The infowindows need to be open on page load. The map is being centered using setbounds to incorporate all of the markers, which works, but it also needs to include the infowindows within the bounds. Currently the infowindows are cropped in places.

JS:

function initialize() {
    var map = new google.maps.Map(document.getElementById('map-canvas'));
    var bounds = new google.maps.LatLngBounds();
    var myLatlng1 = new google.maps.LatLng(51.525209,-0.09402479999994284)
    var contentString1 = '<div class="map-content"><p>Test1<br/ >dsfasdf<br/ >dsfasdf<br/ >dsfasdf<br/ >dsfasdf<br/ >dsfasdf<br/ >dsfasdf</p></div>'
    var infowindow1 = new google.maps.InfoWindow({content: contentString1});
    var marker1 = new google.maps.Marker({position: myLatlng1,map: map,title: 'Test1'});

    google.maps.event.addListener(marker1, 'click', function() {infowindow1.open(map,marker1);});
    infowindow1.open(map,marker1);
    bounds.extend(myLatlng1);

    var myLatlng2 = new google.maps.LatLng(51.52106840183588,-0.10866641049801729)
    var contentString2 = '<div class="map-content"><p><br/ >dsfasdf<br/ >dsfasdf<br/ >dsfasdf<br/ >dsfasdf<br/ >dsfasdf</p></div>'
    var infowindow2 = new google.maps.InfoWindow({content: contentString2});
    var marker2 = new google.maps.Marker({position: myLatlng2,map: map,title: 'Test2'});
    google.maps.event.addListener(marker2, 'click', function() {infowindow2.open(map,marker2);});
    infowindow2.open(map,marker2);
    bounds.extend(myLatlng2)

    //  Fit these bounds to the map
    map.fitBounds(bounds);
}
google.maps.event.addDomListener(window, 'load', initialize);

CSS:

#map-canvas { width: 100%; height: 520px; }

You can see a fiddle here: http://jsfiddle.net/mKKVM/

Can anyone suggest how to get the infowindows inside the bounds?

Mackintosh answered 8/1, 2014 at 17:4 Comment(2)
The code in your jsfiddle is really ugly, its unlookable. Have you heard of indentation? :) BTW the javascript code is supposed to be placed in javascript section (bottom left), you have it in HTML section.Pedestrianize
Thanks for the feedback Tomas. The goal is for all of the content to appear within the bounds of the map. Clicking the markers pans the map and may move other markers (partially) out of view, which is not satisfactory.Mackintosh
L
4

Proof of concept jsfiddle

  1. Display the map normally
  2. Calculate the pixel distance from the marker anchor to the upper edge of the infowindow
  3. Calculate the pixel distance from the marker anchor to the left edge of the infowindow
  4. Calculate the pixel distance from the marker anchor to the right edge of the infowindow
  5. Extend the the original bounds with two points made from the right corner of the bounds plus half the width of the infowindow and the top of the bounds plus the height of the infowindow.
  6. Extend the the original bounds with two points made from the left corner of the bounds minus half the width of the infowindow and the top of the bounds plus the height of the infowindow.
  7. fit the map to the new bounds.

Probably can be refined to use 3 points top center, left center and right center, this is a first cut, proof of concept, can probably be cleaned up and refined.

function initialize() {
  var map = new google.maps.Map(document.getElementById('map-canvas'));
  var projection = null; 
  google.maps.event.addListener(map,'projection_changed', function() {
    projection = map.getProjection();
  }); 

  var bounds = new google.maps.LatLngBounds();
  if (!projection) 
    google.maps.event.addListener(map, 'idle', computeBounds);
  else 
    computeBounds();

  var myLatlng1 = new google.maps.LatLng(51.525209,-0.09402479999994284);
  bounds.extend(myLatlng1);
  var myLatlng2 = new google.maps.LatLng(51.52106840183588,-0.10866641049801729);
  bounds.extend(myLatlng2);
  //  Fit these bounds to the map
  map.fitBounds(bounds);

  function computeBounds() {    

    var contentString1 = '<div class="map-content"><p>Test1<br />dsfasdf<br />dsfasdf<br />dsfasdf<br />dsfasdf<br />dsfasdf<br />dsfasdf</p></div>'
    var infowindow1 = new google.maps.InfoWindow({content: contentString1});
    var marker1 = new google.maps.Marker({position: myLatlng1,map: map,title: 'Test1'});

    google.maps.event.addListener(marker1, 'click', function() {
      infowindow1.open(map,marker1);
    });
    infowindow1.open(map,marker1);
    google.maps.event.addListenerOnce(infowindow1,'domready',calcInfoWindowBounds); 

    var contentString2 = '<div class="map-content"><p><br />dsfasdf<br />dsfasdf<br />dsfasdf<br />dsfasdf<br />dsfasdf</p></div>'
    var infowindow2 = new google.maps.InfoWindow({content: contentString2});
    var marker2 = new google.maps.Marker({position: myLatlng2,map: map,title: 'Test2'});
    google.maps.event.addListener(marker2, 'click', function() {
      infowindow2.open(map,marker2);
    });
    infowindow2.open(map,marker2);

    google.maps.event.addListenerOnce(infowindow2,'domready',calcInfoWindowBounds); 

    function calcInfoWindowBounds(){
      domEls = document.getElementsByClassName('map-content');
      var markerSpace = 32+8;
      var maxTop = 0;
      var maxLeft = 0;
      var maxRight = 0;
      for (var i=0; i<domEls.length; i++) {
        var topOfWindow = domEls[i].offsetHeight + markerSpace;
        var leftOfWindow = domEls[i].offsetWidth/2;
        var rightOfWindow = domEls[i].offsetWidth/2;

        if (topOfWindow > maxTop) maxTop = topOfWindow;
        if (leftOfWindow > maxLeft) maxLeft = leftOfWindow;
        if (rightOfWindow > maxRight) maxRight = rightOfWindow;
      }

      var leftBounds = projection.fromLatLngToPoint(new google.maps.LatLng(bounds.getNorthEast().lat(),bounds.getSouththWest().lng()));
      var rightBounds = projection.fromLatLngToPoint(new google.maps.LatLng(bounds.getNorthEast()));
      var topBounds0 = rightBounds.y + maxTop;
      var rightBounds0 = rightBounds.x + maxRight;
      var leftBounds0 = leftBounds.x - maxLeft;
      bounds.extend(projection.fromPointToLatLng(leftBounds0,topBounds0));
      bounds.extend(projection.fromPointToLatLng(rightBounds0,topBounds0));
      map.fitBounds(bounds);
    }   

  }

}
google.maps.event.addDomListener(window, 'load', initialize);
Laparotomy answered 9/1, 2014 at 5:21 Comment(3)
getSouththWest() should be getSouthWest(), I guess. Then - InvalidValueError: in property lat: not a number on a line var rightBounds = . This line seems somehow turning one subproperty of bounds object to NaN: imgur.com/RMZOlPi.pngDebris
there is infinite loop right there. Whats the problem? I have long infoBox like this, its not working properly. jsfiddle.net/tayfunyasar/H7bPE/27Achilles
There is a bug. Doesn' work as @Debris said. var leftBounds = projection.fromLatLngToPoint(new google.maps.LatLng(bounds.getNorthEast().lat(),bounds.getSouthWest().lng())); var rightBounds = projection.fromLatLngToPoint(new google.maps.LatLng(bounds.getNorthEast().lat(), bounds.getNorthEast().lng()));Administer

© 2022 - 2024 — McMap. All rights reserved.