Adding properties to a leaflet layer that will become geojson options - leaflet

Lets say I draw a shape on a mapbox map, and do this on the draw:crated event:
e.layer.properties = {};
e.layer.properties.myId = 'This is myId';
If I do a featureGroup.toGeoJSON() the geojson features has an empty properties object. Is there any way I configure a leaflet layer so that when it is transformed to geoJson, it will have certain properties set?

Actually, the trick is just to define the layer feature with its type (must be a "Feature") and properties (use the latter to record whatever information you need).
map.on('draw:created', function (event) {
var layer = event.layer,
feature = layer.feature = layer.feature || {}; // Initialize feature
feature.type = feature.type || "Feature"; // Initialize feature.type
var props = feature.properties = feature.properties || {}; // Initialize feature.properties
props.myId = 'This is myId';
drawnItems.addLayer(layer); // whatever you want to do with the created layer
});
See also Leaflet Draw not taking properties when converting FeatureGroup to GeoJson and update properties of geojson to use it with leaflet

You can either modify the leaflet source or write your own function to process the layers and set the properties that you are looking for.

Related

How to get the geojson of all features added by Leaflet-geoman

I'm using Leaflet-geoman to draw circles and polygons in a map.
How can I get the geojson of all features drawn in the map ?
To get all layers of the map you can use this:
var fg = L.featureGroup();
map.eachLayer((layer)=>{
if(layer instanceof L.Path || layer instanceof L.Marker){
fg.addLayer(layer);
}
});
console.log(fg.toGeoJSON());
If you want only the layers they are used from the plugin:
var fg = L.featureGroup();
map.eachLayer((layer)=>{
if((layer instanceof L.Path || layer instanceof L.Marker) && layer.pm){
fg.addLayer(layer);
}
});
console.log(fg.toGeoJSON());
I suggest to use a custom leaflet featureGroup which can be fed to geoman. Let's say you are drawing polygons
const yourCustomPolygonLayer = L.featureGroup().addTo(map);
map.pm.setGlobalOptions({
layerGroup: yourCustomPolygonLayer
});
Now you can iterate over yourCustomPolygonLayer easily.
yourCustomPolygonLayer.eachLayer(layer => {
console.info(layer._latlngs)
})

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();

Mapbox: Filtering out markers in a Leaflet Omnivore KML layer

I am exporting Google Directions routes as KML and displaying them on a Mapbox map by reading them with Omnivore and adding them to the map,
The Google KML stores each route as two Places (the start and end points) and one LineString (the route). In Mapbox I would like to show only the routes, that is to filter out the markers somehow. I'm displaying markers out of my own database and the Google markers clutter it up.
Here is my code. I change the styling of the LineStrings just to show that I can, but do not know what magic call(s) to make to not display the Points.
Thanks.
runLayer = omnivore.kml('data/xxxx.kml')
.on('ready', function() {
var llBnds = runLayer.getBounds();
map.fitBounds(llBnds);
this.eachLayer(function (layer) {
if (layer.feature.geometry.type == 'LineString') {
layer.setStyle({
color: '#4E3508',
weight: 4
});
}
if (layer.feature.geometry.type == 'Point') {
//
// Do something useful here to not display these items!!
//
}
});
})
.addTo(map);
Welcome to SO!
Many possible solutions:
Most straight forward from the code you provided, just use the removeLayer method on your runLayer Layer Group when you get a 'Point' feature.
Cleaner solution would be to filter out those features before they are even converted into Leaflet layers, through a custom GeoJSON Layer Group passed as 3rd argument of omnivore.kml, with a specified filter option:
var customLayer = L.geoJSON(null, {
filter: function(geoJsonFeature) {
// my custom filter function: do not display Point type features.
return geoJsonFeature.geometry.type !== 'Point';
}
}).addTo(map);
var runLayer = omnivore.kml('data/xxxx.kml', null, customLayer);
You can also use the style and/or onEachFeature options on customLayer to directly apply your desired style on your LineString.

Editing/Removing GeoJSON layers from a featureGroup in Mapbox using Leaflet

I'm using Mapbox with Leaflet for drawing, editing and removing polygons etc. Every time I create a new polygon, I convert them to a GeoJSON layer and then add it to the featureGroup that I created, because I want to associate each layer with an ID property that I can use later. This is what I have:
var featureGroup = L.featureGroup().addTo(map);
var drawControl = new L.Control.Draw({
edit: {
featureGroup: featureGroup
},
draw: {
polygon: {
allowIntersection: false
},
polyline: false,
rectangle: false,
circle: false,
marker: false
}
}).addTo(map);
map.on('draw:created', addPolygon);
map.on('draw:edited', editPolygon);
map.on('draw:deleted', deletePolygon);
function deletePolygon(e) {
featureGroup.removeLayer(e.layer);
}
function editPolygon(e) {
featureGroup.eachLayer(function (layer) {
layer.eachLayer(function (layer) {
addPolygon({ layer: layer });
});
});
}
function addPolygon(e) {
var geojsonstring = e.layer.toGeoJSON();
var geojson = L.geoJson(geojsonstring);
featureGroup.addLayer(geojson);
}
When I do this, creating polygons is not a problem. But when I try to edit or delete polygons, it doesn't work properly.
When I try to edit a polygon, it tells me "TypeError: i.Editing is undefined". It doesn't allow me to cancel editing as well.
When I try to delete a polygon, it is not displayed in the map anymore, but it is still not removed from the featureGroup.
What am I doing wrong here?
Edit: The way I'm currently doing this is the same way that ghybs has suggested. But the problem is, once all the edits are done, the polygons are saved to a database (I convert it to a WKT string to save in SQLServer). And when the page is loaded the next time, the polygons are loaded back from the database, and the user can edit or delete them and save it back to the database.
As it is right now, when the user makes the edit and saves them again, it only creates duplicate polygons. and I don't know of any way to connect the edited polygons to the ones from the database.
So I thought if I could convert them to GeoJSON and assign an ID property to each layer (something like ID=0 if it is a new layer, and the corresponding polygonID from the database if it is loaded from the database). So that when they are saved again, I can check this ID and based on that, I can either update the available polygon, or create a new polygon in the database.
Is there a better way of doing this?
Not sure exactly why in addPolygon you go through a GeoJSON object that you convert back into a Leaflet layer group through L.geoJson?
You could have directly added the created layer, as in Leaflet.draw "draw:created" example:
function addPolygon(e) {
var layer = e.layer;
var feature = layer.feature = layer.feature || {}; // Initialize layer.feature
// use the feature.id: http://geojson.org/geojson-spec.html#feature-objects
feature.id = 0; // you can change it with your DB id once created.
featureGroup.addLayer(layer);
// record into DB, assuming it returns a Promise / Deferred.
recordToDb(layer.toGeoJSON()).done(function (result) {
feature.id = result.id; // Update the layer id.
});
}
As for the reason for you error, it is due to the fact that you add a (GeoJSON) Layer Group to your featureGroup, which Leaflet.draw plugin does not know how to handle. You must add only "non group" layers.
See also: https://gis.stackexchange.com/questions/203540/how-to-edit-an-existing-layer-using-leaflet

Leaflet Draw not taking properties when converting FeatureGroup to GeoJson

I'm unable to convert my Layer properties into the properties of the GEOJson object using Leaflet(0.7.7)/Leaflet.Draw(latest). My workflow is:
1 Create Map: var map = L.map('#map', options);
2 Create a FeatureGroup: features= new L.FeatureGroup();
3 Add to the Leaflet Map: map.addLayer(features);
4 On the draw:created event, I'm capturing e.layer and adding a bunch of properties:
var layer = e.layer;
layer.properties = { Title: 'Hello' };
features.addLayer(layer);
geo_features = features.toGeoJSON();
However, my geo_features always have empty property attributes in each of the features and I can't figure it out!
iH8's initial answer was almost correct.
To specify properties that will appear in a vector layer's GeoJSON export (i.e. through its .toGeoJSON() method), you have to fill its feature.type and feature.properties members:
var myVectorLayer = L.rectangle(...) // whatever
var feature = myVectorLayer.feature = myVectorLayer.feature || {};
feature.type = "Feature";
feature.properties = feature.properties || {};
feature.properties["Foo"] = "Bar";
Now myVectorLayer.toGeoJSON() returns a valid GeoJSON feature object represented by:
{
"type": "Feature",
"properties": {
"Foo": "Bar"
// More properties that may be pre-filled.
},
"geometry": // The vector geometry
}
A (kind of ugly workaround) is using a L.GeoJSON layer and add the drawn layer's GeoJSON to it by using it's addData method. Afterwards grab the last layer in the L.GeoJSON layer's _layers object. At that point the layer has a valid GeoJSON feature property you can edit:
var geojson = new L.GeoJSON().addTo(map);
var drawControl = new L.Control.Draw({
edit: {
featureGroup: geojson
}
}).addTo(map);
map.on('draw:created', function (e) {
geojson.addData(e.layer.toGeoJSON());
var layers = geojson._layers,
keys = Object.keys(layers),
key = keys[keys.length - 1],
layer = layers[key];
layer.feature.properties = {
'Foo': 'Bar'
};
});
For your L.GeoJSON call include feature callback onEachFeature to options
L.GeoJSON(featureData,{onEachFeature:function(feature,layer){
//console.log(feature,layer);
// do something like
feature.setStyle( convertLayerOptionsFromFeatureProperties( feature.properties ) );
}} )