I'm in the process of adding a map to a website using Google Maps API v3 and javascript.
I have a list of addresses and have successfully plotted them on the map. When the user types in a zip code, the map re-centers on their location showing the markers closest to that point. Now, I need to create a list view of the closest 3 or 5 locations to their zip code with links for driving direction. I'm stuck...and open for suggestions.
The usual solution is to use the google.maps.geometry.spherical library computeDistanceBetween(from:LatLng, to:LatLng, radius?:number) method to reduce the number to about 10, then use the distance matrix return the driving distance to those locations so the results can be sorted by driving distance (actual travel distance), and reduced to the closest 3 to 5 locations by actual travel distance within the request limits.
example (finds the 3 closest places from a list)
(data borrowed from the FusionTables "pizza store" example)
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
});
closest = findClosestN(results[0].geometry.location,10);
// get driving distance
closest = closest.splice(0,3);
calculateDistances(results[0].geometry.location, closest,3);
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
function findClosestN(pt,numberOfResults) {
var closest = [];
document.getElementById('info').innerHTML += "processing "+gmarkers.length+"<br>";
for (var i=0; i<gmarkers.length;i++) {
gmarkers[i].distance = google.maps.geometry.spherical.computeDistanceBetween(pt,gmarkers[i].getPosition());
document.getElementById('info').innerHTML += "process "+i+":"+gmarkers[i].getPosition().toUrlValue(6)+":"+gmarkers[i].distance.toFixed(2)+"<br>";
gmarkers[i].setMap(null);
closest.push(gmarkers[i]);
}
closest.sort(sortByDist);
return closest;
}
function sortByDist(a,b) {
return (a.distance- b.distance)
}
function calculateDistances(pt,closest,numberOfResults) {
var service = new google.maps.DistanceMatrixService();
var request = {
origins: [pt],
destinations: [],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
};
for (var i=0; i<closest.length; i++) request.destinations.push(closest[i].getPosition());
service.getDistanceMatrix(request, function (response, status) {
if (status != google.maps.DistanceMatrixStatus.OK) {
alert('Error was: ' + status);
} else {
var origins = response.originAddresses;
var destinations = response.destinationAddresses;
var outputDiv = document.getElementById('side_bar');
outputDiv.innerHTML = '';
var results = response.rows[0].elements;
for (var i = 0; i < numberOfResults; i++) {
closest[i].setMap(map);
outputDiv.innerHTML += "<a href='javascript:google.maps.event.trigger(closest["+i+"],\"click\");'>"+closest[i].title + '</a><br>' + closest[i].address+"<br>"
+ results[i].distance.text + ' appoximately '
+ results[i].duration.text + '<br><hr>';
}
}
});
}
example above with "Get Directions" link in the infoWindow
When you have the lat lng pair of a zipcode you can use the harversine formula to find the distance from your location.
Related
May I know how to get more than 10 data results from Google Map when using the radarSearch method that can retrieved 200 results and getDetails method? I want all the marker information is listed down in the white space below the map. However, I only get 10 of it. May I know the problem? The 10 result stay the same and may only change 1 of them when the browser is refresh for a few times.
Here is the code that I used to retrieve the information from Google Map and create the marker. I used the radar Search method to perform the search.
function callback(results, status) {
if (status !== google.maps.places.PlacesServiceStatus.OK) {
console.error(status);
return;
}
for (var i = 0, result; result = results[i]; i++) {
addMarker(result);
}
}
function addMarker(place) {
var placesList = document.getElementById('test');
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
icon: {
url: 'http://maps.gstatic.com/mapfiles/circle.png',
anchor: new google.maps.Point(10, 10),
scaledSize: new google.maps.Size(10, 17)
}
});
service.getDetails(place, function(result, status) {
if (status !== google.maps.places.PlacesServiceStatus.OK) {
console.error(status);
return;
}
iname = result.name;
iLatitude = [result.geometry.location.lat()];
iLongitude = [result.geometry.location.lng()];
iAddress = [result.formatted_address];
placesList.innerHTML += '<li>' + iname +' '+ iAddress + '</li>';
});
}
ScreenShot of the result.
The marker result is nearly 200, while the listed down data only consists of 10
Actually the problem is due to the OVER_QUERY_LIMIT issue, it can be bypass when the time sent request is delayed, setTimeout method can be implemented to avoid OVER_QUERY_LIMIT problem.
Replace with the code below. Can retrieve all the marker data on the map,(currently I have 148 restaurants marker on the Google Map)
service.getDetails(place, function(result, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
iname = result.name;
iLatitude = [result.geometry.location.lat()];
iLongitude = [result.geometry.location.lng()];
iAddress = [result.formatted_address];
placesList.innerHTML += '<li>' + iname + ''+ iAddress + '</li>';
}
else if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
setTimeout(function() {
addMarker(place);
}, 200);
}
});
I have built a web app that uses the google maps v3 API to build a map with directions multiple waypoints.
jQuery.getJSON(driverURL, function(dData){
var routeObject = {};
var lat = dData.Location.lat;
var lng = dData.Location.lng;
routeObject.origin = new google.maps.LatLng(lat, lng);
routeObject.destination = new google.maps.LatLng(endRoute.lat, endRoute.lng);
routeObject.waypoints = waypoints;
routeObject.travelMode = google.maps.TravelMode.DRIVING;
routeObject.optimizeWaypoints = true;
directionsService.route(routeObject, function(response, status) {
if (status === google.maps.DirectionsStatus.OK) {
var directionsDisplay = new google.maps.DirectionsRenderer({
polylineOptions: {
strokeColor: colors[driverLines.length]
}
});
directionsDisplay.setMap(dMap);
directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
});
I have the Map, the waypoints, the start and the end all stored, but I'd like to be able to generate a google maps clickable link to the directions for this route that I can send to users. I can find how to send a link with a single marker, but not how to generate a map link with the full route direction.
Any help appreciated.
I figured this out, and it's actually easier than I thought, but took some doing.
First I took some of the waypoints I had, as addresses, not lat/lng points, and built a route map on maps.google.com. Then I looked at how the URL for that map was constructed. Very simple to re-create.
The URL is just http://maps.google.com/dir/starting address as address,city,state,zip/waypoint as address,city,state,zip/waypoint/ending address as address,city,state,zip And you're done. If you're using lat/lng coordinates for your start,waypoint,end locations you'll have to first geo-code them using the V3 api then extract the address information from the returned result and insert those in your URL, but it works.
Here's how I made the final link that has a start, a bunch of waypoints, and an ending location. I start with a JSON object, called Data, that has all the address info in it and build a long string from it, in the format Google Maps expects:
var dirs = ''
for(var x = 0; x<Data.length;x++){
dirs += Data[x].Address + "," + Data[x].City + "," + Data[x].State + "," + Data[x].Zip + "/";
}
Then, I add the start and end locations to it:
var dirLink = 'http://maps.google.com/maps/dir/';
dirLink += start.Address + "," + start.City + "," + start.State + "," + start.Zip + "/" + dirs + end.Address + "," + end.City + "," + end.State + "," + end.Zip;
And dirLink will be a complete link that will give directions from start.Address through all the waypoints to end.Address.
Don`t forget for
In script :
function initMap() {
var pointA = new google.maps.LatLng(51.7519, -1.2578),
pointB = new google.maps.LatLng(51.509865, -0.118092),
pointC = new google.maps.LatLng(50.8429, -0.1313),
myOptions = {
zoom: 7,
center: pointA
},
map = new google.maps.Map(document.getElementById('map-canvas'), myOptions),
// Instantiate a directions service.
directionsService = new google.maps.DirectionsService,
directionsDisplay = new google.maps.DirectionsRenderer({
map: map
}),
markerA = new google.maps.Marker({
position: pointA,
title: "point A",
label: "A",
map: map
}),
markerB = new google.maps.Marker({
position: pointB,
title: "point B",
label: "B",
map: map
}),
markerC = new google.maps.Marker({
position: pointC,
title: "point C",
label: "C",
map: map
});
// get route from A to B
calculateAndDisplayRoute(directionsService, directionsDisplay, pointA, pointB, pointC);
}
function calculateAndDisplayRoute(directionsService, directionsDisplay, pointA, pointB, pointC) {
var first = new google.maps.LatLng(51.509865, -0.118092); //we can get them from params.
var request = {
origin: pointA,
destination: pointC,
waypoints: [{location: first, stopover: false}
], //here array of waypoints
optimizeWaypoints: true,
travelMode: google.maps.DirectionsTravelMode.WALKING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById("directions_panel");
summaryPanel.innerHTML = "";
// For each route, display summary information.
for (var i = 0; i < route.legs.length; i++) {
var routeSegment = i + 1;
summaryPanel.innerHTML += "<b>Route Segment: " + routeSegment + "</b><br />";
summaryPanel.innerHTML += route.legs[i].start_address + " to ";
summaryPanel.innerHTML += route.legs[i].end_address + "<br />";
summaryPanel.innerHTML += route.legs[i].distance.text + "<br /><br />";
}
} else {
alert("directions response " + status);
}
});
}
initMap();
I'm currently making an app for a university assignment. I'm using the google maps places api and gmaps.js.
What I want to do is let user search places and show the results in a simple list (which I've got working) but I want to calculate the distance to each of the search results as well, which is sort of working (I think!) but I'm not sure how to make it display how I want, e.g:
"Search Result - 1.1 mi away"
"Search Result - 0.8 mi away"
What it is doing right now is calculating the distances but all the values are being set next to all of the search results, instead of next to each other. In one line (all bunched together).
(Had to remove a link to post a new one)
I don't know how to split them or do it more cleanly from the start. I think the problem lies in the function which is calculating the distances using "google.maps.DistanceMatrixService".
var origin = currentLocation;
var destination = place.geometry.location;
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [origin],
destinations: [destination],
travelMode: google.maps.TravelMode.WALKING,
unitSystem: google.maps.UnitSystem.IMPERIAL,
avoidHighways: false,
avoidTolls: false
}, getDistance);
function getDistance(response, status) {
if (status == "OK") {
var distance = response.rows[0].elements[0].distance.text;
console.log(distance);
$(".distance").append(distance);
} else {
return false;
console.log(response + status)
}
}
getDistance();
This line is my best guess:
response.rows[0].elements[0].distance.text;
But I'm quite lost with it.
Full code of my search request:
$("#place-search").submit(function(e){
e.stopPropagation(); e.preventDefault();
var query = $("#place-query").val();
map.addLayer("places", {
location: cheltenham, //new google.maps.LatLng(51.902707,-2.073361),
radius: 500, //experiment with the distance (in metres)
query: query,
opennow: true,
textSearch: function (results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
$(".results-list").html(""); //remove previous results
removeMarkers(); //remove previous markers
var bounds = new google.maps.LatLngBounds();
//console.log(bounds);
//I think if we set i to say 10, it will limit the search results - by default the places api returns 20 result sets
for (var i = 0; i < results.length; i++) {
//console.log(i);
var place = results[i];
var image = { //set to better sizes and positions (icons from search results)
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(25, 25)
};
/* ---------- */
var origin = currentLocation; //new google.maps.LatLng(51.902707,-2.073361);
var destination = place.geometry.location; //new google.maps.LatLng(51.899464, -2.074641);
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [origin],
destinations: [destination],
travelMode: google.maps.TravelMode.WALKING, //this needs to be a choice
unitSystem: google.maps.UnitSystem.IMPERIAL,
avoidHighways: false,
avoidTolls: false
}, getDistance);
function getDistance(response, status) {
if (status == "OK") {
var distance = response.rows[0].elements[0].distance.text; //the one I need
console.log(distance);
$(".distance").append(distance);
} else {
return false;
console.log(response + status)
}
}
getDistance();
/* ---------- */
map.addMarker({
lat: place.geometry.location.lat(),
lng: place.geometry.location.lng(),
icon: image,
animation: google.maps.Animation.DROP,
title: place.name,
//we need to style and build these better - ideas? should be simple I think, Name + Location + Image
infoWindow: {
content: '<h2>'+place.name+'</h2>' + '<p>Rating: '+place.rating+'</p>' + '<p>'+(place.vicinity ? place.vicinity : place.formatted_address)+'</p><img src="'+place.icon+'"" width="100"/>'
}
});
bounds.extend(place.geometry.location);
$(".results-list").append("<li>" + place.name + "<span class=\"distance\"></span></li>");
}
map.fitBounds(bounds); //fit to the new bounds
}//end if search OK
}
});
});
Any help or pointers would be greatly appreciated!
Update:
I've tried moving the line that puts the items into the list with jQuery into the function getDistance(), and that ends up putting the distances with the place name but it's the same place name for every distance that is calculated. It is the last result from the search.
getDistance()
function getDistance(response, status) {
if (status == google.maps.DistanceMatrixStatus.OK) {
var origins = response.originAddresses;
var destinations = response.destinationAddresses;
for (var i = 0; i < origins.length; i++) {
var results = response.rows[i].elements;
for (var j = 0; j < results.length; j++) {
var element = results[j];
var distance = element.distance.text;
var duration = element.duration.text;
var from = origins[i];
var to = destinations[j];
$(".results-list").append("<li><span class=\"name\">" + place.name + "</span>" + distance + "</li>")
}
}
} else {
return false;
console.log(response + status)
}
}
What the output looks like: http://i.imgur.com/FSCMMzF.png
Thanks to everyone who's taken a look so far!
This question already has answers here:
Convert Latitude/Longitude To Address [duplicate]
(3 answers)
Closed 9 years ago.
How to convert latitude and longitude value into address in javascript? I had tried geolocation, but its display only the 10 address. It will not display more then ten address.
my code:
if (result.Status.code == G_GEO_SUCCESS) {
for ( var i = 0; i < result.Placemark.length; i++) {
var addres = result.Placemark[i].address;
// var t1=setTimeout(function(){x.value="2 seconds"},2000);
if (addres == "") {
// alert('blank');
document.getElementById("msg" + noofid).innerHTML = "Unable to find location";
} else {
document.getElementById("msg" + noofid).innerHTML = result.Placemark[i].address;
}
//alert("address");
}
}
// ====== Decode the error status ======
else {
var reason = "Code " + result.Status.code;
if (reasons[result.Status.code]) {
reason = reasons[result.Status.code];
}
alert('Could not find "' + search + '" '
+ reason);
}
});
}
Hello since you have a specific issue regarding this api, and I came across your question I'll share with you some source from an old project of mine that had similar needs.
// get nearest coords based on given tracking
tb.prototype.getNearestStreetCoords = function(lat, lng, callback) {
var parentClass = this;
var nearestStreet = {
latitude: lat,
longitude: lng
};
if (parentClass.useNearest != true) callback(nearest);
var request = {
origin: new google.maps.LatLng(lat, lng),
destination: new google.maps.LatLng(lat, lng),
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService = new google.maps.DirectionsService();
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
callback(response);
} else {
callback(false);
}
});
}
// get nearest address based on lat & lng
tb.prototype.getAddress = function(lat, lng, callback) {
geocoder = new google.maps.Geocoder();
geocoder.geocode({'latLng': new google.maps.LatLng(lat, lng)}, function(results, status) {
var streetAddress = null;
if (status == google.maps.GeocoderStatus.OK) {
streetAddress = results[0].formatted_address;
}
callback(streetAddress);
});
}
I have a JavaScript postcode search that searches for the 3 closet stores in the UK depending on what is entered into the input. At the moment it finds the 3 stores fine.
Firstly, I want to drop a marker at the postcode entered in the input.
Secondly, when the three results show up, they are marked on the map. I want to have a link called directions that, once clicked, will show directions from the start to the chosen store.
I have tried the following code but it doesn't work...however it does get the postcode data from the input and from the directions link and shows them in the console. Will I need to convert them into long and lat for it to work?
function calcRoute() {
var start = document.getElementById('address').value;
var end = document.getElementById('get-directions').name;
//console.log(start, end)
var request = {
origin:start,
destination:end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
I have this code for my start marker, but this doesn't seem to work either
function initialize() {
var start_marker = new google.maps.LatLng(document.getElementById('address').value);
directionsDisplay = new google.maps.DirectionsRenderer();
var mapOptions = {
zoom:7,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: start_marker
}
marker = new google.maps.Marker({
map:map,
draggable:false,
animation: google.maps.Animation.DROP,
position: start_marker,
});
map = new google.maps.Map(document.getElementById('map'), mapOptions);
directionsDisplay.setMap(map);
}
This part gets the long/lat data from the postcode,
this.geocode = function(address, callbackFunction) {
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var result = {};
result.latitude = results[0].geometry.location.lat();
result.longitude = results[0].geometry.location.lng();
callbackFunction(result);
//console.log(result);
//console.log("Geocoding " + geometry.location + " OK");
addMarker(map, results[0].geometry.location);
} else {
alert("Geocode was not successful for the following reason: " + status);
callbackFunction(null);
}
});
And the function for the addMarker is here:
function addMarker(map, location) {
console.log("Setting marker for (location: " + location + ")");
marker = new google.maps.Marker({
map : map,
animation: google.maps.Animation.DROP,
position : location
});
}
Any help would be greatly appreciated!
The constructor for a google.maps.LatLng requires two floating point numbers as arguments, not a string:
var start_marker = new google.maps.LatLng(document.getElementById('address').value);
If all you have is an address, you need to use the Geocoding service to retrieve coordinates for that address if you want to display a marker on the map.