I'm displaying a GeoJSON layer using leaflet, with the pointToLayer function. Everything works ok so far.
But I would like to display my points in a certain order, based on a property of the GeoJSON. This is important because the radiuses of my points varies with this property, and I need to display the smaller circles on top. I hope I make myself clear.
I've tried many things, but here's what I think is my best try :
var pointLayer = L.geoJson(centroids, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, {
fillColor: "#76C551",
color: "#000",
weight: 1,
fillOpacity: 1
});
},
onEachFeature: function (feature, layer) {
var radius = calcPropRadius(feature.properties.nb);
layer.setRadius(radius);
feature.zIndexOffset = 1/feature.properties.nb*1000;
layer.bindPopup(feature.properties.name + " : " + String(feature.zIndexOffset));
}
});
You can notice that the zIndexOffset of features can be read in the popups, and they look ok. But the displaying order of the circles doesn't reflect the zIndexOffset.
I've tried using the setZIndexOffset method, but as I understand it it works only with markers.
Does anyone know how to do this ? Thanks a lot for any insight !
Whereas ghybs answer works perfectly for leaflet 0.7, switching to leaflet 1.0 allows the use of panes which makes for an easier solution :
var pointLayer = L.geoJson(centroids, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, {
fillColor: "#76C551",
color: "#000",
weight: 1,
fillOpacity: 1
});
},
onEachFeature: function (feature, layer) {
var radius = calcPropRadius(feature.properties.nb);
layer.setRadius(radius);
layer.setStyle({pane: 'pane'+ feature.properties.nb});
var currentPane = map.createPane('pane' + feature.properties.nb);
currentPane.style.zIndex = Math.round(1/feature.properties.nb*10000);
layer.bindPopup(feature.properties.name + " : " + String(feature.zIndexOffset));
}
});
Hope it can be of use to someone else !
As you figured out, the zIndexOffset option is only for L.marker's.
L.circleMarker's go into the overlayPane and you can re-order them one to each other using .bringToFront() and .bringToBack() methods.
Related
I can't seem to get CircleMarkers to show their associated popups in Leaflet. Here's what I am doing:
var markerGroup;
fetch("<FILE_NAME_REMOVED>").then(function(response){
return response.text();
}).then(function(text){
var lines = text.split("\n");
var markerArray = [];
for (var i=1; i<lines.length; i++) {
var parts = lines[i].split(",");
if (typeof parts[2] !='undefined') {
marker = new L.CircleMarker([parts[3],parts[2]], {
radius: 4,
color: 'red',
opacity: 0.95,
weight: 1.2,
dashArray: "2,3",
fillOpacity: 0.2
}).bindPopup("I am at " + parts[0] + "," + parts[1]);
markerArray.push(marker);
};
}
markerGroup = L.featureGroup(markerArray).addTo(map);
map.fitBounds(markerGroup.getBounds());
}).catch(function(err){
console.log(err);
});
The popups are just not showing up - in fact when I click on the circles the map just zooms in. If I replace L.CircleMarker with just L.Marker though it works fine, but I actually need circles.
I even tried adding an on click function to the markers, still nothing.
Could someone please help? I am using leaflet 1.3.4.
EDIT:
I didn't mention (because I did't think it mattered) that the markers are added last to the map but the map has a geoJson layer as well. I've noticed (by accident) that the popups do show up just fine over the area of the map not covered by the geoJson layer. This is strange to me because the geojson layer is set to back from the beginning:
var datalayer;
$.getJSON("<FILE_NAME_REMOVED>",function(data){
datalayer = L.geoJson(data ,{
onEachFeature: function(feature, featureLayer) {
featureLayer.setStyle({fillColor: 'white'});
featureLayer.setStyle({weight:1});
featureLayer.setStyle({fillOpacity:0.1});
featureLayer.bringToBack();
}
}).addTo(map);
map.fitBounds(datalayer.getBounds());
});
I was working on an application in which you can show points on a map. To improve the application, I added the functionality the show multipolygons as well.
I've created a dropdowmenu where you can select a dataset. One is a dataset containing stores (points), and the other contains precincts (multipolygons). Everything works fine and I can show either points or polygons on the map.
Because I build the application to only show points first, I've only styled the points (see code below).
var myStyle = {
"color": "#ff7800",
"weight": 5,
"opacity": 0.65
};
window["mapDataLayer"] = L.geoJson(geojson, {
pointToLayer: function (feature, latlng) {
var markerStyle = {
fillColor: getColor(feature.properties.Fastfoodketen),
color: "#696969",
fillOpacity: 0.6,
opacity: 0.9,
weight: 1,
radius: 8
};
return L.circleMarker(latlng, markerStyle);
},
onEachFeature: function (feature, layer){
layer.on({
click: function showResultsInDiv() {
var d = document.getElementById('tab4');
d.innerHTML = "";
for (prop in feature.properties){
d.innerHTML += prop+": "+feature.properties[prop]+"<br>";
}
$('.nav-tabs a[href="#tab4"]').tab('show');
}
}); },
style: myStyle
}).addTo(map);
Now I want to style the polygons. How can I alter the code above to include polygons as well?
I thought it would be a good way was to include an if/else loop to check if the geometry was a point or a multipolygon and then direct to the appropriate styling. However, I don't know how to check if a geometry is a point/polygon.
This is covered by the Leaflet documentation on GeoJSON options (emphasis mine):
pointToLayer: A Function defining how GeoJSON points spawn Leaflet layers.[...]
style: A Function defining the Path options for styling GeoJSON lines and polygons, [...]
You can see examples of this in the Leaflet tutorials for GeoJSON
I'm using leaflet to build a map of France, with the regions highlighted, and on-click zoom.
I used this tutorial first: http://leafletjs.com/examples/choropleth.html
First, I've had the geojson in the script.js, but in my case i needed regions in separated geojson files.
So i'm now calling them in the script.js with leaflet-ajax like this :
var BordeauxLayer = new L.GeoJSON.AJAX("src/js/DI_Bordeaux.geojson").addTo(map);
The regions is displayed on the map, but now all the function to zoom-in, highlight etc... that I took on the tutorial don't work anymore.
L.geoJson(BordeauxLayer,{onEachFeature: onEachFeature}).addTo(map);
// HIGHLIGHT FEATURE = MOUSEOVER
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
}
// HIGHLIGHT FEATURE = MOUSEOVER
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
};
// HIGHLIGHT FEATURE = MOUSE LEFT
function resetHighlight(e) {
geojson.resetStyle(e.target);
};
// ZOOM TO THE REGION
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
And now the console says " Uncaught Error: Invalid GeoJSON object. " on the line 8 of leaflet.js.
The problem seems to be on this line :
L.geoJson(BordeauxLayer,{onEachFeature: onEachFeature}).addTo(map);
And I don't get why :(
Edit : Here is my geojson : https://api.myjson.com/bins/3s1ad
Thank's in advance.
Your call to onEachFeature has to be in your AJAX call
var BordeauxLayer = new L.GeoJSON.AJAX("src/js/DI_Bordeaux.geojson", {onEachFeature: onEachFeature}).addTo(map);
You also have to get rid of
L.geoJson(BordeauxLayer,{onEachFeature: onEachFeature}).addTo(map);
I'm looking to set a geojson feature's style via setting its className. This works perfectly fine if placed directly on the feature like so:
L.geoJson(geojson, {
onEachFeature: function (feature, layer) {
layer.setStyle({className: 'grid-cell'});
}
}).addTo(map);
with the style defined in a .css file
path.grid-cell{
stroke-opacity: 1;
stroke: #444;
fill: #aaa;
}
However, it does not work if added within a feature's event callback:
L.geoJson(geojson, {
onEachFeature: function (feature, layer) {
layer.on('click', function(e){
this.setStyle({className: 'grid-cell'});
this.bringToFront();
});
}
}).addTo(map);
What's surprising is that setStyle({<style_options>}); work in either case for every other L.path option besides className, e.g. color, fillOpacity, weight, etc.
E.g.
L.geoJson(geojson, {
onEachFeature: function (feature, layer) {
// this works
layer.setStyle({color: '#faa', fillOpacity: 0.4, weight: 1});
// this works too
layer.setStyle({className: 'grid-cell'});
layer.on('click', function(e){
// and this works
layer.setStyle({color: '#afa', fillOpacity: 0.4, weight: 2});
// BUT THIS DOES NOT WORK
this.setStyle({className: 'grid-cell'});
this.bringToFront();
});
}
}).addTo(map);
Any idea what's up here? Here's a plunker illustrating the issue.
For a discussion of this issue, look here: https://github.com/Leaflet/Leaflet/issues/2662. One of the comments:
I don't think setStyle should actually change the className. The class is not really a style property, and the logic necessary to handle leaflet- classes seems like a hack. I think a setClassName() or add/removeClass API would be more appropriate.
I have a leaflet map which has lots of markers and what I would like is to open a image next to the map which is linked to certain marker on marker click. All I know that I need javascript/jquery and ajax to make this work.
Here is an example what it could look like: http://www.washingtonpost.com/wp-srv/special/local/14th-street-businesses/
Any hints/tips/tutorials appreciated.
Thanks in advance!
Here is a solution to your problem: http://franceimage.github.io/leaflet/10/
var selectedMarker = false;
var geojsonMarkerOptions = {
radius: 8,
fillColor: "#ff7800",
color: "#000",
weight: 1,
opacity: 1,
fillOpacity: 0.8
};
L.geoJson(fi_markers, {
pointToLayer: function (feature, latlng) {
var marker = L.circleMarker(latlng, geojsonMarkerOptions);
marker.on('click', function (e) {
var feature = e.target.feature;
var content = '<h3>' + feature.properties.popupContent + '</h3>' + feature.properties.thumbnail + '';
document.getElementById("events").innerHTML = content;
if(selectedMarker != false) {
selectedMarker.setStyle({ fillColor: "#ff7800"});
}
marker.setStyle({ fillColor: "#000000"});
selectedMarker = marker;
});
return marker;
}
}).addTo(map);
This a way you can do it (there are plenty others)
In this example:
There are no ajax calls (and no jquery either). Data is loaded from a geoJson structure (look at http://franceimage.github.io/leaflet/10/data.geojson)
The html content of the popup is created using the properties of the geojson feature
I have used CircleMarker so that changing the color is a piece of cake
I hope this will help