Google Maps v3 fitBounds inconsistent zoom

1.1k views Asked by At

having a very strange problem.

A: One method of my map works fine. User sets start point and end point and map is created and the fitBounds.extend(bounds) sets zoom level appropriately to encompass the start/end markers on the map.

B: The second method is if the user sets a start point but not and end point, but based on other user interests I get retrieve and end point for them and plot it on the map using the same functions as method A. However, upon fitBounds.extend(bounds) it sets the zoom level way out at 4 (country level). Then I have to force set the zoom.

It doesn't matter when at any point the user does method A (before or after method B)...when its method A, the zoom level is correct. When its method B its always to zoom level 4.

...but all using the same functions.

Both methods accurately put the markers on the map and accurately draw the route between the markers. Just on method A, the auto zoom is correct and on method B the zoom is always set to 4.

If user does A, its right...then B happens, its zooms out...does B again it stays zoomed out...does A again it goes back to proper zoom.

Driving me nuts here!

My map object is "setMap", it is a global var

function setMapBounds(start,end) {
  mapBounds = new google.maps.LatLngBounds();
  mapBounds.extend(start.position);
  mapBounds.extend(end.position) ;
  setMap.fitBounds(mapBounds) ;
}

function addMarkers(newMarkers) {  // an array of map points.
  var tempMarkers = [] ;

  for (var x=0;x<newMarkers.length;x++) {
    var tempLatlon = new google.maps.LatLng(newMarkers[x].lat,newMarkers[x].lon) ;
    var tempMarker = createMarker(tempLatlon,newMarkers[x].img,newMarkers[x].title) ;
    tempMarkers.push(tempMarker) ;
  }
  return tempMarkers ;
}

function createMarker(latlon,img,title) {
  var marker = new google.maps.Marker({
    map:setMap,
    position:latlon,
    icon: img,
    title:title
  }) ;
  return marker ;
}

// This is Method A - it ALWAYS sets the zoom properly

function setDropoff(dropoffLoc) {  //called from: index.js/setPickup(), tab-map.html
    geoCoder.geocode({'address': dropoffLoc}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      if (results[0]) {
        endLocation = dropoffLoc ;
        endLat = results[0].geometry.location.lat() ;
        endLon = results[0].geometry.location.lng() ;
        // first clear any existing END Markers only.
        while(markersArray.length) { 
          markersArray.pop().setMap(null); 
        }
        endPointSet = 1 ;
        endLatlon = new google.maps.LatLng(endLat,endLon) ;
        var endMarker = createMarker(endLatlon,'img/red-pin.png','Drop off') ;
        markersArray.push(endMarker) ;
        setMapBounds(userMarker,endMarker) ;

        if (startPointSet == 1) {
          drawRoute("DRIVING",startLocation,endLocation) ;
        } 
      }
    } else {
        error = "Address not found."
    }
  });
}

// This is method B, it ALWAYS pushees the zoom out to 4. It is pulled out of another function that tests to see if the user manually set and end point...if so, then add wayPoints between user set start/end points. If not, then set map to user start point to a single end point of interest

if (endPointSet == 1) {  // draw Pickup to START to wayPoints to END
    var markers = [
      {lat:interests[0].shub_lat,lon:interests[0].shub_lon,img:interests[0].img,title:"Pickup"},
      {lat:interests[1].ehub_lat,lon:interests[1].ehub_lon,img:interests[1].img,title:"Dropoff"}
    ] ;
    var points = [interests.shub_address,interests.ehub_address] ;
    extraMarkers = addMarkers(markers) ;
    drawRoute("BICYCLING",startLocation,endLocation,points) ;
  } else {  
    var markers = [
      {lat:interests[0].shub_lat,lon:interests[0].shub_lon,img:interests[0].img,title:"Dropoff"}
      ] ;

    extraMarkers = addMarkers(markers) ;
    setMapBounds(userMarker,extraMarkers[0]) ;
    drawRoute("WALKING",startLocation,interests[0].shub_address) ;
  }
}

Here is are the objects passed into setMapBounds from the else within Method B. Start point is set by User...but no end point is set, I am picking one for them. The first Object is start, the second object is end.

Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 563, gm_bindings_: Object…} 
Lf: Object 
... 
  position: pf 
    D: -82.49799999999999 
    k: 27.873196 
... 

Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 602, gm_bindings_: Object…} 
Lf: Object 
... 
  position: pf 
    D: -82.47631678090198 
    k: 27.9374560148825 
...

And here are the objects passed into setMapBounds from Method A where the user is setting both the same start and end points. you can see the start point is the same for both Method A and B.

Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 563, gm_bindings_: Object…} 
  Lf: Object 
  ... 
  position: pf 
    D: -82.49799999999999 
    k: 27.873196 
... 

Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 703, gm_bindings_: Object…} 
  Lf: Object 
  ... 
  position: pf 
    D: -82.45717760000002 
    k: 27.950575 
  ...
1

There are 1 answers

0
bcdan On

I am making a similar application, and the code that I am using is:

var start;
var end;

function updateMap(name, obj){ //obj is a form input i.e. <input type="text">
  var marker = (name==='start')?start:end;
  geocoder.geocode({address:obj.value}, function(results, status){

    //get coords/check if is valid place
    if(status === google.maps.GeocoderStatus.OK){

      //get info, store in new marker
      marker.setPosition(results[0].geometry.location);
      marker.setTitle(obj.value);

      //if both markers present
      if(start.getPosition() && end.getPosition()){
        map.fitBounds(new google.maps.LatLngBounds(start.getPosition(), end.getPosition()));
      }else{

        //otherwise, if one marker
        map.setCenter(marker.getPosition());
        map.setZoom(15);
      }
      marker.setMap(map);
    }else if(status === google.maps.GeocoderStatus.ZERO_RESULTS){
      alert('There is an issue with address. Please refer to the "Help" link.');
    }else{
      setTimeout(function(){
        updateMap(marker, obj);
      }, 200);
    }
  });
}

What this does is take an argument from a text input, geocode it, and place a marker on the map. The function is triggered by an onchange event on the form element. This can be easily adapted for your own usage. If there was only one point, I just settled for a default zoom value (usually pretty close to the street, though you can adjust this however you want).

As for your question of why it is not working, I can formulate a better guess with the entire code. For now, I would think it has something to do with region-biasing, or that it is simply a bug. It is probably just best to work around it.