Google Maps Route Generation with Waypoints - google-maps

I've got an existing app that tracks vehicles and renders their polyline on a map, and I want to be able to import these polylines into another app using the routing service (so that the imported polyline snaps to the road and can be dragged around etc).
What I'm currently doing is encoding:
var encoded_path = google.maps.geometry.encoding.encodePath(coordinate_array)
The lat lng coordinates array that draws the line (inside the polyline app), and passing this into the directions service route like so (inside the other app):
var coordinates = google.maps.geometry.encoding.decodePath(encoded_path);
var request = {
origin: coordinates[0],
destination: coordinates[coordinates.length - 1],
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
MapService.directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
MapService.directionsDisplay.setDirections(response);
}
});
The problem with this approach is that it's only using the start and end of the polyline to draw the route, so all of the diversions along the route are not shown. So I tried to add waypoints (Google has a limit of 8) to try and get a slightly more accurate route like so:
var waypoints = [];
if (coordinates.length <= 8) {
waypoints = coordinates;
}
else {
for (var i = 0; i < 8; i++) {
var index = Math.floor((coordinates.length/8) * i);
// Break if there's no more waypoints to be added
if (index > coordinates.length - 1)
break;
waypoints.push(new google.maps.LatLng(coordinates[index].lat(), coordinates[index].lng()));
// Break if we've just added the last waypoint
if (index == coordinates.length - 1)
break;
}
}
This way it gets waypoints evenly across the coordinates array. And then I'm trying to display them like so on my call to route:
var request = {
origin: coordinates[0],
destination: coordinates[coordinates.length - 1],
waypoints: waypoints
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
But I'm getting this error: Error: in property waypoints: at index 0: unknown property lb
Does anyone know what could be happening, or how to do this waypoint stuff? I can confirm that the array is correctly generated through the console, here's an example of the first array element:
Array[8]
0: N
lb: -22.39019
mb: 143.04560000000004
__prot__: N
1:...etc etc
Thank you.

waypoints.push(new google.maps.LatLng(coordinates[index].lat(), coordinates[index].lng()));
the 'waypoints' property of the DirectionsRequest object definition should be an Array of google.maps.DirectionsWaypoint object definitions https://developers.google.com/maps/documentation/javascript/3.exp/reference#DirectionsWaypoint
So, try:
waypoints.push(
{
location: new google.maps.LatLng(coordinates[index].lat(), coordinates[index].lng())
}
);

Related

How to reset coordinates into an Ajax call after having initialized a map?

I inserted a map on my webpage by using the Leaflet library. What I want to do is to show a map zoomed on a specific region according to which city the user types into a text field.
I firstly initialized my map on my JS file:
function initMaps(){
map = L.map('leaflet').setView([0, 0], 13);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
'attribution': 'Map data © OpenStreetMap contributors'
}).addTo(map);
}
My javascript code also has an Ajax call.
What I want to do now is to reset the coordinates on the Ajax call.
I wrote the following:
var readCoordinates = function(){
$.ajax({
url: "https://nominatim.openstreetmap.org/search?q=" + encodeURIComponent($("#inlineFormInputCitta").val()) + "+Italy&format=geocodejson",
dataType: "json",
success: function (data) {
setTimeout(function () {
for (let i = 0; i < data.features.length; i++) {
let coordinate = data.features[i].geometry.coordinates;
console.log(coordinate);
map.setView(coordinate, 13);
console.log("ajax and for loop have been activated");
console.log(coordinate.geometry.coordinates);
};
$("#ristoranti").prop("disabled", false);
}, 1000);
}
});
};
The API I'm referring to in the URL is the following: https://nominatim.openstreetmap.org/search?q=Roma%20Italy&format=geocodejson
What I did is trying to reset the coordinates here: map.setView(coordinate, 13);
after having cycled the elements in the JSON object, see the following:
for (let i = 0; i < data.features.length; i++) {
let coordinate = data.features[i].geometry.coordinates;
I may display several coordinates in the console, see the following:
That's because in the JSON file I get through the API request there are several:
The result of this is the following map, which isn't zoomed anywhere:
Which coordinates should I take in order to display that specific region?
EDIT - - -
I changed the code because I'm trying to get a specific subobject, i.e. the one in the screen below (which has "type" = "city"):
The new snippet is the one below, where I add an if statement:
var readCoordinates = function(){
$.ajax({
url: "https://nominatim.openstreetmap.org/search?q=" + encodeURIComponent($("#inlineFormInputCitta").val()) + "+Italy&format=geocodejson",
dataType: "json",
success: function (data) {
setTimeout(function() {
for (let i = 0; i < data.features.length; i++) {
debugger;
let type = data.features[i].properties.geocoding.type;
if( $(type).val() === "city") {
let coordinate = data.features[i].geometry.coordinates;
let lng = coordinate[0];
let lat = coordinate[1];
map.setView([lng, lat], 13);
console.log("ajax and for loop have been activated");
console.log(coordinate);}
};
$("#ristoranti").prop("disabled", false);
}, 1000);
}
});
};
I'm doing the debugger and get many undefined values:
I would do something like that:
if (typeof data.features[0] !== 'undefined') {
let coordinate = data.features[0].geometry.coordinates;
var latlng = L.latLng(coordinate.reverse());
map.flyTo(latlng, 12)
}
Be sure to have something in your array
Get data from the first item since it should be the correct one in most case
Create a latlng with those coordinates. Be careful, sometime you need to reverse the array to have the correct position.
Use flyTo to have a smooth transition to your coordinates. 12 is the zoom level
You don't need to loop over the data since you need only one position. You can replace the for with that.
You're having two problems here:
The response from the Nominatim API is returning several search results, each of them in one GeoJSON Feature inside the response FeatureCollection. It's up to you to choose which search result you want to focus in the map (the first?), or let the user do so.
You're not aware that GeoJSON uses longitude-latitude (or x-y) coordinates, whereas Leaflet uses latitude-longitude (or y-x)

How can I return the distance out of the Google Directions API for later use?

I am trying to calculate the distance between 2 points on the map, and it works pretty good.
The problem is that I am trying to make the function return the distance, so that I can use it, not only display it.
Here is my code:
function getDistance(origin, destination){
var directionsService = new google.maps.DirectionsService();
var request = {
origin: origin,
destination: destination,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request,function(response){
var d = response.routes[0].legs[0].distance.value;
//alert(d);
});
}
The thing is that I want not olny to be able to alert the result, but also to use it in order to, say order some locations based on the distance from the user, and using this kind of function, I don;'t see how.
Thanks!
Just declare your var d outside your function, then you could use it later
var d;
function getDistance(origin, destination) {
// ...
d = response.routes[0].legs[0].distance.value;
}
You can now use d in another method or elsewhere in your code.

Google map API Directions - Issue with variable

I can display the directions between two points using google api as follows:-
if (e.keyCode == 109 && $("#booking-docket").dialog("isOpen")) {
var pickup = $('#txt-pickup-lat-long').val();
var destination = $('#txt-destination-lat-long').val();
alert(pickup);
alert(destination);
var start = new google.maps.LatLng(52.73696,-1.3553244444444);
var end = new google.maps.LatLng(52.781048888889,-1.2110222222222);
var request = {
origin:start,
destination:end,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
alert(pickup) = 52.73696,-1.3553244444444
alert(destination) = 52.781048888889,-1.2110222222222
However, when I change these values from:-
var start = new google.maps.LatLng(52.73696,-1.3553244444444);
var end = new google.maps.LatLng(52.781048888889,-1.2110222222222);
to:-
var start = new google.maps.LatLng(pickup);
var end = new google.maps.LatLng(destination);
It stops working, even though the values of pickup & destination are exactly the same as what is typed in (without using variables).
Any ideas why this is happening?
The problem is that pickup and destination are strings, which is what the jQuery .val() function returns.
The LatLng constructor expects floats. Wrap your pickup and destination values in parseFloat to convert them from string to floats.
In fact as they're actually a list, each containing two items, you'll need to split them into their two separate parts first as well.
var pickup = $('#txt-pickup-lat-long').val();
var pickupLat = pickup.split(",")[0];
var pickupLng = pickup.split(",")[1];
var start = new google.maps.LatLng(parseFloat(pickupLat), parseFloat(pickupLng));

Google maps how to force marker on the nearest road

I am doing a vehicle traking project, i am getting coordiantes from the databases, and showing on the google maps.
here is my code.....!!
function get_coordinates(checkbox){
var v_id=checkbox.id;
if(checkbox.checked){
var hr = new XMLHttpRequest();
hr.open("POST", "fetch_coordinates.php", true);
hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
hr.onreadystatechange = function() {
if(hr.readyState == 4 && hr.status == 200) {
var data = JSON.parse(hr.responseText);
var lat=data.loc.lat;
var lon=data.loc.lon;
addmarker(lat,lon,v_id);
}
}
hr.send("id="+v_id);
} else{
var mark = markers[v_id]; // find the marker by given id
mark.setMap(null);
delete markers[v_id];
}
}
function addmarker(lat,lon,v_id){
var marker = new google.maps.Marker({
id: v_id,
position: new google.maps.LatLng(lat, lon),
zoom: 8,
map: map,
title: 'Vehicle No: '+v_id,
icon: 'live.gif',
optimized:false
});
markers[v_id] = marker;
bounds.extend(new google.maps.LatLng(lat,lon));
// map.setOptions({center:new google.maps.LatLng(lat,lon),zoom:8});
map.fitBounds(bounds);
}
But the problem is, sometimes i get GPS coordiantes which are 1,2 inches away from the road (possibly because of less precison of device or signal distortion etc)
How should I force my marker to automatically adjust on the road? Is there a some way, using direction rendering or any other hint ??? please help
In 2017 the right way to do it is the Roads API Snap to Roads service.
You can read about this web service on
https://developers.google.com/maps/documentation/roads/snap
The Google Maps Roads API takes up to 100 GPS points collected along a route, and returns a similar set of data, with the points snapped to the most likely roads the vehicle was traveling along. Optionally, you can request that the points be interpolated, resulting in a path that smoothly follows the geometry of the road.
https://developers.google.com/maps/documentation/directions/intro
You can use your desired url to get json request..
In the Coding section you can write this code to get the location on the road..
Marker liveloc;
JSONObject obj1=new JSONObject(s);
JSONArray arr1=obj1.getJSONArray("routes");
for (int i=0;i<arr1.length();i++){
JSONObject obj2=arr1.getJSONObject(i);
JSONArray arr2=obj2.getJSONArray("legs");
JSONObject obj3=arr2.getJSONObject(0);
JSONObject obj4=obj3.getJSONObject("start_location");
String k=obj4.getString("lat");
String k2=obj4.getString("lng");
double k3=Double.parseDouble(k);
double k4=Double.parseDouble(k2);
LatLng myloc=new LatLng(k3,k4);
if (liveloc !=null){
liveloc.remove();
}
liveloc=mMap.addMarker(new MarkerOptions().position(myloc));
}
You need to get the first start location from the json request..
Hope it helps...

Using TRANSIT as my travel mode in Google Map api v3

When I was using TRANSIT as my travel mode in Google Map api V3, I defined the origin, destination and some waypoints in DirectionsRequest. However when DirectionsResult came back, DirectionsLeg only started with my origin and ended with my destination, it skipped all my waypoints.
My codes are shown as below
Does anyone get the same problem here?
function calcRoute(waypts, mode) {
var sites = [];
var mode;
//Add waypoints to array, the first and last one are not added in waypoints
for (var i = 1; i < waypts.length-2; i++) {
sites.push({
location:waypts[i],
stopover:true}); //Set true to show that stop is required
}
var request = {
origin: waypts[0], //Set the first one as origin
destination:waypts[waypts.length-1],//Set the last one as destination
waypoints:sites,//Set waypoints
optimizeWaypoints:false,
travelMode: google.maps.TravelMode[mode]
};
//Send to Google
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
var HTMLContent = "";
//Get response and show on my HTML
for(var i =0; i < route.legs.length; i++){
HTMLContent = "From " + route.legs[i].start_address + "To " + route.legs[i].end_address + "<br>";
HTMLContent = HTMLContent + "Distance:" + route.legs[i].distance.text + "<br>";
}
$("#route_Scroll").append(HTMLContent);
}else{
alert(status);
}
});
}
Yup,
https://developers.google.com/maps/documentation/javascript/directions#TransitOptions
"The available options for a directions request vary between travel modes. When requesting transit directions, the avoidHighways, avoidTolls, waypoints[] and optimizeWaypoints options will be ignored. You can specify transit specific routing options through the TransitOptions object literal."
If you want to use it you would have to split the request.
You can't specify waypoints when TravelMode is TRANSIT.
the documentation (now) states:
Waypoints are not supported for transit directions.
The directions service always returns INVALID_REQUEST in that case.
Example