Google Maps API v3 is not rerendering directions correctly - javascript

I created a small test project in here: http://jsfiddle.net/jochenhebbrecht/k3a3fvq0/3/
I clean routes using the following method:
// Clean previous routes
if (directionsDisplays.length > 0) {
for(var i = 0; i < directionsDisplays.length; i++) {
directionsDisplays[i].setMap(null);
}
directionsDisplays.length = 0;
}
I draw routes using the follow method:
// Draw all routes
if (routes.length > 0) {
for (var i = 0; i < routes.length; i++) {
(function(i){
var route = routes[i];
var request = {
origin: route.origin,
destination: route.destination,
travelMode: google.maps.TravelMode.WALKING,
waypoints: route.waypoints
};
var directionsDisplay = new google.maps.DirectionsRenderer({
suppressMarkers: true,
preserveViewport: true,
polylineOptions: {
strokeColor: '#C6D300'
}
});
directionsDisplay.setMap(map);
directionsDisplays.push(directionsDisplay);
directionsService.route(request, function (result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
}
});
})(i);
}
}
I have a checkbox which show some routes on a map. If you check the box, routes are shown. If you uncheck the box, routes are removed.
However, if I check the box again (for a second time), not all routes are rendered correctly. You have to check/uncheck a couple of times to let it work ...
Any idea what I'm doing wrong?

Check the status returned by your directions requests. If they fail due to OVER_QUERY_LIMIT, delay a short while and retry the failed requests.
Also, don't request the routes every time they are displayed, if they are already available redisplay the route.
Note that the approach above will only work for the same order of magnitude of routes you currently have, if you have a lot more routes it will be prohibitively slow.
proof of concept fiddle
function highlightRoutes() {
if (directionsDisplays.length > 0 && (directionsDisplays[0].getMap() == null)) {
// redisplay the routes
for (var i = 0; i < directionsDisplays.length; i++) {
directionsDisplays[i].setMap(map);
}
} else if (directionsDisplays.length > 0 && (directionsDisplays[0].getMap() != null)) {
// hide the routes
for (var i = 0; i < directionsDisplays.length; i++) {
directionsDisplays[i].setMap(null);
}
} else {
var routes = new Array();
if (jQuery('#chkBxBikeRoutes').attr('checked')) {
routes.push.apply(routes, getBikeRoutes());
}
// Clean previous routes
if (directionsDisplays.length > 0) {
for (var i = 0; i < directionsDisplays.length; i++) {
directionsDisplays[i].setMap(null);
}
directionsDisplays.length = 0;
}
// Draw all routes
if (routes.length > 0) {
for (var i = 0; i < routes.length; i++) {
(function(i) {
var route = routes[i];
var request = {
origin: route.origin,
destination: route.destination,
travelMode: google.maps.TravelMode.WALKING,
waypoints: route.waypoints
};
var directionsDisplay = new google.maps.DirectionsRenderer({
suppressMarkers: true,
preserveViewport: true,
polylineOptions: {
strokeColor: '#C6D300'
}
});
directionsDisplay.setMap(map);
directionsDisplays.push(directionsDisplay);
directionsService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
} else if (status == google.maps.DirectionsStatus.OVER_QUERY_LIMIT) {
//document.getElementById("status").innerHTML += request.origin+":"+request.destination+"status:"+status+"<br>";
setTimeout(function() {
directionsService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
} else {
document.getElementById("status").innerHTML += request.origin + ":" + request.destination + "status:" + status + "<br>";
}
})
}, 2000);
} else {
document.getElementById("status").innerHTML += request.origin + ":" + request.destination + "status:" + status + "<br>";
}
});
})(i);
}
}
}
}

Unfortunately you cannot do that.
Update your code as shown below and you will see what happens:
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
} else {
alert(status);
}
You will get several OVER_QUERY_LIMIT status messages.
More information can be found here:
https://developers.google.com/maps/documentation/business/articles/usage_limits
https://developers.google.com/maps/documentation/javascript/directions#DirectionsStatus

Related

Undefined Issue using Google's Javascript API

I've been stuck on an issue for a number of days when using the google geo-location api. This is what I've been trying -
function codeAddress(address) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({"address": address}, function(results, status) {
if (status == "OK") {
return results[0].geometry.location;
} else {
return null;
}
});
}
function generateJSON(origin, destination) {
var origin_loc = codeAddress(origin);
var dest_loc = codeAddress(destination);
....
}
The "origin_loc" variable is coming back unassigned and I haven't been able to figure out why with the debugger. When I log the results[0] to the console it is coming back fine with the object.
Does anyone have any ideas why this is happening?
Thanks
This is what worked for me in the end -
function codeAddresses(addresses, callback) {
var coords = [];
for(var i = 0; i < addresses.length; i++) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address':addresses[i]}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
coords.push(results[0].geometry.location);
if(coords.length == addresses.length) {
callback(coords);
}
}
else {
throw('No results found: ' + status);
}
});
}
}
function generateJSON(origin, destination) {
var addresses = [origin, destination];
codeAddresses(addresses, function(coords) {
var json = { ..... }
....
});
}
Thanks for your help #yuriy636!

Map does not load centered when doing first search

Can anyone tell me why the map does not load centered the first time it loads? It works fine when I do a second search, but never loads up correctly the first time.
src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"
var directionsDisplay;
var directionsService;
var geocoder;
var currentAddress = 'placeholder';
var tabCount = 0;
var altRouteCount = 0;
var savedRoutes;
$(document).ready(function(){
$('#message-container').hide (0);
document.getElementById('sidebar').className = 'sidebar-hidden';
// Keeps form pointAB from refreshing the page.
$('#pointAB').on('submit', function (e) {
e.preventDefault();
});
$('#tabs').tab();
$('#tabs a').click( function (e) {
e.preventDefault();
$(this).tab('show');
});
$('#sidebar #togglebtn').click(toggleSidebar);
$('#deletes').click(deleteTabs);
$('#routeChange').click(function () {
var index = $('#routeChange').data('route');
index = (index+1)%altRouteCount;
deleteTabs();
printRoute (savedRoutes, index);
$('#routeChange').data('route', index);
});
// Call Google Direction
directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();
// Google Autocomplete
var start_input = document.getElementById('start');
var end_input = document.getElementById('end');
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(40.532980, -74.118551),
new google.maps.LatLng(40.895218, -73.735403)
);
// Bounds right now only restrict country
var start_autocomplete = new google.maps.places.Autocomplete((start_input),{
// bounds: {sw:new google.maps.LatLng(40.895218, -73.735403), ne:new google.maps.LatLng(40.532980, -74.118551)},
componentRestrictions: {country: 'us'}
}
);
var end_autocomplete = new google.maps.places.Autocomplete((end_input),{
// bounds: {sw:new google.maps.LatLng(40.895218, -73.735403), ne:new google.maps.LatLng(40.532980, -74.118551)},
componentRestrictions: {country: 'us'}
}
);
start_autocomplete.setBounds(bounds);
end_autocomplete.setBounds(bounds);
// Initial map
function initialize() {
var map;
var pos;
// Default pos for map will be center of Manhattan
if(!pos){
pos = new google.maps.LatLng(40.784148400000000000, -73.966140699999980000);
}
var mapOptions = {
zoom: 13
};
getAddress();
// Draw Map
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
map.setCenter(pos);
// Google Direction text route
directionsDisplay.setMap(map);
directionsDisplay.setPanel(document.getElementById('directions-panel'));
//Needed to resize maps
google.maps.event.addDomListener (map, 'idle', function(){
google.maps.event.trigger (map, 'resize');
});
}
// Load Map
google.maps.event.addDomListener(window, 'load', initialize);
});
/************************************************
Site Navigational Elements
************************************************/
function toggleSidebar() {
var state = $('#sidebar').data('toggle');
if (state == 'hidden') {
document.getElementById('sidebar').className = "sidebar-appear";
$('#sidebar').data('toggle', 'shown');
}
else if (state == 'shown') {
document.getElementById('sidebar').className = "sidebar-hidden";
$('#sidebar').data('toggle', 'hidden');
}
};
function nextSlide() {
$('#navCarousel').carousel('next');
};
function prevSlide(){
$('#navCarousel').carousel('prev');
};
/************************************************
UI Messages
************************************************/
function hideMessage(){
$('#init-message').hide(1000);
};
function pushMessage (messageType, message) {
$('#message-container').hide (0);
if (messageType == 'error') {
document.getElementById('message-container').className = "alert alert-danger";
document.getElementById('icon').className = "glyphicon glyphicon-remove-sign";
}
else if (messageType == 'success') {
document.getElementById('message-container').className = "alert alert-success";
document.getElementById('icon').className = "glyphicon glyphicon-ok-sign";
}
else if (messageType == 'warn') {
document.getElementById('message-container').className = "alert alert-warning";
document.getElementById('icon').className = "glyphicon glyphicon-exclaimation-sign";
}
else {
//Congrats. Senpai has noticed your ability to break shit. Rejoice.
console.error ("Please check your messageType.")
}
$('#message').text(message);
$('#message-container').show (1000);
};
/************************************************
Information Retrieval
************************************************/
// Get current location button function
function getAddress(callback){
geocoder = new google.maps.Geocoder();
// If geolocation available, get position
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(successCallback, errorCallback, {timeout:60000,maximumAge:60000});
}
//Else, browser doesn't support geolocaiton
else {
pushMessage ('error', 'Your browser doesn\'t support geolocation.');
console.log("Browser doesn't support geolocaiton");
}
// Optional callback
if (callback){
callback();
}
};
function successCallback(position){
var pos = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
//Reverse geocoding for current location
geocoder.geocode({'latLng': pos}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results.length != 0) {
currentAddress = results[0].formatted_address;
} else {
alert('No results found');
}
} else {
alert('Geocoder failed due to: ' + status);
}
});
};
function errorCallback(){
};
fillAddress = function() {
if (currentAddress != 'placeholder') {
$('#start').val (currentAddress);
pushMessage ('success', "Got your current location!");
}
else {
pushMessage ('warn', 'Please share your location to use this feature.');
}
};
// Set route and request direction result
function calcRoute() {
var start = document.getElementById('start').value;
var end = document.getElementById('end').value;
if (start == '' && end == '') {
pushMessage ('error', "Please fill in your current location and destination.");
start='';
end='';
return;
}
else if (start == '') {
pushMessage ('error', "Please fill in your current location.");
start='';
end='';
return;
}
else if (end == '') {
pushMessage ('error', "Please fill in your destination.");
start='';
end='';
return;
}
else {
start += ' new york city';
end += ' new york city';
}
var request = {
origin: start,
destination: end,
provideRouteAlternatives: true,
travelMode: google.maps.TravelMode.TRANSIT
};
deleteTabs();
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
altRouteCount = response.routes.length;
savedRoutes = response;
printRoute (savedRoutes, 0);
//Move to next slide when directions have been retrieved.
$('#navCarousel').carousel('next');
//Disable loading icon pseudocode.
//$('#loadingIcon').hide(300);
savedRoutes = response;
}
else {
//If DirectionsStatus.NOT_FOUND
//or DirectionsStatus.ZERO_RESULTS
pushMessage ('error', 'No directions found.');
}
});
};
function printRoute (routeObj, routeNo) {
// Get route object
var thisRoute = routeObj.routes[routeNo].legs[0];
for (var i = 0; i < thisRoute.steps.length; i++) {
// Find all possible transit
if (typeof thisRoute.steps[i].transit != 'undefined'
&& thisRoute.steps[i].transit.line.vehicle.type == "SUBWAY") {
trainTab (thisRoute.steps[i]);
}
}
}
//Get details from Maps API json object
function getTransitDetail(obj, tabNo){
var parent='';
if (tabNo) {
parent='div#tab'+tabNo+' ';
}
$(parent+'#train').text(obj.transit.line.short_name + " Train");
$(parent+'#train-stop-depart').text(obj.transit.departure_stop.name);
$(parent+'#train-stop-end').text(obj.transit.arrival_stop.name);
$(parent+'#num-stop').text(obj.transit.num_stops + " Stops");
$(parent+'#arrival_time').text(obj.transit.arrival_time.text);
$(parent+'#departure_time').text(obj.transit.departure_time.text);
$(parent+'#distance').text(obj.distance.text);
$(parent+'#duration').text(obj.duration.text);
};
// Get current time from device
function getTime(){
var currentdate = new Date();
var datetime = currentdate.getDate() + "/"
+ (currentdate.getMonth()+1) + "/"
+ currentdate.getFullYear() + " # "
+ currentdate.getHours() + ":"
+ currentdate.getMinutes() + ":"
+ currentdate.getSeconds();
return datetime;
};
function makeNewTab() {
var prevTab = 'tab' + tabCount;
tabCount++;
var newTab = 'tab' + tabCount;
console.log ('New Tab.');
//Adds tab to nav bar
$('#routeChange').before('<li>TAG LABEL</li>');
//Adds contents of tab
$('div.tab-content #'+prevTab).after('<div id="'+newTab+'"></div>');
$('#'+newTab).addClass("tab-pane");
};
function deleteTabs() {
var thisTab;
while (tabCount >= 1) {
thisTab = 'tab' + tabCount;
//Remove tab from nav bar
$('ul#tabs li a[href="#'+thisTab+'"]').remove();
//Remove contents of tab
$('#'+thisTab).remove();
tabCount--;
}
tabCount = 1;
$('#tabs a:first').tab('show');
};
function trainTab (obj) {
makeNewTab();
$('ul#tabs li a[href="#tab'+tabCount+'"]').text(obj.transit.line.short_name);
$('#tab'+tabCount).append (
'<div id="station-info" class="col-xs-11 col-xs-height col-sm-12 col-sm-height">\
<p>Station Info:</p>\
<p id="train"></p>\
<p id="train-stop-depart"></p>\
<p id="train-stop-end"></p>\
<p id="num-stop"></p>\
<p id="arrival_time"></p>\
<p id="departure_time"></p>\
<p id="distance"></p>\
<p id="duration"></p>\
<!-- <%= link_to "an article", #station%> -->\
</div>');
getTransitDetail (obj, tabCount);
};
Is it because of the order of my code? I tried playing around with the order and could not find a solution. Any help would be appreciated. Thanks in advance!

jQuery .each loop - Call Function inside

How do I call function inside jQuery .each?
At the moment my function is performed only the last time.
How can I edit this to execute every time the function MyCurrentPosition(dsRow) is called?
This is the code:
Maps.GetCoordinates = function (jsonResponse) {
jQuery.each(jsonResponse, function(filterName,result) {
var risultati = result;
var items = risultati.rows;
//console.log (risultati.total);
if(risultati.total > 0)
{
jQuery.each(items, function(i,dsRow) {
var myhtml= dsRow.latitude;
//This work all time
jQuery('#show_distance_'+dsRow.id).html(myhtml).show();
//but this function only last time print result
MyCurrentPosition(dsRow);
});
}
}); //end foreach
}
EDIT: This is the MyCurrentPosition function :
var options = { enableHighAccuracy: true, timeout: 12000, maximumAge: 0 };
function MyCurrentPosition(dsRow) {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (pos) {
crd = pos.coords;
HelloMapsSearch.GetDistance(crd,dsRow);
},
showError,
options );
} else {
alert("Geolocation is not supported by your device.");
}
//return crd;
}
HelloMapsSearch.GetDistance = function (crd,dsRow) {
var origine = crd;
var destinazione = dsRow;
var mxstart = new google.maps.LatLng(origine.latitude,origine.longitude);
var mxend = new google.maps.LatLng(destinazione.latitude, destinazione.longitude);
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [mxstart],
destinations: [mxend],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
//}, callback );
}, function(response, status) {callback(response, status, dsRow)});
}
function callback(response, status, dsRow) {
if (status != google.maps.DistanceMatrixStatus.OK) {
alert('Error was: ' + status);
} else {
var origins = response.originAddresses;
var destinations = response.destinationAddresses;
var outputDiv = document.getElementById('show_distance_'+dsRow.id);
outputDiv.innerHTML = '';
for (var i = 0; i < origins.length; i++) {
var results = response.rows[i].elements;
for (var j = 0; j < results.length; j++) {
outputDiv.innerHTML += "Origine:"+origins[i] + '<br> to destinazione:' + destinations[j] + '<br>'
+ ': ' + results[j].distance.text + ' in '
+ results[j].duration.text + '<br>';
}
}
}
}
A few things to check out. jsonResponse must be an array. risultati must also have rows that is of type Array.
As for the function inside called MyCurrentPosition, we are currently missing on the implementation itself.
Does it have an if inside that prevents logging? Share the code please.

Javascript 'callback' function not working

I using Google map API v3 to draw routes. But for some path the route is not plotted in the map. so I write a callback function. But it dose not working, my code is
function putRoute(request,color,callback)
{
var color = color;
var request = request;
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var polylineOptionsActual = {
strokeColor :color,
strokeOpacity: 1.0,
strokeWeight : 5,
};
var directionsRenderer = new google.maps.DirectionsRenderer;
directionsRenderer.setMap(map);
directionsRenderer.setOptions( { polylineOptions: polylineOptionsActual, suppressMarkers: true} );
directionsRenderer.setDirections(response);
}
});
if (typeof callback === "function") {
callback(request,color);
}
}
putRoute(request,color,function() {
});
try renaming the function putRoute to
function putRoute(request,color){}
I guess this condition is not true:
if (typeof callback === "function") {
I'd change that to
if (typeof callback != "undefined") {
Atleast, I do know that this last code is working.
You can also try this one:
if (callback instanceof Function) {
// do stuff;
}
Your callback routine is in the wrong place. It needs to be inside the callback function for the DirectionsService:
function putRoute(request,color,callback)
{
var color = color;
var request = request;
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var polylineOptionsActual = {
strokeColor :color,
strokeOpacity: 1.0,
strokeWeight : 5,
};
var directionsRenderer = new google.maps.DirectionsRenderer;
directionsRenderer.setMap(map);
directionsRenderer.setOptions( { polylineOptions: polylineOptionsActual, suppressMarkers: true} );
directionsRenderer.setDirections(response);
// only execute callback on success
if (typeof callback === "function") {
callback(request,color);
}
} else {
alert("Directions request failed:" + status);
}
});
}
I had the same problem when I was defining callback as:
function callback() {
...
}
then I changed it to:
callback = function() {
...
}
and everything worked! hope it helps ;)

Callback with geocoder.geocode

I have some issue with the callback inside geocoder.geocode.
var tri = new Array();
for (var j = 1; j < taille; j++) {
where = getBoutique[j].adresse + ", " + getBoutique[j].ville;
boutiqueProche(lat, lon, where, function (distanceO) {
//window.localStorage.setItem("distance", distance);
console.log(distanceO);
tri.push(distanceO);
//return distance;
//console.log("Nous somme dans "+localStorage.getItem("distance"));
});
console.log("Inside " + tri);
}
function boutiqueProche(cLat, cLong, where, callback) {
var geocoder = new google.maps.Geocoder();
var currentPosition = new google.maps.LatLng(cLat, cLong); // On récupère nos info
var recup = getBoutique.length;
var distance;
geocoder.geocode({
'address': where
}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var laBoutique = new google.maps.LatLng(results[0].geometry.location.lat(), results[0].geometry.location.lng());
distance = google.maps.geometry.spherical.computeDistanceBetween(currentPosition, laBoutique);
recup = distance / 1000;
callback(recup);
} else {
if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
setTimeout(function () {
boutiqueProche(cLat, cLong, where, callback); // rappel fonction avec meme param
}, 200);
} else { /*Faire quelque chose */ }
}
});
}
I want to fill the array tri with the data from recup variable. But when I fill tri, nothing happens. It is empty.
What is the problem?

Categories