730wavy
730wavy

Reputation: 704

Google map autocenter with multiple markers

I created a map to display my search results as markers on the map, and it almost works perfect, however the auto center/zoom is not working as needed. The map addresses or dynamic so I can not hardcode specific coordinates.

I used some of my code from a previous question and other code to use bounds to try and get the coordinates from 2 markers and find the center, however no matter what I do it just doesn't work properly.

Here's the code I'm using ---

<!--- SEARCH MAP --->
<div id="map_wrapper">
    <div id="map_canvas" class="mapping"></div>
</div>

<?php function getCoordinates($address){
$address = str_replace(" ", "+", $address); // replace all the white space with "+" sign to match with google search pattern
$url = "https://maps.googleapis.com/maps/api/geocode/json?address=$address&key=TOKEN_KEY";
$response = file_get_contents($url);
$json = json_decode($response,TRUE); //generate array object from the response from the web
return ($json['results'][0]['geometry']['location']['lat'].",".$json['results'][0]['geometry']['location']['lng']);
} ?>

<script type="text/javascript">

<?php
$locations = array();
//$location_query = new WP_Query( array(
//'posts_per_page' => 100
// ) );

echo "//markers: 100\n";
echo "var locations = [";
$comma = "";
//while ( $location_query->have_posts() ) {
//$location_query->the_post();

while (have_posts()) {
the_post();

$add = get_post_meta(get_the_ID(), 'address', true);
$property_pin = get_post_meta(get_the_ID(), 'pincode', true);
$terms = wp_get_post_terms(get_the_ID(), 'city');

if ( ! empty( $terms ) && ! is_wp_error( $terms ) ){
     foreach ( $terms as $term ) {
if ($term->parent == 0) {
     $addy = getCoordinates($add, $term->name);  
     }
  }

}

$title = str_replace("'", "\'", get_the_title());
echo $comma . "['" . $title . "', " . $addy . ", " . get_the_id() . "]";  
$comma = ", ";
}
echo "];\n\n";

//info content
echo "var theinfo = [";
$comma2 = "";

while (have_posts()) {
the_post();

$add = get_post_meta(get_the_ID(), 'address', true);
$property_price = get_post_meta(get_the_ID(),'price',true);
$terms = wp_get_post_terms(get_the_ID(), 'city');

if ( ! empty( $terms ) && ! is_wp_error( $terms ) ){
     foreach ( $terms as $term ) {
if ($term->parent == 0) { //check for parent terms only
     $tcity = $term->name;    
     }
  }

}

$title = str_replace("'", "\'", get_the_title());
$link = get_the_id();
$linkto = '<a href="/property/'.$link.'/">'.$title.'</a>';
$class = 'class="mapmarkers"';
echo $comma2 . "['<div ".$class."><h3>" . $linkto . "</h3><h4>" . $tcity . "</h4><p>$" . $property_price ."</p></div>']";  
$comma2 = ", ";
} 
echo "];\n\n";

?>

 var map;
   var bounds = new google.maps.LatLngBounds();
    var mapOptions = {
center: new google.maps.LatLng(0, 0),
zoom: 0,
minZoom: 5, 
maxZoom: 15,
        mapTypeId: 'roadmap'
    };

    // Display a map on the page
    map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
    map.setTilt(45);

// Info Window Content
    var infoWindowContent = theinfo;

 // Display multiple markers on a map
    var infoWindow = new google.maps.InfoWindow(), marker, i;

    // Loop through our array of markers & place each one on the map 
    for( i = 0; i < locations.length; i++ ) {
        var position = new google.maps.LatLng(locations[i][1], locations[i][2]);
        marker = new google.maps.Marker({
            position: position,
            map: map,
            title: locations[i][0]
        });
//bounds.extend(position);
bounds.extend(marker.getPosition());

        // Allow each marker to have an info window    
        google.maps.event.addListener(marker, 'click', (function(marker, i) {
            return function() {
                infoWindow.setContent(infoWindowContent[i][0]);
                infoWindow.open(map, marker);
            }
        })(marker, i));

// Automatically center the map fitting all markers on the screen
 map.fitBounds(bounds);
 map.panToBounds(bounds); 
}

  // Override our map zoom level once our fitBounds function runs (Make sure it only runs once)
    var boundsListener = google.maps.event.addListener((map), 'bounds_changed', function(event) {
       this.setZoom(8);
    google.maps.event.removeListener(boundsListener);
   });
</script>

With my code the map is rendering like so --- WRONG

But I need it to be more so like this --- CORRECT

The examples are using only 2 markers but the real amount and locations will be dynamic. How can I fix this?

UPDATE

My coordinates var locations = [['1460 Broadway', 40.7551055,-73.9862093, 2299], ['246 W 18th St', 40.741807,-74.0000351, 2114]];

Upvotes: 0

Views: 4562

Answers (3)

Suhail Mushtaq
Suhail Mushtaq

Reputation: 81

May be this can help some one. If you have requirement to add a ripple around you marker, you can do something like this. you can add ripple to all or some of the markers depends on your requirement.

    <!DOCTYPE html>
    <html> 
    <head> 
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> 
   <title>Google Maps Multiple Markers</title> 
  <script src="http://maps.google.com/maps/api/js?sensor=false" 
          type="text/javascript"></script>
</head> 
<body>
  <div id="map" style="width: 1000px; height: 500px;"></div>

   <script type="text/javascript">
     var locations = [
     ['Saudi Arabia',23.885942, 45.079162   , 6],
      ['United Arab Emirates', 23.424076, 53.847818, 4],
      ['Bahrain',25.930414  ,50.637772  , 5],
      ['Iraq',  33.223191,  43.679291   , 3],
      ['Kuwait',29.31166,   47.481766   , 2],     
      ['Qatar',25.354826,   51.183884   , 1]
    ];

    var map = new google.maps.Map(document.getElementById('map'), {
      zoom: 10,
      center: new google.maps.LatLng(23.885942, 45.079162),
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });

    var infowindow = new google.maps.InfoWindow();

    var marker, i;

    var icon = {
                url: "Ripple.svg", // url of ripple svg image
                scaledSize: new google.maps.Size(200, 200), // scaled size
                origin: new google.maps.Point(0,0), // origin
                anchor: new google.maps.Point(100,100) // anchor
            };        

  for (i = 0; i < locations.length; i++) {   
      marker = new google.maps.Marker({

        position: new google.maps.LatLng(locations[i][1], locations[i][2]),
        map: map, 
         icon: icon,
            optimized: false
      });

       google.maps.event.addListener(marker, 'click', (function(marker, i) {
        return function() {
          infowindow.setContent(locations[i][0]);
          infowindow.open(map, marker);
        }
      })(marker, i));
      }
for (i = 0; i < locations.length; i++) { 
      marker = new google.maps.Marker({
        position: new google.maps.LatLng(locations[i][1], locations[i][2]), 
        map: map
      });

      google.maps.event.addListener(marker, 'click', (function(marker, i) {
        return function() {
          infowindow.setContent(locations[i][0]);
          infowindow.open(map, marker);
        }
      })(marker, i));
    }


  </script>
</body>
</html>

showing ripple around marker[![][2]]3

Upvotes: 0

730wavy
730wavy

Reputation: 704

I figured out the issue, the outermost map container (not shown in question) is set to display none on page load so that I can use a click a function to toggle between a map view and regular list view of posts.

So I had --

    <div id="map_view" style="display:none;">
    <div id="map_wrapper">
    <div id="map_canvas" class="mapping"></div>
    </div>
<script> blah blah </script>
</div>

If I take off display none, it seems to load correctly on page load. Ideally I did not want the map to display first but this seems to be the only solution thus far.

Upvotes: 0

janos
janos

Reputation: 124744

TL;DR

With the given sample locations, and the code that you shared, I'm not able to reproduce the problem: the map view correctly adjusts so that the locations are visible.

What now?

  • Verify the locations data in your program.

    • Are the lat-lon values in the expected range? -> Lat at around 40.7 and lon at around -74
    • Are the lat-lon values in the correct order in the locations arrays? -> Lat is at index 1 (as in locations[i][1]) and lon is at index 2 (as in locations[i][2])
  • Verify that your actual code really matches the posted code -> if some crucial information is missing in the posted code, we might be debugging the wrong thing...

  • Update your question to be a Minimal, Complete, and Verifiable example

  • See below for more details on the debugging process, as well as some other improvement ideas to the JavaScript part of the program.


Based on your posted code and sample locations, I created this minimal example. The only important difference from your code is this part, registering a callback to initialize the map:

<script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
        async defer></script>

It's not visible in your posted code how you initialized the map. In any case, if you initialized incorrectly, the symptom should be not the map in your screenshot, but no map at all, so I guess this is not your problem. But I suggest to verify your initialization.

Please try this example yourself and confirm in your question if you can reproduce the problem with it. If you cannot (as I suspect), then in order to help you, it will be best if you make Minimal, Complete, and Verifiable example based on this.

<!DOCTYPE html>
<html>
  <head>
    <title>Simple Map</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <style>
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map_canvas {
        height: 100%;
      }
      /* Optional: Makes the sample page fill the window. */
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="map_canvas"></div>
    <script>
function initMap() {
  var locations = [
    ['1460 Broadway', 40.7551055,-73.9862093, 2299],
    ['246 W 18th St', 40.741807,-74.0000351, 2114]
  ];
  var map;
  var bounds = new google.maps.LatLngBounds();
  var mapOptions = {
    center: new google.maps.LatLng(0, 0),
    zoom: 0,
    minZoom: 5, 
    maxZoom: 15,
    mapTypeId: 'roadmap'
  };

  // Display a map on the page
  map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
  map.setTilt(45);

  // Info Window Content
  var infoWindowContent = locations;  // suitable dummy value

  // Display multiple markers on a map
  var infoWindow = new google.maps.InfoWindow(), marker, i, position;

  // Loop through our array of markers & place each one on the map 
  for (i = 0; i < locations.length; i++) {
    position = new google.maps.LatLng(locations[i][1], locations[i][2]);
    marker = new google.maps.Marker({
      position: position,
      map: map,
      title: locations[i][0]
    });
    bounds.extend(position);

    // Allow each marker to have an info window    
    google.maps.event.addListener(marker, 'click', (function(marker, i) {
      return function() {
        infoWindow.setContent(infoWindowContent[i][0]);
        infoWindow.open(map, marker);
      }
    })(marker, i));

    // Automatically center the map fitting all markers on the screen
    map.fitBounds(bounds);
    map.panToBounds(bounds); 
  }

  // Override our map zoom level once our fitBounds function runs (Make sure it only runs once)
  var boundsListener = google.maps.event.addListener((map), 'bounds_changed', function(event) {
    this.setZoom(8);
    google.maps.event.removeListener(boundsListener);
  });
}
    </script>
    <script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
            async defer></script>
  </body>
</html>

And this is what the output looks like:

output from original code

It's not great, but the points are at the center of the visible, and very different from what we see in your post. I really think you missed some important details.


At this point, some simple improvements are possible:

  • The zoom level 8 is not well suited for these points, let's drop it
    • And since this is the only job of the boundsListener, let's drop that as well
    • Note that boundsListener seems pointless from the start, since you already called map.fitBounds and map.panToBounds
  • Instead of calling map.fitBounds and map.panToBounds for every point, we can move it out of the loop, and call it after all the points have been added to bounds

Based on the above suggestions, the JavaScript part of the code becomes:

function initMap() {
  var locations = [
    ['1460 Broadway', 40.7551055,-73.9862093, 2299],
    ['246 W 18th St', 40.741807,-74.0000351, 2114]
  ];
  var map;
  var bounds = new google.maps.LatLngBounds();
  var mapOptions = {
    center: new google.maps.LatLng(0, 0),
    zoom: 0,
    minZoom: 5, 
    maxZoom: 15,
    mapTypeId: 'roadmap'
  };

  // Display a map on the page
  map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
  map.setTilt(45);

  // Info Window Content
  var infoWindowContent = locations;  // suitable dummy value

  // Display multiple markers on a map
  var infoWindow = new google.maps.InfoWindow(), marker, i, position;

  // Loop through our array of markers & place each one on the map 
  for (i = 0; i < locations.length; i++) {
    position = new google.maps.LatLng(locations[i][1], locations[i][2]);
    marker = new google.maps.Marker({
      position: position,
      map: map,
      title: locations[i][0]
    });
    bounds.extend(position);

    // Allow each marker to have an info window    
    google.maps.event.addListener(marker, 'click', (function(marker, i) {
      return function() {
        infoWindow.setContent(infoWindowContent[i][0]);
        infoWindow.open(map, marker);
      }
    })(marker, i));
  }

  // Automatically center the map fitting all markers on the screen
  map.fitBounds(bounds);
  map.panToBounds(bounds); 
}

And the output becomes:

after minor refactoring


This is as far as I can get with the information you've provided so far. And I don't see a problem.

I hope the above will help your debugging, or that based on this you will post a Minimal, Complete, and Verifiable example that will help others to find your issue.

Upvotes: 4

Related Questions