Rahul Desai
Rahul Desai

Reputation: 15501

Get nearest location from a set of predefined locations with Google Maps Javascript API

I have a set of 2 predefined locations and based on user's input of zipcode, I need to show the nearest one.

So far, I have searched the user input location using the zipcode:

$("form#zipcodeSearch").on("submit", function(event){
    event.preventDefault();
    var jsonUrl = 'http://maps.googleapis.com/maps/api/geocode/json?address='+$("input#zipcode").val();
    
    $.ajax({
        type: "POST",
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'text/plain'
        },
        dataType: "json",
        url: jsonUrl,
        success: function (data) {
           
            var lat = (data.results[0].geometry.bounds.northeast.lat + data.results[0].geometry.bounds.southwest.lat) / 2;
            var lng = (data.results[0].geometry.bounds.northeast.lng + data.results[0].geometry.bounds.southwest.lng) / 2;

            initialize(lat, lng);            
            
        }
    });

});

var map;
function initialize(lat, lng) {
    var mapOptions = {
        zoom: 15
    };
    map = new google.maps.Map(document.getElementById('map-canvas'),
                              mapOptions);
    
    // Try HTML5 geolocation
    if(navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position) {
            var pos = new google.maps.LatLng(lat, lng);
            
            var infowindow = new google.maps.InfoWindow({
                map: map,
                position: pos,
                content: '<div style="width: 75px">You are here!</div>'
            });
            
            map.setCenter(pos);
            
        }, function() {
            handleNoGeolocation(true);
        }, {
            enableHighAccuracy: true
        });
    } else {
        // Browser doesn't support Geolocation
        handleNoGeolocation(false);
    }    
}

function handleNoGeolocation(errorFlag) {
    if (errorFlag) {
        var content = 'Error: The Geolocation service failed.';
    } else {
        var content = 'Error: Your browser doesn\'t support geolocation.';
    }
    
    var options = {
        map: map,
        position: new google.maps.LatLng(60, 105),
        content: content
    };
    
    var infowindow = new google.maps.InfoWindow(options);
    map.setCenter(options.position);
}
*{
    margin: 0;
    padding: 0;
}

body{
    font-family: arial;
    font-size: 62.5%;        /* so, 10px = 1rem */
}

#map-canvas{
    z-index: -1;
    position: absolute;
    top: 0;
    height: 100%;
    width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>

<form id="zipcodeSearch">
    <input type="text" id="zipcode" placeholder="Enter Zipcode"/>
    <input type="submit" value="Search" />
</form>

<div id="map-canvas"></div>

jsFiddle

Any ideas on how to achieve this? If it is not possible with the JS API, is there any other API that can help me achieve this?

EDIT: Cleaned-up jsFiddle version

Upvotes: 3

Views: 5235

Answers (1)

Rahul Desai
Rahul Desai

Reputation: 15501

Update:
Keyless access to Google Maps Platform is now deprecated. You will need to have an API key with all your API calls to avoid service interruption . For further details please refer to http://g.co/dev/maps-no-account


Original Answer:
I was able to solve this in following way:

  1. Get lat, long co-ordinates of the input zipcode from this URL: http://maps.googleapis.com/maps/api/geocode/json?address=zipcode (add zipcode)
  2. Take average of the lats and longs of northeast and southwest returned in the response of this URL. Consider the calculated average lat and long as the input co-ordinates.
  3. Compute the distance to get the closest location using google.maps.geometry.spherical.computeDistanceBetween()
  4. Initialize the Google Map with all of the markers.
  5. Use google.maps.LatLngBounds() to adjust the zoom so that the map includes the input zipcode's location and the nearest searched location.

Here's a demo. The H icon stands for the input zipcode location and C icon stands for the closest location among the searched ones. (For now, I have kept only 2 predefined locations).

var predefinedLocations = [{
    "name": "Brookwood Medical Center",
    "lat": 33.4636415,
    "lng": -86.7771671
  },
  {
    "name": "Lutheran Medical Center",
    "lat": 40.646872,
    "lng": -74.020892
  }
];

$("form#zipcodeSearch").on("submit", function(event) {
  event.preventDefault();
  var jsonUrl = 'http://maps.googleapis.com/maps/api/geocode/json?address=' + $("input#zipcode").val();

  $.ajax({
    type: "POST",
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'text/plain'
    },
    dataType: "json",
    url: jsonUrl,
    success: function(data) {

      var lat = (data.results[0].geometry.bounds.northeast.lat + data.results[0].geometry.bounds.southwest.lat) / 2;
      var lng = (data.results[0].geometry.bounds.northeast.lng + data.results[0].geometry.bounds.southwest.lng) / 2;
      var p1, p2;

      predefinedLocations.forEach(function(obj) {
        p1 = new google.maps.LatLng(obj.lat, obj.lng);
        p2 = new google.maps.LatLng(lat, lng);

        obj.distance = calcDistance(p1, p2);
      });

      // sort by distance
      var locationInfo = predefinedLocations.sort(compare);

      //console.log('locationInfo', locationInfo);

      initializeGoogleMap(locationInfo, lat, lng);

    }
  });

});

var map;

function initializeGoogleMap(locationInfo, lat, lng) {
  var mapOptions = {
    zoom: 15
  };
  map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

  // zoom to only the input zipcode and closest location    
  var latlngbounds = new google.maps.LatLngBounds();
  latlngbounds.extend(new google.maps.LatLng(locationInfo[0].lat, locationInfo[0].lng));
  latlngbounds.extend(new google.maps.LatLng(lat, lng));
  map.fitBounds(latlngbounds);

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

  var marker, i;

  // set marker for input location
  setMarker(lat, lng, map, 'http://www.lsac.org/images/default-source/mainportalimages/icon-h-grey-bg.jpg?sfvrsn=2', "You are here!", i, infowindow);

  // set marker for closest location
  setMarker(locationInfo[0].lat, locationInfo[0].lng, map, 'http://alert.mta.info/sites/all/themes/mta/images/subway_bullets/c.png', locationInfo[0].name, i, infowindow);

  for (var j = 1; j < locationInfo.length; j++) {
    // set marker for other location
    setMarker(locationInfo[j].lat, locationInfo[j].lng, map, '', locationInfo[j].name, i, infowindow);
  }

}

function calcDistance(p1, p2) {
  return (google.maps.geometry.spherical.computeDistanceBetween(p1, p2) / 1000).toFixed(2);
}

function compare(a, b) {
  if (parseFloat(a.distance) < parseFloat(b.distance)) {
    return -1;
  }

  if (parseFloat(a.distance) > parseFloat(b.distance)) {
    return 1;
  }

  return 0;
}

function setMarker(lat, lng, map, icon, content, i, infowindow) {

  var marker = new google.maps.Marker({
    position: new google.maps.LatLng(lat, lng),
    map: map,
    icon: icon
  });

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

}
* {
  margin: 0;
  padding: 0;
}

html {
  font-size: 62.5%;
  /* so, 10px = 1rem */
}

body {
  font-family: arial;
}

#map-canvas {
  z-index: -1;
  position: absolute;
  top: 0;
  height: 100%;
  width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://maps.google.com/maps/api/js?sensor=false&libraries=geometry"></script>

<form id="zipcodeSearch">
  <input type="text" id="zipcode" placeholder="Enter zipcode here" />
  <input type="submit" value="Search" />
</form>

<div id="map-canvas"></div>

jsFiddle version of the same code

I hope this answer helps someone facing the same problem as I did.

Upvotes: 5

Related Questions