user13286
user13286

Reputation: 3075

Google Maps API - Closest marker function change to closest n markers

I am using the formula found in this question to find the closest marker on the map to the current position. I would like to modify this formula so that it finds the closet n number of locations(closest 5 locations, closest 10 locations, etc.) and I am not sure how to accomplish this.

Here is the modified formula I am using:

function rad(x) {return x*Math.PI/180;}
function find_closest_marker(center, map) {
    var lat = center.lat();
    var lng = center.lng();
    var R = 6371; // radius of earth in km
    var distances = [];
    var closest = -1;
    for( i=0;i<markers.length; i++ ) {
        var mlat = markers[i].position.lat();
        var mlng = markers[i].position.lng();
        var dLat  = rad(mlat - lat);
        var dLong = rad(mlng - lng);
        var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(rad(lat)) * Math.cos(rad(lat)) * Math.sin(dLong/2) * Math.sin(dLong/2);
        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        var d = R * c;
        distances[i] = d;
        if ( closest == -1 || d < distances[closest] ) {
            closest = i;
        }
    }

    //Log title of closest marker
    console.log(markers[closest].title);
}

Here is how I am loading the markers:

// Add markers to the map
function setMarkers(center, map) {
    var json = (function () { 
        var json = null; 
        $.ajax({ 
            'async': false, 
            'global': false, 
            'url': "js/data.json", 
            'dataType': "json", 
            'success': function (data) {
                 json = data; 
             }
        });
        return json;
    })();
    // Loop over each of the json elements
    for (var i = 0, length = json.length; i < length; i++) {
        var data = json[i],
        latLng = new google.maps.LatLng(data.lat, data.lon);
        // Create a marker and place it on the map
        var icon = 'assets/marker.png';
        var marker = new google.maps.Marker({
            position: latLng,
            map: map,
            icon: icon,
            title: data.loc
        });
        markers.push(marker);
        infoBox(map, marker, data);
    }
}

How can I modify the formula further so that it finds the closest n number of markers rather than just the single closest one?

Upvotes: 1

Views: 7730

Answers (1)

geocodezip
geocodezip

Reputation: 161404

You could use the (slightly modified) findClosestN function from this question (changed gmarkers to markers, changed the function to return the closest array limited to numberOfResults elements)

function findClosestN(pt, numberOfResults) {
    var closest = [];
    for (var i = 0; i < markers.length; i++) {
        markers[i].distance = google.maps.geometry.spherical.computeDistanceBetween(pt, markers[i].getPosition());
        markers[i].setMap(null);
        closest.push(markers[i]);
    }
    closest.sort(sortByDist);
    return closest.splice(0,numberOfResults);
}

function sortByDist(a, b) {
    return (a.distance - b.distance)
}

proof of concept fiddle

code snippet:

var geocoder = null;
var map = null;
var customerMarker = null;
var markers = [];
var closest = [];

function initialize() {
  // alert("init");
  geocoder = new google.maps.Geocoder();
  map = new google.maps.Map(document.getElementById('map'), {
    zoom: 9,
    center: new google.maps.LatLng(52.6699927, -0.7274620),
    mapTypeId: google.maps.MapTypeId.ROADMAP
  });
  var infowindow = new google.maps.InfoWindow();
  var marker, i;
  var bounds = new google.maps.LatLngBounds();
  document.getElementById('info').innerHTML = "found " + locations.length + " locations<br>";
  for (i = 0; i < locations.length; i++) {
    var coordStr = locations[i][4];
    var coords = coordStr.split(",");
    var pt = new google.maps.LatLng(parseFloat(coords[0]), parseFloat(coords[1]));
    bounds.extend(pt);
    marker = new google.maps.Marker({
      position: pt,
      map: map,
      icon: locations[i][5],
      address: locations[i][2],
      title: locations[i][0],
      html: locations[i][0] + "<br>" + locations[i][2]
    });
    markers.push(marker);
    google.maps.event.addListener(marker, 'click', (function(marker, i) {
        return function() {
          infowindow.setContent(marker.html);
          infowindow.open(map, marker);
        }
      })
      (marker, i));
  }
  map.fitBounds(bounds);

}

function codeAddress() {
  var address = document.getElementById('address').value;
  geocoder.geocode({
    'address': address
  }, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      map.setCenter(results[0].geometry.location);
      if (customerMarker) customerMarker.setMap(null);
      customerMarker = new google.maps.Marker({
        map: map,
        position: results[0].geometry.location
      });
      for (var i = 0; i < markers.length; i++) {
        markers[i].setMap(null);
      }
      var numResults = parseInt(document.getElementById('numberResults').value);
      closest = findClosestN(results[0].geometry.location, numResults);
      for (var i = 0; i < closest.length; i++) {
        closest[i].setMap(map);
      }
    } else {
      alert('Geocode was not successful for the following reason: ' + status);
    }
  });
}

function findClosestN(pt, numberOfResults) {
  var closest = [];
  for (var i = 0; i < markers.length; i++) {
    markers[i].distance = google.maps.geometry.spherical.computeDistanceBetween(pt, markers[i].getPosition());
    markers[i].setMap(null);
    closest.push(markers[i]);
  }
  closest.sort(sortByDist);
  return closest.splice(0, numberOfResults);
}

function sortByDist(a, b) {
  return (a.distance - b.distance)
}

google.maps.event.addDomListener(window, 'load', initialize);

var locations = [
  ["John's Pizza", "no", "400 University Ave, Palo Alto, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.121277,37.386799,0 -122.158012,37.4168,0 -122.158012,37.448151,0 -122.142906,37.456055,0 -122.118874,37.45224,0 -122.107544,37.437793,0 -122.102737,37.422526,0 -122.113037,37.414618,0 -122.121277,37.386799,0   </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.447038,-122.160575", "http://maps.google.com/mapfiles/ms/icons/blue.png"],
  ["JJs Express", "yes", "1000 Santa Cruz Ave, Menlo Park, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.200928,37.438611,0 -122.158012,37.4168,0 -122.158012,37.448151,0 -122.142906,37.456055,0 -122.144623,37.475948,0 -122.164192,37.481125,0 -122.189255,37.478673,0 -122.208481,37.468319,0 -122.201271,37.438338,0 </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.448638,-122.187176", "http://maps.google.com/mapfiles/ms/icons/green.png"],
  ["John Paul's Pizzeria", "no", "1100 El Camino Real, Belmont, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.304268,37.516534,0 -122.300835,37.505096,0 -122.262383,37.481669,0 -122.242813,37.502917,0 -122.244186,37.534232,0 -122.269249,37.550021,0 -122.291222,37.545122,0 -122.302895,37.537499,0 -122.304268,37.516534,0 </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.520436,-122.275978", "http://maps.google.com/mapfiles/ms/icons/red.png"],
  ["JJs Express", "yes", "300 E 4th Ave, San Mateo, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.304268,37.516534,0 -122.348557,37.538044,0 -122.359886,37.56363,0 -122.364006,37.582405,0 -122.33654,37.589207,0 -122.281609,37.570433,0 -122.291222,37.545122,0 -122.302895,37.537499,0 -122.304268,37.516534,0 </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.564435,-122.322080", "http://maps.google.com/mapfiles/ms/icons/green.png"],
  ["John's Pizza", "yes", "1400 Broadway Ave, Burlingame, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.374306,37.548933,0 -122.348557,37.538044,0 -122.359886,37.56363,0 -122.364006,37.582405,0 -122.33654,37.589207,0 -122.359543,37.59764,0 -122.372246,37.604712,0 -122.417564,37.594648,0 -122.374306,37.548933,0 </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.584935,-122.366182", "http://maps.google.com/mapfiles/ms/icons/blue.png"],
  ["JJs Express", "yes", "700 San Bruno Ave, San Bruno, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.462883,37.628916,0 -122.445374,37.639247,0 -122.426147,37.648762,0 -122.405205,37.642238,0 -122.400055,37.628644,0 -122.392159,37.610696,0 -122.372246,37.604712,0 -122.417564,37.594648,0 -122.462196,37.628644,0  </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.630934,-122.406883", "http://maps.google.com/mapfiles/ms/icons/green.png"],
  ["JJs Express", "yes", "300 Beach St, San Francisco, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.43576,37.790795,0 -122.449493,37.801646,0 -122.425461,37.809784,0 -122.402115,37.811411,0 -122.390442,37.794593,0 -122.408295,37.79188,0 -122.434387,37.789167,0 </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.807628,-122.413782", "http://maps.google.com/mapfiles/ms/icons/green.png"],
  ["JJs Express", "yes", "1400 Haight St, San Francisco, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.463398,37.760266,0 -122.477349,37.774785,0 -122.427349,37.774785,0 -122.429237,37.763658,0 -122.46357,37.760808,0</coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.770129,-122.445082", "http://maps.google.com/mapfiles/ms/icons/green.png"],
  ["JJs Express", "yes", "2400 Mission St, San Francisco, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.418766,37.747779,0 -122.425289,37.768951,0 -122.406063,37.769901,0 -122.406063,37.749679,0 -122.418251,37.747508,0 </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.758630,-122.419082", "http://maps.google.com/mapfiles/ms/icons/green.png"],
  ["JJs Express", "yes", "500 Castro St, Mountain View, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.121277,37.386799,0 -122.108917,37.362244,0 -122.077675,37.3385,0 -122.064285,37.378615,0 -122.069778,37.3898,0 -122.076645,37.402619,0 -122.078705,37.411619,0 -122.113037,37.414618,0 -122.121277,37.386799,0  </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.390040,-122.081573", "http://maps.google.com/mapfiles/ms/icons/green.png"],
  ["John's Pizza", "no", "100 S Murphy Ave, Sunnyvale, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.047119,37.33113,0 -122.065315,37.332495,0 -122.077675,37.3385,0 -122.064285,37.378615,0 -122.036819,37.385162,0 -122.006607,37.382162,0 -122.00386,37.342048,0 -122.047119,37.331403,0  </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.377441,-122.030071", "http://maps.google.com/mapfiles/ms/icons/blue.png"],
  ["John's Pizza", "no", "1200 Curtner Ave, San Jose, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-121.935196,37.345051,0 -121.931076,37.294267,0 -121.871338,37.293721,0 -121.806793,37.293174,0 -121.798553,37.361426,0 -121.879578,37.36088,0 -121.934509,37.345597,0 -121.935196,37.345051,0 </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.288742,-121.890765", "http://maps.google.com/mapfiles/ms/icons/blue.png"],
  ["John's Pizza", "yes", "700 Blossom Hill Rd, San Jose, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-121.935883,37.253287,0 -121.931076,37.294267,0 -121.871338,37.293721,0 -121.806793,37.293174,0 -121.790657,37.234702,0 -121.852455,37.223221,0 -121.935539,37.253014,0 </coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.250543,-121.846563", "http://maps.google.com/mapfiles/ms/icons/blue.png"],
  ["John's Pizza", "yes", "100 N Milpitas Blvd, Milpitas, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-121.947556,37.435612,0 -121.934509,37.476493,0 -121.893311,37.469409,0 -121.852798,37.429615,0 -121.843872,37.400165,0 -121.887817,37.3898,0 -121.959915,37.420345,0 -121.959915,37.427979,0 -121.948929,37.435612,0 -121.947556,37.435612,0</coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.434113,-121.901139", "http://maps.google.com/mapfiles/ms/icons/blue.png"],
  ["John's Pizza", "yes", "3300 Mowry Blvd, Fremont, CA", "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.02343,37.52198,0 -122.023773,37.558731,0 -121.989784,37.573426,0 -121.959572,37.566351,0 -121.944466,37.544305,0 -121.967125,37.520891,0 -122.023087,37.522525,0</coordinates></LinearRing></outerBoundaryIs></Polygon>", "37.552773,-121.985153", "http://maps.google.com/mapfiles/ms/icons/blue.png"]
];
html,
body,
table,
tbody,
#map {
  height: 100%;
  width: 100%;
  padding: 0;
  margin: 0;
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry,places&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<table border="1" style="height: 90%; width:100%;">
  <tr style="height: 100%; width:100%;">
    <td style="height: 100%; width:100%;">
      <div id="map"></div>
    </td>
    <td>
      <div id="side_bar"></div>
    </td>
  </tr>
</table>
<input id="address" type="text" value="Palo Alto, CA" />
<input id="numberResults" type="text" value="5" />
<input type="button" value="Search" onclick="codeAddress();" />
<div id="info"></div>

Upvotes: 6

Related Questions