I am trying to style individual markers, or clusters of size 1, based on some feature property.
var markers = L.markerClusterGroup();
function onEachFeature(feature, layer) {
if (feature.properties.EncounterType && feature.properties.Year) {
layer.bindPopup(feature.properties.EncounterType + " in " +
feature.properties.Year);
}
}
function style(feature) {
switch (feature.properties.EncounterType) {
case 'Shooting':
return {
color: "ff0000"
};
case 'Sighting':
return {
color: "0000ff"
};
case 'Hunting':
return {
color: "ff0000"
};
}
}
var geoJsonLayer = L.geoJSON(storer, {
onEachFeature: onEachFeature
}, {
style: style
});
markers.addLayer(geoJsonLayer);
map.addLayer(markers);
The onEachFeature function successfully creates the popups. However, the style function does not change the color of the clusters of size 1. I've tried using the iconCreateFunction when initializing the markerclustergroup, however, that did not work either.
Your style option is separated in a 3rd argument of your call to L.geoJSON factory, whereas it should have been placed within the 2nd argument, alongside onEachFeature option.
var geoJsonLayer = L.geoJSON(storer, {
onEachFeature: onEachFeature,
style: style
});
But that is probably not the only reason for your issue.
style option will apply to vector shapes (polylines, polygons, etc.), i.e. to non-point data. It may also apply to Circle Markers, which can be used for Point type geometries, but you have to explicitly create them (typically through the pointToLayer option).
Those non-point data cannot be handled by Leaflet.markercluster.
Therefore if you see "clusters of size 1" (I guess you mean markers), they come from unstyled Point type geometries in your storer GeoJSON data.
This is a normal marker:
It is a PNG image that cannot be styled.
If you want to customize the appearance of your Point geometries, use custom icons, a plugin that provide such custom icons, or Circle Markers which you can modify the colour easily (including through the style option).
For example, if you were to choose that last option, you could do something like:
var geoJsonLayer = L.geoJSON(storer, {
pointToLayer: function (geoJsonPoint, latlng) {
return L.circleMarker(latlng);
},
onEachFeature: onEachFeature,
style: style
});
Related
// Create the map object with center, zoom level and default layer.
let map = L.map('mapid', {
center: [40.7, -94.5],
zoom: 3,
layers: [streets]
});
// Create a base layer that holds all three maps.
let baseMaps = {
"Streets": streets,
"Satellite": satelliteStreets,
"Night Navigation": nightNav
};
// 1. Add a 2nd layer group for the tectonic plate data.
let allEarthquakes = new L.LayerGroup();
let allTectonics = new L.LayerGroup();
let majorEQ = new L.LayerGroup();
// 2. Add a reference to the tectonic plates group to the overlays object.
let overlays = {
"Earthquakes": allEarthquakes,
"Tectonic Plates": allTectonics,
"Major Earthquakes": majorEQ
};
// Then we add a control to the map that will allow the user to change which
// layers are visible.
L.control.layers(baseMaps, overlays).addTo(map);
let tectonicData = "https://raw.githubusercontent.com/fraxen/tectonicplates/master/GeoJSON/PB2002_boundaries.json";
let tstyle = map.on('baselayerchange', function(feature) {
console.log('base layer has been changed');
return {
fillColor: tecStyle(L.overlays),
fillOpacity: 0.8,
weight: 0.5
};
});
function tecStyle(feature) {
if (feature === baseMaps["Streets"]) { return "purple";
}
if (feature === baseMaps["Satellite"]) {
return "red";
}
if (feature === baseMaps["Night Navigation"]) {
return "red";
}
};
// 3. Use d3.json to make a call to get our Tectonic Plate geoJSON data.
d3.json(tectonicData).then(function(data) {
// Create GeoJSON layer with the retrieved data.
L.geoJSON(data, {
style: tstyle,
onEachFeature: function(feature, layer){
layer.bindPopup("<h3><b> Plate Boundary Name: " + feature.properties.Name + "</h3></b>");
}
}).addTo(allTectonics);
allTectonics.addTo(map);
});
});
I want the tectonic fault line color to change colors depending on whether the user is on the 'Streets', 'Satellite', or 'Night Navigation' layers. For example, I want the fault line color to be 'purple' when on 'Streets', 'red' when on 'Satellite', and 'blue' when on 'Night Navigation' base layer maps. I was hoping I could get it to work using map.on and the event listener is working, because it comes up in my DevTools console, but the color of the fault line remains the default color of 'blue' no matter what layer I am on. What am I doing wrong here? or is there an easier way to do this?
update "style: tstyle" in step 3 to "style: tecStyle" and you should be good to go!
I have a map with a lot of markers and a complex popup content, generated by a function called popupcontent(), which takes a lot of time to compute when it is done for all markers on the map with the oneachfeature function.
Is there a way to trigger a function in a popup only when it is actually opened instead of generating all the popups in the beginning? This would speed up loading time a lot.
This is my code so far (I am using the markerclusterer extension):
var geojson1 = L.geoJson(bigJson,{
onEachFeature: function (feature, layer) {
layer.bindPopup(popupcontent(feature,layer));
}
})
.addLayer(tiles);
var markers = L.markerClusterGroup({
spiderfyOnMaxZoom: true,
showCoverageOnHover: true,
zoomToBoundsOnClick: true,
disableClusteringAtZoom: 10,
removeOutsideVisibleBounds:true
});
var geoJsonLayer = L.geoJson(bigJson, {
});
markers.addLayer(geojson1);
map.addLayer(markers);
map.fitBounds(markers.getBounds());
Demo: http://stefang.cepheus.uberspace.de/farmshops/
I think what you're looking for is something like so (if your layer is an interactive layer):
onEachFeature: function (feature, layer) {
layer.once("click", ()=>{
layer.bindPopup(popupcontent(feature,layer)).openPopup();
});
}
Use "once" instead of "on" so it only gets binded once when the layer is clicked.
I have a feature in a Leaflet map made up of many circle markers (L.circleMarker). The markers are symbolized to show whether a picture was taken at that location.
What I would like to do is bring all the markers that do have a photo at that location to the top of the layer, similar to how a marker can be raised with a mouse-over (but without mouse-over in this case).
Here is an illustration of the original version:
And this is what I would like them to be:
I've considered having different layers for photos vs. no photos, but due to some functions in the map, it's preferable that they are in a single layer.
Any ideas as to how this could be done with JavaScript and Leaflet?
In the style definition for the circle marker it's possible to specify the "map pane" to which the marker is rendered (http://leafletjs.com/reference-1.0.3.html#map-pane). It seems like this is the only way to specify the zIndex of circleMarkers (regular markers have a zindexOffset option).
My code looks like this:
var style = {
radius: 1.75,
fillColor: "darkred",
color: "darkred",
pane: 'overlayPane'
};
var picStyle = {
radius: 0.25,
fillColor: "blue",
color: "blue",
pane: 'shadowPane'
};
var site2 = new L.geoJSON(valuesSite2, {
onEachFeature: onEachFeature,
pointToLayer: function (feature, latlng) {
feature.properties.layer = "Site 2";
onEachFeature: onEachFeature;
if (<there is a picture>) {
return L.circleMarker(latlng, picStyle)
} else {
return L.circleMarker(latlng, style);
}
}
}).addTo(map);
The result looks like:
I have a leaflet map with multiple geoJSON layers:
var site1 = new L.geoJSON(site1_geojson, {
onEachFeature: onEachFeature,
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, style);
}
}).addTo(map);
I would like the onEachFeature function to return the name (e.g. "site1") of the layer clicked on. Something like:
var nameOfLayer;
function onEachFeature(feature, layer) {
layer.on('click', function(e) {
nameOfLayer = ????
});
}
I've tried assigning feature and layer to nameOfLayer, but from what I can gather those look like just the point clicked on, not the geoJSON layer itself.
Is this possible to do with leaflet and JavaScript?
If you want a constant string:
var site1 = L.geoJSON(site1_geojson, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, style);
}
}).addTo(map).bindPopup('Site 1');
If you want a popup specific to each layer / feature, and this specific content is reachable in each Feature properties, you can refer to Combining geojson and json for leaftlet and Leaflet omnivore + clustering markers + filtering marker cluster group
I'm adding some points to a map using the code below and they look great. I'm also adding some json polygons without issue.
When a certain zoom level is reached I would like the points and polygons to turn off. Using the map.removeLayer(name of polygon) turns off the polygon perfectly and then zoom back out I use map.addLayer(name of polygon) and they come back (using 'zoomend' and if else statement).
The point features do not react to the removeLayer function like the polygons do. I've also tried to harvestPoints.setOpacity(0) which does not work either. What code should I use to turn these geojson markers "on" and "off" like the polygon features?
function onEachPoint(feature, layer) {
layer.bindPopup(feature.properties.MGNT_AREA.toString());
layer.on('click', function (e) { layer.openPopup(); });
layer.bindLabel(feature.properties.MGNT_AREA.toString(), {
noHide: true,
className: "my-label",
offset: [-2, -25]
}).addTo(map);
};
var areaIcon = {
icon: L.icon({
iconUrl: 'labels/MonitoringIcon.png',
iconAnchor: [20, 24]
})
};
var harvestPoints = new L.GeoJSON.AJAX('labels/dfo_areas_point.json', {
onEachFeature: onEachPoint,
pointToLayer: function (feature, latlng) {
return L.marker(latlng, areaIcon);
}
});
Not sure exactly what is the root cause for your issue, as we are missing how exactly you reference yours points (markers) when you try to remove them from the map.
Normally, there should be no difference between polygons and points (markers) to achieve what you described (removing the layers from the map at certain zoom level, and add them back at other zooms).
Note that setOpacity is a method for L.Markers, whereas you apply it to harvestPoints which is your geoJson layer group.
What may happen is that you add individual points (markers) to your map (last instruction in your onEachPoint function), but try to remove the layer group harvestPoints from map. Because it seems to be never added to the map, nothing happens.
If you want to turn on/off ALL the points in your harvestPoints layer group at the same time, then you would simply add / remove that layer group to / from the map, instead of adding individual markers:
var harvestPoints = L.geoJson.ajax('labels/dfo_areas_point.json', {
onEachFeature: onEachPoint,
pointToLayer: function (feature, latlng) {
// make sure `areaIcon` is an OPTIONS objects
return L.marker(latlng, areaIcon);
}
}).addTo(map); // Adding the entire geoJson layer to the map.
map.on("zoomend", function () {
var newMapZoom = map.getZoom();
if (newMapZoom >= 13) {
map.addLayer(harvestPoints);
} else {
// Removing entire geoJson layer that contains the points.
map.removeLayer(harvestPoints);
}
});
Side note: popups open on click by default, you should not need to add an on click listener for that?
Demo: http://jsfiddle.net/ve2huzxw/62/