0

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]];

730wavy
  • 944
  • 1
  • 19
  • 57
  • Have you tried to move `map.fitBounds(bounds);` out of the `for` loop? – xomena Dec 01 '17 at 15:13
  • @xomena just tried, it didnt do anything. – 730wavy Dec 01 '17 at 21:32
  • I get a javascript error with the posted code: `Uncaught ReferenceError: theinfo is not defined`. If I fix that it centers correctly (at zoom level 8). [fiddle](http://jsfiddle.net/geocodezip/qz6f4xs4/) – geocodezip Dec 03 '17 at 02:59
  • My guess is it is a data problem, do the coordinates you provided reproduce the problem for you? – geocodezip Dec 03 '17 at 03:01
  • @geocodezip "theinfo" is already defined in my code. – 730wavy Dec 03 '17 at 04:36
  • Not in the code you posted... please provide a [mcve] that demonstrates your issue. – geocodezip Dec 03 '17 at 04:54
  • Yes it is, `//info content echo "var theinfo = ["; $comma2 = ""; ........ ` The code I posted is the exact code I have, and the coordinates are the exact coordinates it produces. The code uses wordpress loop to get the values for the geocoding function. – 730wavy Dec 03 '17 at 15:43

3 Answers3

3

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.

janos
  • 120,954
  • 29
  • 226
  • 236
0

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.

730wavy
  • 944
  • 1
  • 19
  • 57
  • If anyone knows of a solution that still allows the map to be hidden on page load, please let me know. – 730wavy Dec 14 '17 at 14:05
0

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

Suhail Mushtaq
  • 81
  • 1
  • 2
  • 11
  • @RichJ I mentioned it may help someone in case they need to add some logic like this. In your case, i think you can use this line of code to focus of any of your marker. here i have hard coded the lat long 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 }); – Suhail Mushtaq Dec 06 '17 at 04:51