Add Layer Groups and Markers in a loop ( from json) - leaflet

I just started working with Leaflet. I want to create a map for a game, so this is a map created with L.CRS.Simple.
I have been able to set the map image, and add marker manually.
Now, I want to create markers and layers groups dynamicly from a json file that I generate in PHP from a sqlite database.
My json is this one for now : https://grounded.dubebenjamin.com/api/markers.json
My json is a list of type(layergroup) inside which I have put another object containing all the markers for the type(layergroup) :
Structure :
{
"landmarks": {
"id": 1,
"slug": "landmark",
"type": "Landmarks",
"markers": [
{"id": 1, "title": "Title of marker 1 of layergroup1"},
{"id": 2, "title": "Title of marker 2 of layergroup1"}
]
},
"science": {
"id": 2,
"slug": "science",
"type": "Science Points",
"markers": [
{"id": 1, "title": "Title of marker 1 of layergroup2"}
]
}
}
= Where landmarks and science are layergroup.
From this json, my plan was to have a first loop, where for each type I want to create a layer group, then create the markers for this layer group and assign the markers to the layer groups.
Manually, I understand the usage of L.marker and L.layerGroup, but where I am stuck, is how to do that in a loop, and defined the layoutgroup name from the json data.
From now, I have just been able to create the marker, but not the layer group. You can see my progress here: https://grounded.dubebenjamin.com/
If you need more precision, just ask me.

Use this code:
var layergroups = {};
fetch('https://grounded.dubebenjamin.com/api/markers.json').then(response => response.json())
.then((data)=>{
layergroups = {};
for(type in data){
var lg = L.layerGroup().addTo(map)
layergroups[type] = lg;
if(data[type].markers){
var markers = data[type].markers;
markers.forEach((marker)=>{
L.marker([marker.x,marker.y]).bindPopup(marker.desc).addTo(lg);
})
}
}
})
First fetch the data from the server, then loop through the layergroups and add them to the map and then to the Object/Array.
Then you create the markers and add them to the layergroup.
You can get the layergroups over the Object layergroups but keep in mind that the request is async.

Related

In Mapbox GL JS, can you pass coordinates to an external GeoJSON data source?

Can you pass coordinate values as variables when trying to retreive an external GeoJSON data source? Ideally I'd like to pass something like this, but it doesn't work for me.
map.addSource('geojsonpoints', {
type: "geojson",
data: 'http://myexample.com/pins?lat={lat}&lon={long}'
});
I am able to pass Z, X, Y coordinates if I use Map Vector Tiles (mvt) as a source. i.e. This works:
map.addSource('mapvectortiles', {
'type': 'vector',
'tiles': ['http://myexample.com/{z}/{x}/{y}'],
But I haven't figured out how to do it for a GeoJSON source. Anyone have any ideas if it is possible in n Mapbox GL JS?
FYI, I am able to generate the URL using the method below, but the problem is it doesn't refresh when I move the map, unlike vector tiles.
var lng = map.getCenter().lng
var lat = map.getCenter().lat
var url = 'http://myexample.com/pins?lat='+lat+'&lon='+lng
map.addSource('EPC', {
type: "geojson",
data: url
});
I use GeoJSON to draw Tiles on the map
this is a sample GeoJSON:
{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[4.342254780676343, 50.89533552689166],
[4.342254780676343, 50.89443721160754],
[4.340830581474948, 50.89443721160754],
[4.340830581474948, 50.89533552689166],
[4.342254780676343, 50.89533552689166]
]
]
},
"properties": {}
}
]
}
after all you have to add the source and add the layer
add Source:
const sourceJson: GeoJSONSourceRaw = {
type: 'geojson',
data: data as FeatureCollection
};
map.addSource(sourceId, sourceJson)
data is your json file
add Layer:
const layer: FillLayer = {
id: sourceId,
source: sourceId,
type: 'fill',
paint: {
'fill-color': color,
'fill-opacity': opacity
}
}
this.map.addLayer(layer);
There are two parts to your question:
Update the data source when the map is moved
Use the map's extent as part of the GeoJSON source's URL.
You have part 2 under control, so:
Update the data source when the map is moved
Use map.on('moveend', ...
Use map.getSource(...).setData(...)

How to use this JSON Data on my Leaflet Map

How can I use this type of json data in my leaflet map? I have lot of area datasets and there co-ordinates array is somewhat confusing. I want to know how can I use this data set to show polygons on my map.
{
"Locality": "Andrews Ganj",
"Loc_Id": 1006613,
"City": "New Delhi",
"City_Id": 10397,
"State": "Delhi",
"HH": 1713,
"T_Pop": 7418,
"T_mPop": 3842,
"T_fPop": 3576,
"CGT10L": 20.26,
"C5_10L": 31.23,
"C1o5_5L": 36.37,
"CLT1o5L": 12.14,
"Coordinates": "28.561508|77.220098$28.561776|77.220469$28.562004|77.220674$28.561748|77.221049$28.561635|77.221411$28.562657|77.221943$28.562881|77.221555$28.562955|77.221624$28.563224|77.221846$28.564101|77.222571$28.564359|77.222735$28.564582|77.222899$28.565257|77.22327$28.565302|77.223305$28.565317|77.223356$28.56528|77.22352$28.565568|77.223684$28.565617|77.223663$28.565647|77.223663$28.565681|77.223667$28.565886|77.223844$28.565997|77.22403$28.566084|77.224073$28.566611|77.22444$28.56707|77.224663$28.567374|77.224804$28.567752|77.224983$28.567935|77.22501$28.567964|77.225012$28.56778|77.22547$28.567577|77.225968$28.567507|77.226139$28.566662|77.228219$28.566539|77.228578$28.566479|77.228722$28.566147|77.229518$28.56609|77.229666$28.565992|77.229919$28.565964|77.229999$28.5659|77.230175$28.565791|77.230598$28.565746|77.230792$28.5657|77.231073$28.565646|77.2317$28.565643|77.231748$28.565602|77.232306$28.565532|77.233377$28.565492|77.23383$28.565472|77.23409$28.565177|77.233967$28.564747|77.23376$28.56397|77.233318$28.563079|77.232797$28.562897|77.232657$28.560578|77.231256$28.560877|77.231066$28.56154|77.230979$28.561895|77.231141$28.562254|77.230363$28.562874|77.228948$28.563081|77.228477$28.563377|77.227801$28.563269|77.227589$28.563478|77.227399$28.563565|77.227283$28.564525|77.224997$28.564815|77.224312$28.564827|77.224284$28.564441|77.224069$28.564275|77.223981$28.563897|77.223919$28.563211|77.223555$28.562788|77.223312$28.562583|77.223192$28.562223|77.222981$28.561837|77.222605$28.561175|77.22209$28.560751|77.22165$28.560386|77.221168$28.561018|77.22056$28.561508|77.220098"
},
We can split the Coordinates string into a usable array with String.split and then display it in a map:
//for the demo
var defaultCoords = [28.561508, 77.220098];
//set up our map
var map = L.map('map').setView(defaultCoords, 12);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{}).addTo(map);
var sampleData = {
"Locality": "Andrews Ganj",
"Loc_Id": 1006613,
"City": "New Delhi",
"City_Id": 10397,
"State": "Delhi",
"HH": 1713,
"T_Pop": 7418,
"T_mPop": 3842,
"T_fPop": 3576,
"CGT10L": 20.26,
"C5_10L": 31.23,
"C1o5_5L": 36.37,
"CLT1o5L": 12.14,
"Coordinates": "28.561508|77.220098$28.561776|77.220469$28.562004|77.220674$28.561748|77.221049$28.561635|77.221411$28.562657|77.221943$28.562881|77.221555$28.562955|77.221624$28.563224|77.221846$28.564101|77.222571$28.564359|77.222735$28.564582|77.222899$28.565257|77.22327$28.565302|77.223305$28.565317|77.223356$28.56528|77.22352$28.565568|77.223684$28.565617|77.223663$28.565647|77.223663$28.565681|77.223667$28.565886|77.223844$28.565997|77.22403$28.566084|77.224073$28.566611|77.22444$28.56707|77.224663$28.567374|77.224804$28.567752|77.224983$28.567935|77.22501$28.567964|77.225012$28.56778|77.22547$28.567577|77.225968$28.567507|77.226139$28.566662|77.228219$28.566539|77.228578$28.566479|77.228722$28.566147|77.229518$28.56609|77.229666$28.565992|77.229919$28.565964|77.229999$28.5659|77.230175$28.565791|77.230598$28.565746|77.230792$28.5657|77.231073$28.565646|77.2317$28.565643|77.231748$28.565602|77.232306$28.565532|77.233377$28.565492|77.23383$28.565472|77.23409$28.565177|77.233967$28.564747|77.23376$28.56397|77.233318$28.563079|77.232797$28.562897|77.232657$28.560578|77.231256$28.560877|77.231066$28.56154|77.230979$28.561895|77.231141$28.562254|77.230363$28.562874|77.228948$28.563081|77.228477$28.563377|77.227801$28.563269|77.227589$28.563478|77.227399$28.563565|77.227283$28.564525|77.224997$28.564815|77.224312$28.564827|77.224284$28.564441|77.224069$28.564275|77.223981$28.563897|77.223919$28.563211|77.223555$28.562788|77.223312$28.562583|77.223192$28.562223|77.222981$28.561837|77.222605$28.561175|77.22209$28.560751|77.22165$28.560386|77.221168$28.561018|77.22056$28.561508|77.220098"
};
//first take the coords string and split into an array by the $
var coords = sampleData.Coordinates.split('$')
//next, take that array of strings that looks like' 28.561508|77.220098' and split again by the |
coords = coords.map(function (pair) {
return pair.split('|');
});
//show it on a map.
var polygon = L.polygon(coords, { color: 'red' }).addTo(map);
// zoom the map to the polyline
map.fitBounds(polygon.getBounds());

Leaflet: Create layers from geojson "properties"?

I've new to mapping, and I've started creating my map following the documentations and tutorials on http://leafletjs.com. So far so good, I've manage to create a map, add a lot of geosjon data from geojson.io that dislay "popupContent" in a popup. And it works.
But I can't understand how create a few layers to sort all those markers. What I want is too use the "properties" to do it. I have properties named "status" with a values "done", "new" and "active".
Like so:
"type": "Feature",
"properties": {
"popupContent": "content",
"marker-color": "#FFFFFF",
"title": "title of project",
"status": "active
Is that possible? To create a 3 layers based on "status" properties?
If you need the html file to look at, say so and I can add it.
Thanks
You can use the filter option of L.geoJson to create separate layers based on the feature properties. Just specify a function that will return true for the features you want included in each layer:
var activeLayer = L.geoJson(yourGeoJson, {
filter: function(feature, layer) {
return (feature.properties.status === "active");
}
}).addTo(map);
var newLayer = L.geoJson(yourGeoJson, {
filter: function(feature, layer) {
return (feature.properties.status === "new");
}
}).addTo(map);
var doneLayer = L.geoJson(yourGeoJson, {
filter: function(feature, layer) {
return (feature.properties.status === "done");
}
}).addTo(map);

Difference between leaflet Marker and mapbox featureLayer

I understood that I can use the general Leaflet layer, and the more advanced map-box featureLayer, that provides useful functions as the filter.
However, I don't understand the difference between
marker = L.Marker (new L.LatLng(lat, lng),
{
icon: L.mapbox.marker.icon(
{'marker-color': 'fc4353'
'marker-size': 'large'
}),
title: name,
});
map.addLayer(marker);
and
var poijson = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [lng, lat]
},
"properties": {
"title": poi.name,
"marker-color": "#fc4353",
"marker-size": "large"
}
};
map.featureLayer.setGeoJSON(geojson);
Is it just the same?
[UPDATE]
Moreover, if I had many markers, should I add a new layer for each marker? It seems not a good thing for performance..
For instance, If I do:
var pois; //loaded with pois info
var geojson=[]; //will contain geojson data
for (p=0; p< pois.length; p++)
{
var poi = pois[p];
var poijson =
{
"type": "Feature",
"geometry":
{
"type": "Point",
"coordinates": [poi.lng, poi.lat]
}
};
geojson.push(poijson);
}
map.featureLayer.setGeoJSON(geojson);
Does it will create many layers for each poi, or just one layer with all the markers?
thank you
When you add a marker to a Leaflet map via map.addLayer(marker);, the marker is added to the 'leaflet-maker-pane'. The markers are plain images/icons.
You can use a geoJSON layer to draw GIS features: points, lines, polygons, etc.
See here: http://leafletjs.com/examples/geojson.html
Mapbox's featureLayers is just an extension to Leaflet's geoJSONLayer
To add multiple markers, call addMarker multiple times. Leaflet will create a new layer for each of the markers. Each marker will be added as an image element to the leaflet-marker-pane div:
http://bl.ocks.org/d3noob/9150014
Updated response:
If you add a GeoJSON layer with multiple features, Leaflet will create separate layer for each of the features. You can inspect the layers of the map by calling map._layers after adding the GeoJSON Layer.
marker.addTo(map) and map.addLayer(marker) are doing the same thing.
Here's the addTo function taken from the source
addTo: function (map) {
map.addLayer(this);
return this;
},

Missing info of feature when getting it from Leaflet's event.layer.toGeoJSON()

I'm using L.geoJson and adding layer to my map, then with items.on('click', function (event) {}) displaying info of selected object which is stored in event.layer (getting info with toGeoJSON()).
Problem is, when there are some of the items, everything seems to work, but now when there are >1000 polygons, some of the data when using on('click') does not contain my info of the feature inside event.layer.
What could be a problem?
ADDITIONAL INFO:
Our GeoJSON looks something like this, it has additional data like ID and various properties.
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": 1,
"geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
"properties": {"prop1": "value1"}
},
{
"type": "Feature",
"id": 2,
"geometry": {"type": "Point", "coordinates": [142.0, 15.5]},
"properties": {"prop1": "value2"}
}
]
}
I put everything on a map:
data = L.geoJson(data);
allItems.clearLayers().addLayer(data);
Features are displayed on a map.
Then I listen for clicks on the features on the map:
allItems.on('click', function (event) {
// On many of the features this is empty,
// on some data can be retrieved.
// On some that doesn't have ID, properties
// are empty too
console.log(event.layer.toGeoJSON().id);
});
GeoJSON has been checked and ID and properties ARE THERE.
Here's a little explanation about how to handle click events on L.GeoJSON layer and/or it's features. I've commented the code to explain what is going on and added an example on Plunker for you so you can test the concept.
Example on Plunker: http://plnkr.co/edit/TcyDGH?p=preview
Code:
var geoJsonLayer = L.geoJson(data, {
// Executes on each feature in the dataset
onEachFeature: function (featureData, featureLayer) {
// featureData contains the actual feature object
// featureLayer contains the indivual layer instance
featureLayer.on('click', function () {
// Fires on click of single feature
console.log('Clicked feature layer ID: ' + featureData.id);
});
}
}).on('click', function () {
// Fires on each feature in the layer
console.log('Clicked GeoJSON layer');
});
As for your code, i'm quite confused as to where the allItems comes from. A layerGroup or something like that? Trying to capture clicks on individual features in the GeoJSON layer on that object won't work, because it won't be able to differentiate between the features. Same goes for the handler on the GeoJSON layer, it will fire, but won't know which feature you clicked. The handler in the onEachFeature function will. But i'm assuming you understand by now if your understanding the code/example above.