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

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)
})

Related

Changing instance of Feature on click

Im trying to find a way to change the instance of a Leaflet geoJson Feature after it is added to the map.
This is what I want to achieve:
Importing data with L.GeoJson and I am using pointToLayer to change the marker to L.CircleMarker
Now I want
layer.on('click', function (e) {
e.target //Do something here to change it from L.CircleMarker to L.Marker
});
Any idea how to achieve this?
var group = L.geoJSON(); // Your geojson group on importing
layer.on('click', function (e) {
var circlemarker = e.target //Do something here to change it from L.CircleMarker to L.Marker
var marker = L.marker(circlemarker.getLatLng()).addTo(group);
marker.feature = circlemarker.feature
circlemarker.removeFrom(group)
// Then add the same events to the layer as in pointToLayer
});

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 draw loses shapes after drawing

I'm using leaflet to show a map and the leaflet-draw plugin to draw shapes on this map.
I have the code below (see plunker) which allows to draw shapes. But as soon the shape is finished, it disapears.
What is missing to make the shapes visible on the map after drawing?
var mymap = L.map('mapid').setView([47.2090048, 7.7746663], 15);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoiZXJuc3RwIiwiYSI6ImNpcGdtMTUzOTAwMGV2Ymt3Z2JlYnMyejgifQ.gHxSIfBUM0-UiuWurWoEvQ', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.streets'
}).addTo(mymap);
var marker = L.marker([47.2090048, 7.7747663]).addTo(mymap);
// Initialise the FeatureGroup to store editable layers
var drawnItems = new L.FeatureGroup();
mymap.addLayer(drawnItems);
// Initialise the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems
}
});
mymap.addControl(drawControl);
You've successfully drawn the shapes, but what's missing here is you haven't shown the drawn shape on top of your map layer, despite of what you're trying to achieve is to display it.
What you've got to do is just to add the drawn layer on top of your map.
E.g.
mymap.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
// Do marker specific actions
}
// Do whatever else you need to. (save to db, add to map etc)
mymap.addLayer(layer);
});
You can add this code to the end of your js. This is taken from the docs
You need to listen for the draw:created event and add the layer to the L.FeatureGroup in the event listener:
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
// Do marker specific actions
}
// Do whatever else you need to. (save to db, add to map etc)
drawnItems.addLayer(layer);
});

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

Adding properties to a leaflet layer that will become geojson options

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.