leaftletjs-adding points dynamically and draw line string - leaflet

I am trying to draw the path of a flight using leafletjs and geojson. I'll be getting the geometry from a stream.
this is what I have done so far:
let index = 0;
let geoJsonLayer;
let intervalFn = setInterval(function () {
let point = trackData.features[index++];
if(point) {
let coords = point.geometry.coordinates;
coords.pop();
coords.reverse();
geoFeature.geometry.coordinates.push(coords);
if(map.hasLayer(geoJsonLayer)) map.removeLayer(geoJsonLayer);
geoJsonLayer = L.geoJson(geoFeature, {
onEachFeature: (feature, layer) => {
const content = feature.properties.title;
layer.bindPopup(content);
}
});
geoJsonLayer.addTo(map);
// console.log(coords);
} else {
clearInterval(intervalFn);
}
}, 100);
setInterval is to simulate the part whereby I get the geometry from a stream.
now when a user clicks on the path I need to show some properties of the path, and I am trying to use the onEachFeature for that, but its not working correctly.
I suspect its because I am removing the layers (I did this to improve the performance)
Is there any other better ways to do what I am trying to achieve ?

You should probably try addLatLng()
Adds a given point to the polyline.
Your geoFeature sounds to be a single Feature, so your geoJsonLayer will contain a single layer (polyline):
let myPolyline;
geoJsonLayer.eachLayer(function (layer) {
myPolyline = layer; // Will be done only once actually.
});
// When you receive a new point…
myPolyline.addLatLng([lat, lng]);
With this you should not have to remove your layers every time.
The popup should therefore stay open, if it is shown.
Demo: https://jsfiddle.net/3v7hd2vx/265/ (click on the button to add new points)

Related

How to update geojson markers periodically

What I am trying to do is to use Leaflet with OSM map,
and load data from PHP in GeoJSON format + update periodically.
I can manage to display a map, load data, but do not know how to update points instead of still adding a new ones.
function update_position() {
$.getJSON('link_to_php', function(data) {
//get data into object
var geojsonFeature = JSON.parse(data);
// how to remove here old markers???
//add new layer
var myLayer = L.geoJSON().addTo(mymap);
//add markers to layet
myLayer.addData(geojsonFeature);
setTimeout(update_position, 1000);
});
}
update_position();
have tried mymap.removeLayer("myLayer"); but this seems to now work inside of function. Please help
L.geoJSON extends from LayerGroup which provide a function named clearLayers(docs), so you call that to clear markers from the layer.
Also, it is recommended that you put the layer variable outside the function:
var geoJSONLayer = L.geoJSON().addTo(mymap);
function update_position() {
$.getJSON('link_to_php', function(data) {
//get data into object
var geojsonFeature = JSON.parse(data);
geoJSONLayer.clearLayers();
//add markers to layet
geoJSONLayer.addData(geojsonFeature);
setTimeout(update_position, 1000);
});
}
update_position();

How to change the color of results from leaflet-knn on the map

I have displayed the the result markers for the leaflet-knn on the map with following code:
const myloc = new L.LatLng(13.7433242, 100.5421583);
var gjLayer = L.geoJson(testCities, {
onEachFeature: function(feature, layer) {
content = "<b>Name:</b> " + feature.properties.name;
layer.bindPopup(content);
}
});
var longitude = myloc.lng,
latitude = myloc.lat;
var res = leafletKnn(gjLayer).nearest(
[longitude, latitude], 5, distance);
for (i = 0; i < res.length; i++) {
map.addLayer(res[i].layer);
}
Now I want to change the color of this marker that is added or I want to change the icon.
Can anybody tell me how can I do?
Leaflet-knn is agnostic when it comes to the representation of the results - it relies on the existing L.Layers: it takes a L.GeoJSON as an input and then iterates through all its members in order to fetch all their coordinates (in the case of polylines and polygons) and then store a reference to the L.Layer for each of its coordinates.
The results of a leaflet-knn search include the original L.Layer from the L.GeoJSON that was passed at instantiation time.
Either symbolize your GeoJSON afterwards, as explained in the Leaflet tutorials, or create new markers/symbols for the results after each query.
Right now your code is relying on the default symbolization of GeoJSON data (instantiate a L.Marker with a L.Icon.Default for points). I suggest the approach of displaying your L.GeoJSON in the map to ensure that it looks like you want it to (even if it's a partial set of the data), then implementing the leaflet-knn search.

Bing Maps directions with clustering

I am able to draw the Map with maneuverPoints.
Below is the screen shot for map
Below is the code for the routing.
var maneuverPoints = this.model.get("maneuverPoints");
if (maneuverPoints) {
var routePoints = [];
_.each(maneuverPoints, function (point) {
routePoints.push(new MsMaps.Location(point.latitude, point.longitude));
});
var routeOptions = {
strokeColor: new MsMaps.Color(1, 65, 255, 35),
strokeThickness: 3
};
var routeShape = new MsMaps.Polyline(routePoints, routeOptions);
map.entities.push(routeShape);
}
Now I am trying to implement clustering and I am able to do it as below:
The pink pushpins are the clusters.
Code for clustering is as below:
Microsoft.Maps.loadModule("Microsoft.Maps.Clustering", function () {
var clusterLayer = new Microsoft.Maps.ClusterLayer(pushpins);
map.layers.insert(clusterLayer);
clusterLayer.setPushpins(pushpins);
map.setView(viewOptions);
var maneuverPoints = this.model.get("maneuverPoints");
if (maneuverPoints) {
var routePoints = [];
_.each(maneuverPoints, function (point) {
routePoints.push(new MsMaps.Location(point.latitude, point.longitude));
});
var routeOptions = {
strokeColor: new MsMaps.Color(1, 65, 255, 35),
strokeThickness: 3
};
var routeShape = new MsMaps.Polyline(routePoints, routeOptions);
map.entities.push(routeShape);
}
I am not able to do clustering and routing at same time. Is it possible to do both at same time?
Your code isn't doing routing by the looks of things, it is simply taking route line points and rendering them as a polyline. I don't see the directions module being used in your code. If you are using that directions module, why don't you simply use the built in rendering? You can customize how it looks. If you continue using a polyline as you are, consider adding it to a layer, it will make it easier to manage later.
That said, the code you provided is simply clustering and drawing a polyline. This works fine when I test this scenario.
Any reason why you are calling setPushpins in the cluster layer? You already passed the pushpins in when creating the layer, no need to pass them in again.

Getting the bounds of loaded tile of leaflet

Using leaflet is there any way I can get the bounds (NorthEast, SouthWest) of a loaded tile? I want to request the server to load the markers only for a particular tile which is loaded, so that when user is panning/dragging the map he can easily see the new markers on new area.
What you really want to do is a subclass of L.GridLayer. This will allow fine control over loaded/unloaded tiles, and is the best way to use the private L.GridLayer._tileCoordsToBounds() method.
With some basic handling of loaded markers, it should look like:
L.GridLayer.MarkerLoader = L.GridLayer.extend({
onAdd: function(map){
// Add a LayerGroup to the map, to hold the markers
this._markerGroup = L.layerGroup().addTo(map);
L.GridLayer.prototype.onAdd.call(this, map);
// Create a tilekey index of markers
this._markerIndex = {};
},
onRemove: function(map){
this._markergroup.removeFrom(map);
L.GridLayer.prototype.onRemove.call(this, map);
};
createTile: function(coords, done) {
var tileBounds = this._tileCoordsToBounds(coords);
var tileKey = this._tileCoordsToKey(coords);
var url = ...; // Compute right url using tileBounds & coords.z
fetch(url).then(function(res){
if (!key in this._markerIndex) { this._markerIndex[key] = []; }
// unpack marker data from result, instantiate markers
// Loop as appropiate
this._markerGroup.addLayer(marker);
this._markerIndex[key] = marker;
done(); // Signal that the tile has been loaded successfully
});
},
_removeTile: function (key) {
for (var i in this._markerIndex[key]) {
this._markerGroup.remove(this._markerIndex[key][i]);
}
L.GridLayer.prototype._removeTile.call(this, key);
}
});
Please note that zooming might be a source of bugs and graphical glitches (markers being removed because a tile unloads, before the markers at the new zoom level are loaded). Beware of that.

Leaflet: Removing markers from map

I load some lat / lon info, then use it to build a polyline.
I then want to add a marker at each of the polyline vertices that will show when the polyline is clicked.
The vertices should disappear if a different (or the same) polyline is clicked.
The code below creates the polyline and the vertex markers.
But the vertex markers do not ever disappear.
I've tried to do this several ways with the same result. I've tried storing the vertex markers in an array and adding them directly to the map, then map.removeLayer'ing them. That doesn't work either. Nor does it work if I use an L.featureGroup instead of a layerGroup.
Clearly I've missed the point somewhere as to how markers can be removed. Could someone point me at the error in my methodology?
// trackMarkersVisible is a global L.layerGroup
// success is a callback from an ajax that fetches trackData, an array f lat/lon pairs
success: function (trackData) {
// build an array of latLng's
points = buildTrackPointSet(trackData, marker.deviceID);
var newTrack = L.polyline(
points, {
color: colors[colorIndex],
weight: 6,
clickable: true
}
);
$(newTrack).on("click", function () {
trackMarkersVisible.clearLayers();
$.each(points, function(idx, val) {
var tm = new L.Marker(val);
trackMarkersVisible.addLayer(tm);
});
map.addLayer(trackMarkersVisible);
});
}
Without a JSFiddle or Plunker it's hard to say because i'm not sure what behaviour your getting but using the clearLayers() method of L.LayerGroup should remove all layers from that group. I would check in the onclick handler if the group already has layers: group.getLayers().length === 0 If the group is empty, add the markers, if the group has layers use clearLayers. Example in code:
polyline.on('click', function (e) {
if (group.getLayers().length === 0) {
e.target._latlngs.forEach(function (latlng) {
group.addLayer(L.marker(latlng));
});
} else {
group.clearLayers();
}
});
This works for me, see the example on Plunker: http://plnkr.co/edit/7IPHrO?p=preview
FYI: an instance of L.Polyline is always clickable by default so you can leave out the clickable: true