10

I have this script that will show custom markers on a google map, but I would like to include a input text-box and be able to enter a city/state and a zip-code and see if there are any markers within lets say 400 miles from that city/state or zip-code. I would love it if the map can be dynamic so as you type out the city/state or zip-code it will show the results on the map by getting rid of all the other markers and leaving only the one that is within that radius, if that is too hard then a simple alter box saying what unit is the closest will also be OK :) I searched and found some say that I should load the geometry library and use computeDistanceBetween() to find the distance of each marker from your center point but I have no idea how to do the zip-code part or how to put all of this together to work.

Here is my code:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title></title>
<script type="text/javascript"  src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclustererplus/src/markerclusterer.js"></script>

<script type="text/javascript"> 
   var image = new google.maps.MarkerImage("marker-images/image.png",new google.maps.Size(40,35),new google.maps.Point(0,0),new google.maps.Point(20,35));

   var shadow = new google.maps.MarkerImage(
                            'marker-images/shadow.png',
                            new google.maps.Size(62,35),
                            new google.maps.Point(0,0),
                            new google.maps.Point(20,35)
                          );

   var shape = {
                coord: [27,0,30,1,32,2,34,3,35,4,36,5,38,6,39,7,39,8,39,9,39,10,38,11,37,12,33,13,34,14,34,15,33,16,32,17,31,18,27,19,28,20,28,21,27,22,26,23,22,25,23,26,24,27,24,28,24,29,24,30,24,31,24,32,23,33,22,34,17,34,16,33,15,32,15,31,14,30,14,29,15,28,15,27,16,26,17,25,13,23,12,22,11,21,11,20,12,19,8,18,7,17,6,16,5,15,5,14,6,13,2,12,1,11,0,10,0,9,0,8,0,7,1,6,3,5,4,4,5,3,7,2,9,1,12,0,27,0],
                type: 'poly'
          };

     // this variable will collect the html which will eventually be placed in the side_bar 
     var side_bar_html = ""; 

     // arrays to hold copies of the markers and html used by the side_bar 
     // because the function closure trick doesnt work there 
     var gmarkers = []; 

     // global "map" variable
     var map = null;
     var circle = null;

     //marker clusterer
     var mc;
     var mcOptions = {gridSize: 10, maxZoom: 8};

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

     //geocoder
     var geocoder = new google.maps.Geocoder(); 
     var address = new Array("41.8119,-87.6873",
                        "40.7888,-74.056",
                        "41.8119,-87.6873",
                        "48.6681,-97.3627",
                        "44.9793,-93.273",
                        "39.4857,-75.6775",
                        "41.8119,-87.6873",
                        "42.0203,-87.9059",
                        "32.7812,-96.7903",
                        "27.5159,-99.4941",
                        "32.7812,-96.7903",
                        "37.5608,-95.6684",
                        "41.8119,-87.6873",
                        "38.3763,-97.6702",
                        "42.2458,-83.2491",
                        "41.8122,-91.9139",
                        "41.8397,-88.0887",
                        "41.8397,-88.0887",
                        "38.5128,-122.787",
                        "41.8397,-88.0887",
                        "42.8863,-87.892",
                        "42.8863,-87.892",
                        "30.7539,-83.3321",
                        "39.889,-84.2422",
                        "34.106,-83.589");
     var content = new Array("Unit No# 0206",
                        "Unit No# #2003",
                        "Unit No# 0176",
                        "Unit No# #2001",
                        "Unit No# 0124",
                        "Unit No# 0157",
                        "Unit No# #0162",
                        "Unit No# 0104",
                        "Unit No# 0118",
                        "Unit No# #2007",
                        "Unit No# 0112",
                        "Unit No# 0139",
                        "Unit No# 0205",
                        "Unit No# 0127",
                        "Unit No# 0187",
                        "Unit No# 0105",
                        "Unit No# 0214",
                        "Unit No# 0186",
                        "Unit No# 0173",
                        "Unit No# 0134",
                        "Unit No# 0128",
                        "Unit No# 0125",
                        "Unit No# 0158",
                        "Unit No# 0193",
                        "Unit No# 0201");

     //min and max limits for multiplier, for random numbers
     //keep the range pretty small, so markers are kept close by
     var min = .999999;
            var max = 1.000001;

    function createMarker(latlng,text) {
      var marker = new google.maps.Marker({
         draggable: false,
         raiseOnDrag: false,
         icon: image,
         shadow: shadow,
         shape: shape,
         position: latlng,
         map: map
       });

     ///get array of markers currently in cluster
     var allMarkers = mc.getMarkers();

     //check to see if any of the existing markers match the latlng of the new marker
      if (allMarkers.length != 0) {
        for (i=0; i < allMarkers.length; i++) {
          var existingMarker = allMarkers[i];
          var pos = existingMarker.getPosition();

          if (latlng.equals(pos)) {
            text = text + " & " + content[i];
          }                   
        }
      }

      google.maps.event.addListener(marker, 'click', function() {
        infowindow.close();
        infowindow.setContent(text);
        infowindow.open(map,marker);
      });
      mc.addMarker(marker);
      return marker;
    }
    function initialize(){
        var options = { 
            zoom: 4, 
            center: new google.maps.LatLng(39.8282,-98.5795), 
            mapTypeId: google.maps.MapTypeId.ROADMAP 
        };
        map = new google.maps.Map(document.getElementById('map'), options); 

    //marker cluster
        var gmarkers = [];
        mc = new MarkerClusterer(map, [], mcOptions);
        for (i=0; i<address.length; i++) {
           var ptStr = address[i];
           var coords = ptStr.split(",");
           var latlng = new google.maps.LatLng(parseFloat(coords[0]),parseFloat(coords[1]));
           gmarkers.push(createMarker(latlng,content[i]));
        }
    }

          function codeAddress() {
            var address = document.getElementById('address').value;
            var radius = parseInt(document.getElementById('radius').value, 10) * 1609.34;
            geocoder.geocode( { 'address': address}, function(results, status) {
              if (status == google.maps.GeocoderStatus.OK) {
                map.setCenter(results[0].geometry.location);
                var marker = new google.maps.Marker({
            //        map: map,  <-- uncomment to show red marker
                    position: results[0].geometry.location
                });
                if (circle) circle.setMap(null);
                circle = new google.maps.Circle({center:marker.getPosition(),
                                                 radius: radius,
                                                 fillOpacity: 0.35,
                                                 fillColor: "#FF0000",
                                                 map: map});
                var bounds = new google.maps.LatLngBounds();
            var foundMarkers = 0;
                for (var i=0; i<gmarkers.length;i++) {
                  if (google.maps.geometry.spherical.computeDistanceBetween(gmarkers[i].getPosition(),marker.getPosition()) < radius) {
                    bounds.extend(gmarkers[i].getPosition())
                    gmarkers[i].setMap(map);
            foundMarkers++;
                  } else {
                    gmarkers[i].setMap(null);
                  }
                }
                if (foundMarkers > 0) {
                  map.fitBounds(bounds);
            } else {
                  map.fitBounds(circle.getBounds());
                }
              } else {
                alert(status);
              }
            });
          }

    var infowindow = new google.maps.InfoWindow(
      { 
        size: new google.maps.Size(150,50)
      });


    function handleKeyPress(e){
     var key=e.keyCode || e.which;
      if (key==13){
         codeAddress();
      }
    }

    function handleResetKeyPress(e){
        if (map.getZoom() != 4) map.setZoom(4);
          map.setCenter(new google.maps.LatLng(39.8282, -98.5795));
        document.getElementById("address").value = 'Enter City,State or Zipcode';
        document.getElementById("radius").value = '200';
    }
    </script> 

    <style>
    html, body, #map {
    height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
    }
    .auto-style1 {
        text-align: center;
    }
      #footer {
        position : absolute;
        bottom : 0;
        height : 40px;
        margin-top : 40px;
     /* border: 1px solid blue; */
      }
    </style>
    </head>
    <body onload='initialize()'>
    <div id="map"></div>
    <div id="footer" class="auto-style1" style="left: 0px; bottom: 0; width: 100%">
          <input type="text" id="address" value="Enter City,State or Zipcode" onclick="if(this.value=='Enter City,State or Zipcode'){this.value=''}" onblur="if(this.value==''){this.value='Enter City,State or Zipcode'}" onkeypress="handleKeyPress(event);" style="width: 183px">
          <input type="button" value="Search" onclick="codeAddress();">
          <input type="button" value="Reset" onclick="handleResetKeyPress();">
          <input type="text" id="radius" value="200" style="width: 42px" onclick="if(this.value=='200'){this.value=''}" onblur="if(this.value==''){this.value='200'}" onkeypress="handleKeyPress(event);"> miles
    </div>
    </body>
</html>
RavatSinh Sisodiya
  • 1,596
  • 1
  • 20
  • 42
compcobalt
  • 1,322
  • 7
  • 31
  • 61
  • [example radius search](http://www.geocodezip.com/v3_MW_example_map3_radiusSearch.html) – geocodezip Aug 29 '13 at 13:31
  • 1
    I do exactly the same as you on one of my maps couldn't work out a sensible way of doing exactly this and returning a text list (though I need to at some point so will revisit it in future) for now I do as @geocodezip does in his example and just dump a circle overlay with radius X over the top of the map and allow the user to click on the markets to work out the actual items in region themselves. – Dave Aug 29 '13 at 13:51
  • @geocodezip Thanks for that link works great for me, I would love it if I had a text list like Dave said but I guess I will have to live with this for now. Can you just tell me know do I convert from Km to Miles ? I know it's has to do with var radius = parseInt(document.getElementById('radius').value); but what value do I * it with ? – compcobalt Aug 29 '13 at 14:39
  • @geocodezip this is what I did var radius = parseInt(document.getElementById('radius').value, 10)*640; but I would like to know if this is okay and accurate ? or do you have another way of doing this ? btw: it can be off a mile or 2 I don't need it super accurate, Thanks again. – compcobalt Aug 29 '13 at 14:51
  • 2
    @compcobalt the `Circle`'s `radius` property is actually always in meters. So if your getting your user input in miles, you'll need to convert it to meters and then set the `radius`. It would be `var radius = parseInt(document.getElementById('radius').value, 10) * 1609.34;`. – Suvi Vignarajah Aug 29 '13 at 15:34
  • @SuviVignarajah That is Great Thanks... also would you know how I can create a zoom and center reset input button that will reset the maps zoom and recenter it onclick ? – compcobalt Aug 29 '13 at 15:58
  • Sure, you'd store the initial zoom and center values of your map. Then set an event listener on an element that listens for a `click` and in the callback function reset the zoom and center of map using `map.setZoom(initialZoomValue)` and `map.setCenter(initialCenterLatLng)`. – Suvi Vignarajah Aug 29 '13 at 16:14
  • @SuviVignarajah Thanks!! :) I did as you told me and the zoom works but the setCenter makes the clustering of the markers disappear. I updated my question to show how I have it set now, if you get a chance to look at it and see what I'm doing wrong, Thanks again – compcobalt Aug 29 '13 at 16:36
  • 1
    No worries. `setCenter` doesn't work because you cannot pass in numeric values into that method, it must be the `google.maps.LatLng` object - `map.setCenter(new google.maps.LatLng(39.8282, -98.5795));`. – Suvi Vignarajah Aug 29 '13 at 16:51
  • 1
    But the problem is not with you `setCenter`, it's with the `setZoom`. Seems like the `markerclusterer` doesn't redraw when you set the zoom to the same zoom level. A quick fix would be to check to see if you are already at the initial zoom level, if so don't bother setting it, else set it back to initial zoom. `if (map.getZoom() != 4) map.setZoom(4);` – Suvi Vignarajah Aug 29 '13 at 16:54
  • You are right! :)THANKS A MILLION!!:) – compcobalt Aug 29 '13 at 17:02

2 Answers2

10

Here is a working example.

The example uses all_locations - array of example locations.

You can replace that with your locations (e.g. locations you fetch from your DB). You can insert any address to the input bar, e.g. '123 New Street, New York, 56789, NY' and using google.maps.Geocoder the code will geocode that map into LatLng location around which it will draw a radius. Only locations that fall within the radius around the address will show on map. To see the example locations, input "Second Steet, New York" as address.

var map = null;
  var radius_circle;
  var markers_on_map = [];
  var geocoder;
  var infowindow;
  
  //all_locations is just a sample, you will probably load those from database
  var all_locations = [
   {type: "Restaurant", name: "Restaurant 1", lat: 40.723080, lng: -73.984340},
   {type: "School", name: "School 1", lat: 40.724705, lng: -73.986611},
   {type: "School", name: "School 2", lat: 40.724165, lng: -73.983883},
   {type: "Restaurant", name: "Restaurant 2", lat: 40.721819, lng: -73.991358},
   {type: "School", name: "School 3", lat: 40.732056, lng: -73.998683}
  ];

  //initialize map on document ready
  $(document).ready(function(){
      var latlng = new google.maps.LatLng(40.723080, -73.984340); //you can use any location as center on map startup
      var myOptions = {
        zoom: 1,
        center: latlng,
        mapTypeControl: true,
        mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU},
        navigationControl: true,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      };
      map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
   geocoder = new google.maps.Geocoder();
      google.maps.event.addListener(map, 'click', function(){
           if(infowindow){
             infowindow.setMap(null);
             infowindow = null;
           }
      });
  });
  
  function showCloseLocations() {
   var i;
   var radius_km = $('#radius_km').val();
   var address = $('#address').val();

   //remove all radii and markers from map before displaying new ones
   if (radius_circle) {
    radius_circle.setMap(null);
    radius_circle = null;
   }
   for (i = 0; i < markers_on_map.length; i++) {
    if (markers_on_map[i]) {
     markers_on_map[i].setMap(null);
     markers_on_map[i] = null;
    }
   }

   if (geocoder) {
    geocoder.geocode({'address': address}, function (results, status) {
     if (status == google.maps.GeocoderStatus.OK) {
      if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
       var address_lat_lng = results[0].geometry.location;
       radius_circle = new google.maps.Circle({
        center: address_lat_lng,
        radius: radius_km * 1000,
        clickable: false,
      map: map
       });
                    if (radius_circle) map.fitBounds(radius_circle.getBounds());
       for (var j = 0; j < all_locations.length; j++) {
        (function (location) {
         var marker_lat_lng = new google.maps.LatLng(location.lat, location.lng);
         var distance_from_location = google.maps.geometry.spherical.computeDistanceBetween(address_lat_lng, marker_lat_lng); //distance in meters between your location and the marker
         if (distance_from_location <= radius_km * 1000) {
          var new_marker = new google.maps.Marker({
           position: marker_lat_lng,
           map: map,
           title: location.name
          });              google.maps.event.addListener(new_marker, 'click', function () {
                                    if(infowindow){
             infowindow.setMap(null);
             infowindow = null;
           }
           infowindow = new google.maps.InfoWindow(
            { content: '<div style="color:red">'+location.name +'</div>' + " is " + distance_from_location + " meters from my location",
              size: new google.maps.Size(150,50),
              pixelOffset: new google.maps.Size(0, -30)
            , position: marker_lat_lng, map: map});
          });
          markers_on_map.push(new_marker);
         }
        })(all_locations[j]);
       }
      } else {
       alert("No results found while geocoding!");
      }
     } else {
      alert("Geocode was not successful: " + status);
     }
    });
   }
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
        google.load("maps", "3",{other_params:"sensor=false&libraries=geometry"});
      </script>

<body style="margin:0px; padding:0px;" >
 <input id="address" value="Second Steet, New York" placeholder="Input Address"/>
 <select id="radius_km">
  <option value=1>1km</option>
  <option value=2>2km</option>
  <option value=5>5km</option>
  <option value=30>30km</option>
 </select>
 <button onClick="showCloseLocations()">Show Locations In Radius</button>
 <div id="map_canvas"  style="width:500px; height:300px;">
</body>
</html>
Community
  • 1
  • 1
Matej P.
  • 5,303
  • 1
  • 28
  • 44
  • Thanks ,answer is useful to me.Vote Up.Code written by you is up to my requirement. I want suggestion how to change the circle border color, width and opacity color in circular area. – Deep 3015 Feb 13 '17 at 07:31
  • The `google.maps.Circle` object has properties like `strokeWeight, fillColor, fillOpacity`... You can set them when creating the circle, eg.: `radius_circle = new google.maps.Circle({ center: address_lat_lng, radius: radius_km * 1000, clickable: false, map: map, fillOpacity: 0.5, fillColor: 'ffffff' });` More in the docs: https://developers.google.com/maps/documentation/javascript/3.exp/reference (look up "google.maps.Circle class") – Matej P. Feb 13 '17 at 12:23
  • @MatejP.I am totally new to this map and UI. I have say set of lat&log of people and a center point. I want to show all people location as a RED Marker on Google MAP. Please excuse for naive questions. – Kumar Aug 10 '18 at 15:49
4

Here is an example of how you could solve this with the geocoding API and some simple geometry.

(Note that I have hardcoded the address and radius for brevity.)

// we assume that you have an array of markers
var markers = [];

//In order to lookup the the position of a zip-code you can use the geocoding API:
// https://developers.google.com/maps/documentation/geocoding/
var geocode_api_base_url = "http://maps.googleapis.com/maps/api/geocode/json?";
var params = {
    adress : 05673,
    components : "country:us",
    sensor : false
}
// This is the result set of markers in area
var in_area = [];

//  http://maps.googleapis.com/maps/api/geocode/json?address=05673&components=country:US&sensor=false
$.getJSON( geocode_api_base_url + $.param(params), function(data) {

    var location, search_area, in_area = [];

    location = data['results'][0]['address_components']['geometry']['location'];

    // We create a circle to look within:
    search_area = {
        strokeColor: '#FF0000',
        strokeOpacity: 0.8,
        strokeWeight: 2,
        center : new google.maps.LatLng(location.lat, location.lon),
        radius : 500
    }

    search_area = new google.maps.Circle(search_area);

    $.each(markers, function(i,marker) {
       if (google.maps.geometry.poly.containsLocation(marker.getPosition(), search_area)) {
         in_area.push(marker);
       }
    });

    console.info(in_area);

});
max
  • 96,212
  • 14
  • 104
  • 165