Google Direction service plotting unexpected route - javascript

I have an asset i.e. a truck generating reads (lat, lng) at a specific interval and I am plotting those reads on maps using direction service api
But direction service is returning path which is not at all correct.
Highlighted area is a car parking and a truck can't go inside that.
Code provided below:
displayRoute(){
var path = new this.google.maps.MVCArray();
var service = new this.google.maps.DirectionsService();
var markers = this.state.markers;
var wayPoints = [];
if (markers.length >= 2) {
this.isContinueRouting = true;
for (var k = 0, parts = [], max = this.maxWayPointLimit - 1; k < markers.length; k = k + max){
parts.push(markers.slice(k, k + max + 1));
}
var TempParts = [].slice.call(parts);
var delayFactor = 0;
var continueRouting = () => {
if(this.isContinueRouting) {
if (!TempParts || TempParts.length === 0) {
this.refreshMap();
return;
}
var firstPart = TempParts[0];
TempParts = TempParts.slice(1);
wayPoints = [];
for (var j = 1; j < firstPart.length - 1; j++) {
wayPoints.push({location: firstPart[j].latLng, stopover: false});
}
var getDirectionRoute = (objRequest) => {
service.route(objRequest, (result, status) => {
if (status === this.google.maps.DirectionsStatus.OK) {
var renderer = new this.google.maps.DirectionsRenderer({
suppressMarkers: true,
polylineOptions:{strokeColor: '#4986E7', icons:[{icon:{path:this.google.maps.SymbolPath.FORWARD_CLOSED_ARROW}}]}
});
var gRenderers = this.state.gRenderers;
if(!gRenderers){
gRenderers = [];
}
gRenderers.push(renderer);
this.setState({
gRenderers: gRenderers
});
renderer.setMap(this.map);
renderer.setDirections(result);
continueRouting();
}
else if (status === this.google.maps.DirectionsStatus.OVER_QUERY_LIMIT) {
delayFactor++;
setTimeout(() => {
getDirectionRoute(objRequest);
}, delayFactor * 1000);
}
else {
console.log("Route: " + status);
}
});
};
getDirectionRoute({
origin: firstPart[0].latLng,
destination: firstPart[firstPart.length - 1].latLng,
waypoints: wayPoints,
optimizeWaypoints: false,
travelMode: this.google.maps.DirectionsTravelMode.DRIVING
});
}
}
continueRouting();
}
else{
this.refreshMap();
}
}
I am providing lat lng details below as well, separated by |
'31.7041718,-106.2919151|31.7041718,-106.2919151|31.7032561,-106.2934446|31.7076082,-106.2920445|31.6872383,-106.2983887|31.6135476,-106.2551746|31.6160641,-106.2541132|31.6185915,-106.2564508|31.6366903,-106.2750925|31.7042845,-106.2951952|31.7043367,-106.2925862|31.7025645,-106.2905912|31.7815772,-106.4109026|31.792458,-106.5084194|31.8825601,-106.5835285|31.8610442,-106.6844508|31.8685025,-106.7015895|31.8725584,-106.6778204|31.8025682,-106.5208837|31.7450037,-106.3330166|31.7037371,-106.2927402|31.7020747,-106.2912236|31.6605857,-106.2750073|31.6211992,-106.2589605|31.6146543,-106.2533209|31.7194213,-106.3032185|31.7039523,-106.2928624|31.702484,-106.2902215|31.7043125,-106.2952218|31.777505,-106.4241939|31.8764563,-106.5801106|31.7928081,-106.6849148|31.7890649,-106.6837816|31.8092266,-106.6847083|31.8576709,-106.5757679|31.7814772,-106.4071658|31.7040939,-106.2929278|31.7036424,-106.292041|31.7036424,-106.292041|31.7021739,-106.2920716|31.7021681,-106.292032|31.7021681,-106.292032|31.7021681,-106.292032|31.7021681,-106.292032|31.7021681,-106.292032|31.7021681,-106.292032|31.7021681,-106.292032|31.7021681,-106.292032'
I even tried implementing snap to road but that causes other issues as all reads are not near to each other.
Not sure what is the issue here.

I don't think you can use the Directions API to visualise historical routes. Given the start end end coordinates and the waypoints between, the API tries to PLAN and suggest a route for you to take LATER.
I think the only solution would be to fix the problems the Snap to Roads API and use that. If the results are too erratic, then maybe you should set the GPS transponders to report their coordinates more often, if possible.

Related

How to centralized the heat-map area in the map after zoom-in?

I'm using google map API to show Heat-map. After zooming one level, I want the heat-map area to show in the center of the map. I'm attaching the image also, it that you can see the heatmap at the bottom of the map.
render: function() {
var results = this.model.get('results');
if (!results)
return this;
var data = results[this.model.get('index')];
if (!data)
return this;
if (!data.data.length) {
data.data.push({
count: 0,
lat: 0,
lng: 0
});
}
showHeatMapData(data);
var startTime = this.model.get("starttm");
if(startTime >= 1436985000 && startTime <= 1437244199)
{
$("#pichart").show();
}
else
{
$("#pichart").hide();
}
this.heatmap.setData(data);
this.map.setZoom(20);
return this;
}
to zoom and fit the map to all the points:
this.heatmap.setData(data);
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < data.length; i++) {
bounds.extend(data[i]);
}
this.map.fitBounds(bounds);
i am guessing you have a longitude and latitude contains array
somethings looks like
var locationarray = [];
locationarray[0] = new google.maps.LatLng(13.74428, 100.5404525);
locationarray[1] = new google.maps.LatLng(13.744108, 100.543098);
now when you done loading other functions, you can just simply set the map center from your location array, like this
map.setCenter(locationarray[0]);
i hope this will help you.
Try this:
this.heatmap.setData(data);
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < data.length; i++) {
bounds.extend(data[i]);
}
this.map.setCenter(bounds.getCenter());
this.map.setZoom(20);

Google map marker with angularjs for large data

I am building an widget where user can upload an excel file and the places are get marked in the google map.
The following code works, but issue comes when i am reading an large excel file with 10k amount of data, the browser gets stuck. I am using a for loop and adding some timeout to get the data from the google api.
I pass the city name and get the latitude and longitude and mark it on the map.
Is there a better way i can implement?
Here is the code:
function googleMapsInit(widId, $scope, $http, $rootScope, $mdDialog) {
$scope.finish = function() {
var objIndex = getRootObjectById(widId, $rootScope.dashboard.widgets);
$mdDialog.hide();
document.getElementById('map').innerHTML = "";
//excel data
var array = JSON.parse($rootScope.json_string);
$scope.locationData = [];
//dividing it to chunks
var k,j,temparray,chunk = 8;
for (k=0,j=array.length; k<j; k+=chunk) {
temparray = array.slice(k,k+chunk);
var i;
//getting the longitude and latitude from the google geo api
for(i=0;i < temparray.length ; i++){
Geocode(temparray[i].PLACE_OF_ACCIDENT);
}
}
//sometimes data gets delayed
setTimeout(function(){ googleMap(); }, 5000);
};
function Geocode(address) {
var obj = {};
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': address}, function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
obj = {
lat : results[0].geometry.location.G,
lng : results[0].geometry.location.K
};
setTimeout(function(){ $scope.locationData.push(obj); }, 100);
}
else if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
setTimeout(function() {
Geocode(address);
}, 100);
}
else if (status === google.maps.GeocoderStatus.ZERO_LIMIT) {
setTimeout(function() {
Geocode(address);
}, 100);
}
else {
}
});
}
function googleMap() {
var dataStore = $scope.locationData;
var array = JSON.parse($rootScope.json_string);
var map = new google.maps.Map(document.getElementById('map'),{
center: {lat: 7.85, lng: 80.65},
zoom: 6 });
var pinImageGreen = new google.maps.MarkerImage("http://maps.google.com/mapfiles/ms/icons/green-dot.png");
var pinImageBlue = new google.maps.MarkerImage("http://maps.google.com/mapfiles/ms/icons/blue-dot.png");
var marker = [];
var k;
for(k=0; k < array.length; k++){
marker[k] = new google.maps.Marker({
position: {lat: $scope.locationData[k].lat, lng: $scope.locationData[k].lng},
map: map,
title: array[k].PLACE_OF_ACCIDENT,
icon: pinImageGreen,
VEHICLE_TYPE: array[k].VEHICLE_TYPE,
VEHICLE_USAGE: array[k].VEHICLE_USAGE,
VEHICLE_CLASS: array[k].VEHICLE_CLASS
});
marker[k].addListener('click', function(data) {
var j;
for(j=0;j<array.length;j++){
if(($scope.locationData[j].lat == data.latLng.G) && ($scope.locationData[j].lng == data.latLng.K )){
document.getElementById("details").innerHTML =
array[j].PLACE_OF_ACCIDENT + "</br>" +
array[j].VEHICLE_TYPE + "</br>" +
array[j].VEHICLE_USAGE + "</br>" +
array[j].VEHICLE_CLASS + "</br>" ;
}
}
});
}
}
$scope.cancel = function() {
$mdDialog.hide();
};
}
One way to slightly improve performance is this: Instead of adding markers to the map one at a time, just create the markers array separately and then add them all at once to the map. Here is a sample code:
var markersData = [];
for (var i = 0; i < myArray.length; i++) {
var item = scope.myArray[i];
if (item.lat != undefined && item.lon != undefined) {
var icon = 'icon.png';
markersData.push({
lat: item.lat,
lng: item.lon,
title: 'xyz'
});
}
}
map.addMarkers(markersData);
By the way I have used "gmaps.js" for this which simplifies coding google maps, but you don't necessarily need it. The general idea is to avoid adding markers to the map inside the loop, one by one.

Google Maps Roads API returns duplicate coordinates and placeIds

I'm implementing google maps roads API to pick up the coordinates where I clicked on the roads. But it returns more than expected coordinates and placeids. Suppose I set a direction from place A to place B using directions API then I clicked some points (lets say 10 points) on the roads to draw the route. In response the roads API is returning more than 10 placeIds and coordinates where I need only 10. Here is the code.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=drawing,places"></script>
<script>
//GOOGLE_API_KEY
var apiKey = '';
if(!apiKey)
alert("Please provide API Key");
var map;
var elevator;
var directionsDisplay;
var directionsService;
var placeDetailsService;
var drawingManager;
var placeIdArray = [];
var polylines = [];
var snappedCoordinates = [];
var initialLocation;
var siberia = new google.maps.LatLng(60, 105);
var newyork = new google.maps.LatLng(40.69847032728747, -73.9514422416687);
var browserSupportFlag = new Boolean();
function initialize()
{
document.getElementById("save").style.display="none";
var mapOptions = {
zoom: 17,
center: {lat: 40.69847032728747, lng: -73.9514422416687}
};
directionsService = new google.maps.DirectionsService();
var polylineOptionsActual = new google.maps.Polyline({
strokeColor: '#FF0000',
strokeOpacity: 0.6,
strokeWeight: 2
});
directionsDisplay = new google.maps.DirectionsRenderer({polylineOptions: polylineOptionsActual});
map = new google.maps.Map(document.getElementById('map'), mapOptions);
directionsDisplay.setMap(map);
//Place Details
placeDetailsService= new google.maps.places.PlacesService(map);
// Create an ElevationService
elevator = new google.maps.ElevationService();
// Adds a Places search box. Searching for a place will center the map on that location
map.controls[google.maps.ControlPosition.RIGHT_TOP].push(
document.getElementById('bar'));
//Start Location Searchbox
var autocomplete = new google.maps.places.Autocomplete(document.getElementById('autocStart'));
autocomplete.bindTo('bounds', map);
autocomplete.addListener('place_changed', function () {
var placeStart = autocomplete.getPlace();
//alert(placeStart.place_id);
placeDetailsService.getDetails({
placeId: placeStart.place_id
}, function(place, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
console.log(place.geometry.location);
//alert("Start Location: "+place.geometry.location.G);
document.getElementById("startPlaceLat").value=place.geometry.location.G;
document.getElementById("startPlaceLng").value=place.geometry.location.K;
}
});
});
//End Location Searchbox
var autocomplete1 = new google.maps.places.Autocomplete(document.getElementById('autocEnd'));
autocomplete1.bindTo('bounds', map);
autocomplete1.addListener('place_changed', function () {
var placeEnd = autocomplete1.getPlace();
//alert(placeEnd.place_id);
placeDetailsService.getDetails({
placeId: placeEnd.place_id
}, function(place, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
console.log(place.geometry.location);
//alert("End Location: "+place.geometry.location.G);
document.getElementById("endPlaceLat").value=place.geometry.location.G;
document.getElementById("endPlaceLng").value=place.geometry.location.K;
}
});
});
// Enables the polyline drawing control. Click on the map to start drawing a
// polyline. Each click will add a new vertice. Double-click to stop drawing.
drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.POLYLINE,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [
google.maps.drawing.OverlayType.POLYLINE
]
},
polylineOptions: {
strokeColor: '#696969',
strokeWeight: 2
}
});
drawingManager.setMap(map);
// Snap-to-road when the polyline is completed.
drawingManager.addListener('polylinecomplete', function (poly) {
var path = poly.getPath();
polylines.push(poly);
placeIdArray = [];
runSnapToRoad(path);
});
// Clear button. Click to remove all polylines.
$('#clear').click(function (ev) {
for (var i = 0; i < polylines.length; ++i) {
polylines[i].setMap(null);
}
polylines = [];
ev.preventDefault();
document.getElementById("snappedCoordinatesArray").value = "";
document.getElementById("snappedPaceIdArray").value = "";
document.getElementById("altitudeArray").value = "";
document.getElementById("dataDisplay").style.display = "none";
document.getElementById("autocStart").value = "";
document.getElementById("autocEnd").value = "";
document.getElementById("startPlaceLat").value = "";
document.getElementById("startPlaceLng").value = "";
document.getElementById("endPlaceLat").value = "";
document.getElementById("endPlaceLng").value = "";
document.getElementById("save").style.display="none";
directionsDisplay.set('directions', null);
return false;
});
_init();
}
// Snap a user-created polyline to roads and draw the snapped path
function runSnapToRoad(path) {
var pathValues = [];
for (var i = 0; i < path.getLength(); i++) {
pathValues.push(path.getAt(i).toUrlValue());
}
$.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: pathValues.join('|')
}, function (data) {
processSnapToRoadResponse(data);
drawSnappedPolyline();
//getAndDrawSpeedLimits();
});
}
// Store snapped polyline returned by the snap-to-road method.
function processSnapToRoadResponse(data)
{
snappedCoordinates = [];
placeIdArray = [];
for (var i = 0; i < data.snappedPoints.length; i++)
{
var latlng = new google.maps.LatLng(
data.snappedPoints[i].location.latitude,
data.snappedPoints[i].location.longitude);
//getElevation(latlng);
snappedCoordinates.push(latlng);
placeIdArray.push(data.snappedPoints[i].placeId);
}
//get Altitude in meters
getElevation(snappedCoordinates);
document.getElementById("snappedCoordinatesArray").value = snappedCoordinates;
document.getElementById("snappedPaceIdArray").value = placeIdArray;
}
// Draws the snapped polyline (after processing snap-to-road response).
function drawSnappedPolyline() {
var snappedPolyline = new google.maps.Polyline({
path: snappedCoordinates,
strokeColor: 'black',
strokeWeight: 3
});
snappedPolyline.setMap(map);
polylines.push(snappedPolyline);
}
// Gets speed limits (for 100 segments at a time) and draws a polyline
// color-coded by speed limit. Must be called after processing snap-to-road
// response.
function getAndDrawSpeedLimits() {
for (var i = 0; i <= placeIdArray.length / 100; i++) {
// Ensure that no query exceeds the max 100 placeID limit.
var start = i * 100;
var end = Math.min((i + 1) * 100 - 1, placeIdArray.length);
drawSpeedLimits(start, end);
}
}
// Gets speed limits for a 100-segment path and draws a polyline color-coded by
// speed limit. Must be called after processing snap-to-road response.
function drawSpeedLimits(start, end) {
var placeIdQuery = '';
for (var i = start; i < end; i++) {
placeIdQuery += '&placeId=' + placeIdArray[i];
}
$.get('https://roads.googleapis.com/v1/speedLimits',
'key=' + apiKey + placeIdQuery,
function (speedData) {
processSpeedLimitResponse(speedData, start);
}
);
}
// Draw a polyline segment (up to 100 road segments) color-coded by speed limit.
function processSpeedLimitResponse(speedData, start) {
var end = start + speedData.speedLimits.length;
for (var i = 0; i < speedData.speedLimits.length - 1; i++) {
var speedLimit = speedData.speedLimits[i].speedLimit;
var color = getColorForSpeed(speedLimit);
// Take two points for a single-segment polyline.
var coords = snappedCoordinates.slice(start + i, start + i + 2);
var snappedPolyline = new google.maps.Polyline({
path: coords,
strokeColor: color,
strokeWeight: 6
});
snappedPolyline.setMap(map);
polylines.push(snappedPolyline);
//passDataToObjC();
}
}
//Color of the roads depends upon speed limit
function getColorForSpeed(speed_kph) {
if (speed_kph <= 40) {
return 'purple';
}
if (speed_kph <= 50) {
return 'blue';
}
if (speed_kph <= 60) {
return 'green';
}
if (speed_kph <= 80) {
return 'yellow';
}
if (speed_kph <= 100) {
return 'orange';
}
return 'red';
}
//Call Elevation API to get Altitude
function getElevation(snappedCoordinatesArr)
{
var locations = [];
// Retrieve the latlng and push it on the array
for (var i = 0; i < snappedCoordinatesArr.length; i++)
{
locations.push(snappedCoordinatesArr[i]);
}
// Create a LocationElevationRequest object using the array's one value
var positionalRequest =
{
'locations': locations
}
//alert(positionalRequest);
// Initiate the location request
elevator.getElevationForLocations(positionalRequest, function (results, status)
{
if (status == google.maps.ElevationStatus.OK)
{
// Retrieve the first result
if (results)
{
var altitudeArr = [];
for (var j = 0; j < results.length; j++)
{
altitudeArr.push(results[j].elevation);
}
document.getElementById("altitudeArray").value = altitudeArr;
document.getElementById("dataDisplay").style.display = "block";
document.getElementById("save").style.display="block";
//alert(altitudeArr);
}
else
{
alert('No results found');
}
}
else
{
alert('Elevation service failed due to: ' + status);
}
});
}
//Call Directions API to draw route
function calcRoute()
{
var start = document.getElementById("autocStart").value;
var end = document.getElementById('autocEnd').value;
var selectedMode = document.getElementById("travelType").value;
//alert(start);
var request = {
origin: start,
destination: end,
travelMode: google.maps.TravelMode[selectedMode]
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
//Save Details into Database
function _init()
{
document.getElementById("geodata-form").onsubmit = function (e) {
e.preventDefault();
var f = e.target,
formData = new FormData(f),
xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.responseText) {
alert('Geodata successfully saved.');
document.getElementById("save").style.display="none";
// location.reload();
} else {
alert('Error occured !');
}
}
}
xhr.open("POST", f.action);
xhr.send(formData);
}
}
$(window).load(initialize);
</script>
I have created a JSfiddle here. Just give a google API key and then tell me whats wrong with this code?
You are calling the Roads API with interpolate: true. According to the documentation, that causes it to behave the way you say it is.
from the documentation:
interpolate — Whether to interpolate a path to include all points forming the full road-geometry. When true, additional interpolated points will also be returned, resulting in a path that smoothly follows the geometry of the road, even around corners and through tunnels. Interpolated paths will most likely contain more points than the original path. Defaults to false.

google maps direction service not permitting nested plain js call to elevation service

I have a project whereby a route is generated by the google maps directions service, and I have a loop to obtain all coordinates along it (using a functioned called showPathInfo - see base of query for full HTML):
var tp = result.routes[0].legs[i].steps[j].path[k]; // local variable
var z = new google.maps.LatLng(tp.lat(),tp.lng()); // local variable
I wish to make a call to the elevation service during each loop iteration using:
elevation = getElevation(z); // global variable but NOT an array
where getElevation is a function (see base of query for full HTML).
For some reason, even though the coords are correctly passed to the function, and are rendered appropriately into a getElevationForLocations object (I have checked this by having the getElevation return variables before the getElevationForLocations call); the service returns "undefined" for
return results[0].elevation;
I am interested in getting this solution to work to take advantage of the higher accuracy afforded to individual elevation service requests, and am trying to avoid batch requests with locations[] as a full array or using the getElevationForPath function.
Admittedly there is the problem of a limit to the number of single elevation requests that can be made per second and in total, but I have tried slowing down the code execution and limiting the distances in order to get this to work at least once:
function wait() { setTimeout(function () {
elevation = getElevation(z); // here defined as a global variable
}, 500);}
wait();
Does anyone have any ideas why such a nested call like this cannot work?
The full fiddle html code is as follows:
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>html, body, #map-canvas {height: 100%;margin: 0px;padding: 0px}</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true"></script>
<script>
var rendererOptions = { draggable: true };
var directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);;
var directionsService = new google.maps.DirectionsService();
var infowindow = new google.maps.InfoWindow();
var map;
var elevation; // *******************
var elevator;
var start = new google.maps.LatLng(55.60289406109326, -2.88885779678822);
var wpnt1 = new google.maps.LatLng(55.59226543103951, -2.91247397661209);
var wpnt2 = new google.maps.LatLng(55.57330299699533, -2.88813963532448);
var wpnt3 = new google.maps.LatLng(55.58132161006218, -2.84357875585556);
var wpnt4 = new google.maps.LatLng(55.58602383263128, -2.87256672978401);
var wpnt5 = new google.maps.LatLng(55.60450928199337, -2.89154000580311);
var ended = new google.maps.LatLng(55.60289406109326, -2.88885779678822);
function initialize() {
elevator = new google.maps.ElevationService();
var mapOptions = { zoom: 10,center: start };
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
directionsDisplay.setMap(map);
directionsDisplay.setPanel(document.getElementById('directionsPanel'));
google.maps.event.addListener(directionsDisplay, 'directions_changed', function() {
document.getElementById('points').innerHTML = "";
showPathInfo(directionsDisplay.getDirections());
});
calcRoute();
} // ***** End of initialise function
function calcRoute() {
var request = {origin: start,destination: ended,
waypoints:[{location: wpnt1}, {location: wpnt2}, {location: wpnt3}, {location: wpnt4}, {location: wpnt5}],
travelMode: google.maps.TravelMode.WALKING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
function showPathInfo(result) {
var total = 0;
var ns = 0;
var pt = 0;
var myroute = result.routes[0];
document.getElementById('points').insertAdjacentHTML('beforeend', '<th>Point</th><th>Lat</th><th>Lon</th><th>Elevation</th>');
for (var i = 0; i < myroute.legs.length; i++) {
total += myroute.legs[i].distance.value;
ns += myroute.legs[i].steps.length;
for (var j = 0; j < myroute.legs[i].steps.length; j++) {
for (var k = 0; k < myroute.legs[i].steps[j].path.length; k++) {
var tp = myroute.legs[i].steps[j].path[k];
var z = new google.maps.LatLng(tp.lat(),tp.lng());
//function wait() { setTimeout(function () {
elevation = getElevation(z);
//}, 500);} // End of getAndWait
//wait();
document.getElementById('points').insertAdjacentHTML('beforeend',
'<tr><td>' + pt + '</td><td>' +
tp.lat().toFixed(7) + '</td><td>' +
tp.lng().toFixed(7) + '</td><td>' +
elevation + '</td></tr>');
pt += 1;
}
}
}
total = total / 1000.0;
document.getElementById('total').innerHTML = total + ' km';
document.getElementById('legs').innerHTML = myroute.legs.length;
document.getElementById('steps').innerHTML = ns;
}
function getElevation(z) {
var locations = [];
var clickedLocation = z;
locations.push(clickedLocation);
var positionalRequest = { 'locations': locations }
elevator.getElevationForLocations(positionalRequest, function(results, status) {
if (status == google.maps.ElevationStatus.OK) {
// Retrieve the first result
if (results[0]) {
return results[0].elevation;
} else {
return 'No results found';
}
} else {
return 'Elevation service failed due to: ' + status;
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map-canvas" style="float:left;width:70%; height:100%"></div>
<div id="directionsPanel" style="float:right;width:30%;height 25%">
<p>Total Distance: <span id="total"></span> Legs: <span id="legs"></span>Steps: <span id="steps"></span></p>
<table id="points"></table>
</div>
</body>
</html>
Postscript
In the end it was the use of a Bluebird promise loop that worked.
<script src="https://cdn.jsdelivr.net/bluebird/latest/bluebird.js"></script>
For the record I was not using node.js or any other functionality other than just plain js plus bluebird. Promises are dealt with in detail by many answers in StackOverflow so I recommend reading these and looking through the API: https://github.com/petkaantonov/bluebird/blob/master/API.md .

Will there be any inconsistency with the value calculated?

I have a javascript code like below to calculate the total distance between n markers.
var distance = 0;
function updateTimeAndDistance(timeAndPath) {
realtracPath = timeAndPath.path;
getDistance();
console.log("calculated distance : " + distance);
}
function getDistance() {
for ( var i = 0; i < realtracPath.length - 1 ; i++) {
var startPos = new google.maps.LatLng(realtracPath[i].lat, realtracPath[i].lng);
var endPos = new google.maps.LatLng(realtracPath[i+1].lat, realtracPath[i+1].lng);
var request = {
origin : startPos,
destination : endPos,
travelMode : google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
distance += response.routes[0].legs[0].distance.value;
}
});
}
}
but I am worried that, will there be any inconsistency in the value of the distance calculated as the distance is calculated asynchronously.
EDIT: every time I run this, I am getting distance as zero. I am not understanding why, though I have used the global distance variable.
Thanks.
Try introducing an async callback function like so;
var distance = 0;
function updateTimeAndDistance(timeAndPath) {
realtracPath = timeAndPath.path;
getDistance(function(){
console.log("calculated distance : " + distance);
});
}
function getDistance(cb) {
var latch = realtrackPath.length;
for ( var i = 0; i < realtracPath.length - 1 ; i++) {
var startPos = new google.maps.LatLng(realtracPath[i].lat, realtracPath[i].lng);
var endPos = new google.maps.LatLng(realtracPath[i+1].lat, realtracPath[i+1].lng);
var request = {
origin : startPos,
destination : endPos,
travelMode : google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
distance += response.routes[0].legs[0].distance.value;
latch--
if (latch==0){
cb()
}
}
});
}
}
Note: If the status does not come back as OK nothing will happen. It can be quite handy to have callbacks with function signatures that pass booleans indicating errors etc.

Categories