I am trying to render bus routes of bangalore city with snap to road feature provided by google api. If I just render single route, it is visible with the colour I mention for stroke color property of polyline.If the route is pretty long, then I am splitting the route into multiple paths for that route. But, when I add the second route, a polyline from the end of first route to the start of second route is drawn. I am not able to figure out, where I am going wrong. Any help is deeply appreciated. Please find the javascript code of the same.
<script type="text/javascript">
var infoWindow = new google.maps.InfoWindow();
var routePath;
var OrgDest;
var OrgDestpoints;
var wp;
var waypts;
var traceroutePath;
var service;
var map;
var marker, markloc;
var markers = [];
var orgdest = {"1": [[12.9197565816171, 77.5923588994416,12.95719452, 77.56829549],[12.95719452, 77.56829549,12.98997477, 77.57209867],[12.98997477, 77.57209867,13.02311, 77.55029]],"KHC": [[12.97466107, 77.58199613,12.97466107, 77.58199613]]};
var waypoints = {"1":[[12.92268932, 77.59338455,12.92318598, 77.58877168,12.9279596, 77.58760419,12.93610683, 77.58392363,12.93672057, 77.57217014,12.93956243, 77.57215225,12.94189, 77.57358,12.94574241, 77.57070059],[12.95850855, 77.57402561,12.96161187, 77.57527904,12.96366, 77.56843,12.96811874, 77.56800682,12.97736, 77.57074,12.98997477, 77.57209867],[12.98997477, 77.57209867,12.99789013, 77.57130999,13.00908169, 77.5710476,13.01742075, 77.55707759]],"KHC": [[12.98420536, 77.59761828,12.98368012, 77.6035693]]};
var routeColors = {"1": "#FF00FF","KHC": "#800000"};
var routeNames = ["1","KHC"];
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(12.9536775, 77.5883784),
zoom: 12
};
map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions);
//directionsDisplay.setMap(map);
var routeInfoWindow = new google.maps.InfoWindow({ // this info window shows the route name when the mouse hovers over a route line
disableAutoPan: true
});
for (var i = 0; i < routeNames.length; i++) { // loop over each route
var routeName = routeNames[i];
for (var j = 0; j < orgdest[routeName].length; j++) { // loop over each path on the route
OrgDest = orgdest[routeName][j];
OrgDestpoints = []
for (var k = 0; k < OrgDest.length; k += 2) { // loop over each point in the path
OrgDestpoints.push(new google.maps.LatLng(OrgDest[k], OrgDest[k+1]));
}
waypts = [];
if(waypoints[routeName].length > 0)
{
wp = waypoints[routeName][j];
for (var k = 0; k < wp.length; k += 2) { // loop over each waypoints in the path
waypts.push(
{location:new google.maps.LatLng(wp[k], wp[k+1]),
stopover:true
});
}
}
if(j>0)// & (j!=(orgdest[routeName].length)))
traceroutePath.setMap(null); //clearing previously rendered map
if(i>0 & j==0)
{
traceroutePath.setMap(null); //clearing previously rendered map
}
routePath = OrgDestpoints;
traceroutePath = new google.maps.Polyline({
path: routePath,
strokeColor: routeColors[routeName],
strokeOpacity: 1.0,
strokeWeight: 2
});
service = new google.maps.DirectionsService(),traceroutePath,snap_path=[];
traceroutePath.setMap(map);
for(z=0;z<routePath.length-1;z++){
service.route({origin: routePath[z],destination: routePath[z+1],
travelMode: google.maps.DirectionsTravelMode.DRIVING,
waypoints: waypts},
function(result, status) {
if(status == google.maps.DirectionsStatus.OK) {
snap_path = snap_path.concat(result.routes[0].overview_path);
alert(result.routes[0].legs[0].start_location)
traceroutePath.setPath(snap_path);
} else alert("Directions request failed: "+status);
});
}
} //end of j for loop; paths to form a route
}//end of i for loop; all routes
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
You have two issues that are causing the issue.
the code is concatenating the paths from the directions requests together, that is an issue because:
a. the directions service is asynchronous, the routes may come back in a different order than you send them (unless you send them one by one).
b. the routes requested are not continuous.
for (z = 0; z < routePath.length - 1; z++) {
service.route({
origin: routePath[z],
destination: routePath[z + 1],
travelMode: google.maps.DirectionsTravelMode.DRIVING,
waypoints: waypts
},
function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
var snap_path = result.routes[0].overview_path;
var traceroutePath = new google.maps.Polyline({
strokeColor: routeColors[routeName],
strokeOpacity: 1.0,
strokeWeight: 2,
map: map
});
traceroutePath.setPath(snap_path);
} else alert("Directions request failed: " + status);
});
proof of concept fiddle
code snippet:
var infoWindow = new google.maps.InfoWindow();
var routePath;
var OrgDest;
var OrgDestpoints;
var wp;
var waypts;
var traceroutePath;
var service;
var map;
var marker, markloc;
var markers = [];
var orgdest = {
"1": [
[12.9197565816171, 77.5923588994416, 12.95719452, 77.56829549],
[12.95719452, 77.56829549, 12.98997477, 77.57209867],
[12.98997477, 77.57209867, 13.02311, 77.55029]
],
"KHC": [
[12.97466107, 77.58199613, 12.97466107, 77.58199613]
]
};
var waypoints = {
"1": [
[12.92268932, 77.59338455, 12.92318598, 77.58877168, 12.9279596, 77.58760419, 12.93610683, 77.58392363, 12.93672057, 77.57217014, 12.93956243, 77.57215225, 12.94189, 77.57358, 12.94574241, 77.57070059],
[12.95850855, 77.57402561, 12.96161187, 77.57527904, 12.96366, 77.56843, 12.96811874, 77.56800682, 12.97736, 77.57074, 12.98997477, 77.57209867],
[12.98997477, 77.57209867, 12.99789013, 77.57130999, 13.00908169, 77.5710476, 13.01742075, 77.55707759]
],
"KHC": [
[12.98420536, 77.59761828, 12.98368012, 77.6035693]
]
};
var routeColors = {
"1": "#FF00FF",
"KHC": "#800000"
};
var routeNames = ["1", "KHC"];
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(12.9536775, 77.5883784),
zoom: 12
};
map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
var routeInfoWindow = new google.maps.InfoWindow({ // this info window shows the route name when the mouse hovers over a route line
disableAutoPan: true
});
for (var i = 0; i < routeNames.length; i++) { // loop over each route
var routeName = routeNames[i];
for (var j = 0; j < orgdest[routeName].length; j++) { // loop over each path on the route
OrgDest = orgdest[routeName][j];
OrgDestpoints = []
for (var k = 0; k < OrgDest.length; k += 2) { // loop over each point in the path
OrgDestpoints.push(new google.maps.LatLng(OrgDest[k], OrgDest[k + 1]));
}
waypts = [];
if (waypoints[routeName].length > 0) {
wp = waypoints[routeName][j];
for (var k = 0; k < wp.length; k += 2) { // loop over each waypoints in the path
waypts.push({
location: new google.maps.LatLng(wp[k], wp[k + 1]),
stopover: true
});
}
}
if (j > 0) // & (j!=(orgdest[routeName].length)))
traceroutePath.setMap(null); //clearing previously rendered map
if (i > 0 & j == 0) {
traceroutePath.setMap(null); //clearing previously rendered map
}
routePath = OrgDestpoints;
traceroutePath = new google.maps.Polyline({
path: routePath,
strokeColor: routeColors[routeName],
strokeOpacity: 1.0,
strokeWeight: 2
});
service = new google.maps.DirectionsService(), traceroutePath, snap_path = [];
traceroutePath.setMap(map);
for (z = 0; z < routePath.length - 1; z++) {
service.route({
origin: routePath[z],
destination: routePath[z + 1],
travelMode: google.maps.DirectionsTravelMode.DRIVING,
waypoints: waypts
},
function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
var snap_path = result.routes[0].overview_path;
var traceroutePath = new google.maps.Polyline({
strokeColor: routeColors[routeName],
strokeOpacity: 1.0,
strokeWeight: 2,
map: map
});
traceroutePath.setPath(snap_path);
} else alert("Directions request failed: " + status);
});
}
} //end of j for loop; paths to form a route
} //end of i for loop; all routes
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map-canvas"></div>
I am developing this page for a site, that generates search results based on the current logged in user. My aim is to loop through every house and assign it a distance.
My issue is I cannot seem to use context (this) inside of a distance matrix request/response.
$('.houseWrapper').each(function() {
var origin = $(this).children('.houseMeta').attr('data-origin');
var destination = $(this).children('.houseMeta').attr('data-destination');
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [origin],
destinations: [destination],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false,
}, callback);
function callback(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;
console.log($(this).html());
}
}
}
}
});
try :
var that = this;
var origin = $(this).children('.houseMeta').attr('data-origin');
....
Then later:
console.log($(that).html());
I would make "this" passed in as an argument to the function, kind of like how a partial function works.
var callback = function(this) {
return function(response, status) {
// ...
}
}(this);
there are 2 arguments that will be passed to the $.each()-callback, the index of the element and the element.
Just use these arguments:
$('.houseWrapper').each(function(index,node) {
//somewhere
console.log($(node).html());
});
I am a bit confused with my code and I don't really know which way to go.
Let's consider I have a car marker that is running through a polyline.
I change its position each 500 ms by setting a timer :
function animate() {
var p = polyline.GetPointAtDistance(distanceFromBeginning);
carMarker.setPosition(p);
distanceFromBeginning += step;
timerHandle = setTimeout("animate("+(distanceFromBeginning)+")", tick);
}
I also added the fact that my car can be dragged on the route :
google.maps.event.addDomListener(carMarker, 'dragend', function(e) {
var p = find_closest_point_on_path(e.latLng,polyline.getPath());
console.log("position is : " + p);
carMarker.setPosition(p);
console.log("dragend")
});
Now that I have a new position after dragging the car on the polyline, how can I get its distance from the start location so I can update it correctly in my timer?
Once you have the coordinates for the end location (lets call the "destination"), and assuming that on your 'dragend' event you set the coordinates for the car (let call "origin") location you can call this function on your listener:
function calculateDistances() {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [origin],
destinations: [destination],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, callback);
}
function callback(response, status) {
if (status != google.maps.DistanceMatrixStatus.OK) {
alert('Error was: ' + status);
} else {
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++) {
console.log(results[j].distance.text);
console.log(results[j].duration.text);
}
}
}
}
Check this example on jsfiddle based on the Google documentation(look the result on your console)
Fell free to reply if you need more help with this code or if it's not what you want.
I have been playing a little bit with Google's DistanceMatrixService. The code below works, but, how can I pass another parameter to the callback function or grab one of the values out of the callback?
For example: I have two divs that I want to show different results in (Results1 and Results2), so I am thinking I need to either
pass another value to the GoogleMapDistance function like GoogleMapDistance(YourLatLong,DestLatLong,TheDiv)
or
be able to grab the ResultStr externally outside of the callback document.getElementById("Results1").innerHTML = ResultStr;
or
set the innerHTM to the returned value of the function document.getElementById("Results1").innerHTML = GoogleMapDistance(YourLatLong,DestLatLong);
I'm stuck. How can I do accomplish this? The way it looks right now is that I am only going to be able to run all this code once and have it only write to one div.
<div id="Results1"></div>
<div id="Results2"></div>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<script>
function GoogleMapDistance(YourLatLong,DestLatLong)
{
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [YourLatLong],
destinations: [DestLatLong],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.IMPERIAL,
avoidHighways: false,
avoidTolls: false
}, callback);
}
function callback(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 from = origins[i];
var to = destinations[j];
var distance = element.distance.text;
var duration = element.duration.text;
var ResultStr = distance + " (<i>" + duration + "</i>)";
}
}
document.getElementById("Results1").innerHTML = ResultStr;
}
}
var YourLatLong = "45.4049,-122.797997";
var DestLatLong1 = "47.468893,-122.227978";
var DestLatLong2 = "61.221274,-149.831545";
GoogleMapDistance(YourLatLong,DestLatLong1);
</script>
You can't change how Google calls the callback, but you can let it call your own locally function as the callback and then have that (via a closure) call another callback after adding the desired extra argument like this:
function GoogleMapDistance(YourLatLong,DestLatLong, item)
{
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [YourLatLong],
destinations: [DestLatLong],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.IMPERIAL,
avoidHighways: false,
avoidTolls: false
}, function(response, status) {callback(response, status, item)});
}
Or, you could just define your callback inline so it has access to the parent function variables directly:
function GoogleMapDistance(YourLatLong,DestLatLong, item)
{
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [YourLatLong],
destinations: [DestLatLong],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.IMPERIAL,
avoidHighways: false,
avoidTolls: false
}, function callback(response, status)
{
// you can access the parent scope arguments like item here
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 from = origins[i];
var to = destinations[j];
var distance = element.distance.text;
var duration = element.duration.text;
var ResultStr = distance + " (<i>" + duration + "</i>)";
}
}
document.getElementById("Results1").innerHTML = ResultStr;
}
}
)}
I play with distance matrix
http://code.google.com/apis/maps/documentation/javascript/services.html#distance_matrix
to get the duration from one origin to multiple destinations.
I have this code:
var duration = new Array();
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [origin],
destinations: destination,
travelMode: google.maps.TravelMode.DRIVING,
avoidHighways: false,
avoidTolls: false
},
function(response, status)
{
if (status == google.maps.DistanceMatrixStatus.OK)
{
var destinations = response.destinationAddresses;
var results = response.rows[0].elements;
for (var j = 0; j < results.length; j++)
duration[j] = results[j].duration.value;
}
});
alert(duration[0]);
but i have alert "undefined". when i put the alert command inside the callback function i have the alert i want. why is that??? how can i fix it?
Thank u in advance!
var duration = new Array();
function calculate_distance(){
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [origin],
destinations: destination,
travelMode: google.maps.TravelMode.DRIVING,
avoidHighways: false,
avoidTolls: false
},
function(response, status)
{
if (status == google.maps.DistanceMatrixStatus.OK)
{
var destinations = response.destinationAddresses;
var results = response.rows[0].elements;
for (var j = 0; j < results.length; j++)
duration[j] = results[j].duration.value;
}
});
}
google.maps.event.addListener(autocomplete, 'place_changed', calculate_distance);
alert(duration[0]);
Try anything like that
Move the alert in to the callback. The function is a callback that is executed asynchronously.