I'm trying to create a leaflet routing machine route in my web app using waypoints stored in a database. I'm first creating the control:
var routeControl = L.Routing.control({waypoints: [null]}).addTo(map);
getTestRoute("1");
The function 'getTestRoute' pulls in my waypoints from a db as lat/long pairs and adds them to the control, here's the function:
function getTestRoute(route){
$.ajax({
url: './get_route.php',
type: 'POST',
dataType: 'JSON',
data: {
getRoute: route
},
success: function (res) {
$.each(res,function(key,value){
var newLatLng = new L.LatLng(res[key].latitude, res[key].longitude);
routeControl.spliceWaypoints(0, 0, newLatLng);
})
}
});
}
My issue is that instead of seeing a route on the map I'm seeing my waypoints (five in total) added to the map as markers with no routing between them.
Please please help!!!
Here is a fiddle of my issue: http://jsfiddle.net/c4yfy4ek/46/
As can be seen on the fiddle no routes are created between the points, and the points are added as markers (which I'm assuming is unexpected??).
The problem is the use of spliceWaypoints combined with an undocumented feature in Leaflet Routing Machine.
When the control is created, it will automatically add waypoints such that the route always has a start and an end waypoint, it such waypoints are not already supplied. That means: whatever you do, getWaypoints will always return an array with at least two entries; if not provided, these waypoints will however have their latLng properties set to undefined, indicating the location has not yet been provided.
In the code in question, the control is created and will get two waypoints added implicitly by Leaflet Routing Machine, with undefined locations. Later, you add a couple of new waypoints, but the implicit two waypoints remain, without locations. No route will be calculated, since two waypoints are missing locations.
The solution is to build the array of waypoints first, and then call setWaypoints, instead of spliceWaypoints.
See an updated version of the fiddle: http://jsfiddle.net/c4yfy4ek/53/
Related
I'm working on a project and I need to display points of interest that are saved in a database.
For the itinerary, I used leaflet routing machine and nominatim.
Now I need to display those points of interest that are 5km around the route.
I found in this link https://www.liedman.net/leaflet-routing-machine/api/#iroute the property "coordinates". It returns an array of all the waypoints used to display the itinerary.
How can I use this function to make a call on my database each kilometer to get my informations ?
I hope I was clear and thank you !
I worked on a similar problem and in my case I queried the routing server directly and got the coordinates of each step between the waypoints.
I found it ! I used this :
L.Routing.control({
waypoints: [(my waypoints)],
(my options)
}]}
}).on('routesfound', function(e){
console.log(e);}
The console.log(e) show all the coordinates we want to work on. And there is a yt video explaining that : https://www.youtube.com/watch?v=6mAdRdwZihc
For those who have the same problem
I'm building an app with many different datasets. Locations, customers, ratings etc...
Throughout the app there are popups and dynamically filled modules, dropdowns etc... At the moment my method is to attach "data-id" as an attribute to any buttons that create dynamic content then run ajax functions using the attribute to get content for the popup.
I'm assuming this is the correct thing to do for large modules that require a lot of dynamic data, but take the below example.
I have a list of locations, when the user clicks (add link) I'd like the popup module to have the title 'Adding link to [location name]'. Would I really need to create an ajax function simply to fill in the name of the location from the database? I could get it from the DOM but that seems silly because most of the popups require data that isn't in the dom.
Basically, my question is; What is the easiest way to get basic data from the database in javascript?
Here's an example of what I have for a whole bunch of buttons with various modules and titles:
$('body').on('click','.add_board_to_loc',function(){
var id = $(this).attr('data-id');
let getLocation = function(id){
$.ajax({
type: 'POST',
url: 'includes/ajax.php',
data: {
action: 'getLocation',
loc_id: id
},
success: function(data){
$('#add_link_modal_title').text(data['location_name']);
}
});
}
$('#addBoardModal').modal('show');
});
I would split this code into several layers.
One layer can be a transport layer. On transport layer you make ajax request and process errors.
The next layer can be a general layer, here you pass params as table, where statmets and so on. Anyone will be able to access this data through api so be carful with permissions.
And the last layer can be Buisness layer where you request things like: get Location.
I'm struggling with adding a click event to points on my mapbox map. I'm having to add the source from a backend sql query into a hbs template. I've tried just adding business1 as the source without the for loop but i get an invalid geojson object warning. If i add just 'locations' as the id obviously it gives me a warning that the id already exists on the map.
So how i can add an onclick call for dynamics id's?
How i load the points
business1 = {{{businesses}}}
for(i=0;i<business1.length;i++){
// Add the data to your map as a lyer
map.addLayer({
id: 'locations'+[i],
type: 'symbol',
minzoom: zoomThreshold,
// Add a GeoJSON source containing place coordinates and information.
source: {
type: 'geojson',
data: business1[i]
},
layout: {
'icon-image': 'circle-stroked-15',
'icon-allow-overlap': true,
}
});
}
How the map click is called-with the added [i] just to show what i'm thinking
map.on('click', function(e) {
var features = map.queryRenderedFeatures(e.point, {
layers: ['locations'+[i]] // replace this with the name of the layer
});
if (!features.length) {
return;
}
What else i've tried-but always returns the same location regardless of what is clicked
for(i=0; i<business1.length;i++){
var features = []
var feature = [i]
feature.dataPosition = i;
var clickedNameClicked = names[this.dataPosition]
console.log(clickedNameClicked)
features.push(business1[i]);
}
I definitely don't recommend adding a new source / layer for each business. That will not be performant if you have a bunch of layers, and I think it's adding too much complexity to your on click logic.
I've tried just adding business1 as the source without the for loop but i get an invalid geojson object warning.
This is a strong indication that there's something awry with your business data that you should address before adding it to your map and worrying about click events. I would recommend using a tool like http://geojsonlint.com/ to see what is going on there.
Once you have valid geojson, it will be much easier to add click events to your icons. https://docs.mapbox.com/mapbox-gl-js/example/queryrenderedfeatures-around-point/
⚠️ Disclaimer: I currently work at Mapbox ⚠️
I'm getting a set of points along my route but in the paths where the car is on a highway, the segments are distant. I'd like to get a finer granulation of the routing. Is it possible?
$.ajax({
url: 'https://route.cit.api.here.com/routing/7.2/calculateroute.json',
type: 'GET', dataType: 'jsonp', jsonp: 'jsoncallback',
data: {
waypoint0: '59.159486,17.645687',
waypoint1: "59.397635,17.891626",
mode: 'fastest;car;traffic:enabled',
app_id: 'VXZP5fwHfh2WQIWnp0Zx',
app_code: 'NgKq-kVEUMKxxNpBKP_hBg',
departure: 'now'
},
success: function (data) {
moves = data.response.route[0].leg[0].maneuver;
timeAvailable = 45;
trackPoints = moves.map(function (d) { return {
lat: d.position.latitude,
lng: d.position.longitude,
time = d.travelTime }; });
for (var i = 0; i < trackPoints.length; i++) {
smackUpArea(map, trackPoints[i], timeAvailable);
timeAvailable -= trackPoints[i].time;
};
}
})
Optimally, I'd like t get a point every x kilometer or every y minutes driven. Is that possible at all?
To get more fine-grained routing information, you can request the links that the route is composed of. To do so, add the legattributes query parameter with value links or li. This will add a link array to the response for each leg object in each route. Furthermore, you can decide what information you want to see for each link, using the linkattributes query parameter. You could include things like length and shape of the link, as well as the remaining time or distance on the route at the moment a user reaches this link along the route. There's many other possibilities, which you can find here (look for RouteLinkAttributeType).
So in your code, this might look something like:
data: {
waypoint0: '59.159486,17.645687',
waypoint1: "59.397635,17.891626",
mode: 'fastest;car;traffic:enabled',
app_id: 'VXZP5fwHfh2WQIWnp0Zx',
app_code: 'NgKq-kVEUMKxxNpBKP_hBg',
departure: 'now',
legattributes: 'li',
linkattributes: 'le,rt'
},
And an actual link returned in the response would look something like:
{
"linkId":"-733185668",
"shape":["52.5158286,13.3774424","52.5158286,13.3774424"],
"length":0,
"remainTime":249,
"speedLimit":13.8888893,
"_type":"PrivateTransportLinkType"
}
I think there is one possible solution, but this would not be optimal.
I would add shape in the route attributes as a parameter of the request. And from the response, iterate through the every two pairs of lat/long to calculate the route of them. This would break down the segment into smaller pieces. It is still not optimal like what you asked in the question though. Using time-based or distance-based isoline with start as center then get the intersection seems painful to me. Hopefully someone has a better solution to this.
I'm trying to reload points on a map based on when someone clicks a button.
I have a couple json objects saved in memory, "data" and "data2". The following code takes the "data2" JSON file and sets it equal to the "data" JSON file and then triggers a map reload event.
dataholder = data
function myFunction() {
data = dataholder
window.data = data2;
google.maps.event.trigger(map, 'resize');
}
Currently, the map won't reload with the new set of data. However, I am not getting any error messages.
There's no map reload event. The resize event, when it comes from a window resize, will at most recalculate the map bounds and reproject the existing features (markers, polylines, polygons). For this case in particular, I don't think that manually triggering the resize event will have any effect.
In second place, you say you have two json files, but your code suggest you instead have two json objects already in memory (meaning you don't need to perform aditional requests to retrieve the value of data2). The rest of the answer will assume that.
If your original collection of markers came from "data", which is a collection of LatLng pairs, and you want to replace the markers for the contents of "data2" the process would be:
1.- Push the markers into an object where you can find them later on
var markers=[];
for(onemarker in data) {
var newmarker=new google.maps.Marker({map: map, position: new google.maps.LatLng({onemarker.lat, onemarker.lng}) });
markers.push(newmarker);
}
2.- When you want to replace the markers, first purge the markers array
while(markers.length) {
var oldmarker=markers.pop();
oldmarker.setMap(null);
};
3.- Fill the markers array with the data from the data2 object
for(onemarker in data2) {
var newmarker=new google.maps.Marker({map: map, position: new google.maps.LatLng({onemarker.lat, onemarker.lng}) });
markers.push(newmarker);
}
For this kind of markers, as for the regular features, there's no instantaneous binding between the object and the underlying data. This is slightly different for the new google.maps.Data() layer for which you can skip the iteration and just feed it a geoJSON array. You still need to have an object to store the current markers, or else you won't have a way to access them when you want to remove them.