Reputation: 2628
I am building a website that renders circles on a map. If the ["feature-state", "value]
property is >= 1, the circle is green and if the ["feature-state", "value"]
property is 0 or null, the circle is red (the default value is 0). When my map is zoomed in enough, the circles are rendered properly (all circles with ["feature-state", "value]
>= 1 are rendered green). However, when I zoom out, the cluster circle that contains children features/circles with a ["feature-state", "value]
, the circle is rendered as red instead of green. Is there any way to ensure that the clusters are rendered as green if the sum of their children's ["feature-state", "value]
is >= 1?
Below is my rendering code:
map.addSource('cities', {
"type": "geojson",
"data": "cities.geojson",
"cluster": true,
"clusterMaxZoom": 14,
"clusterRadius": 80
});
map.addLayer({
"id": "cities",
"type": "circle",
"source": "cities",
"paint": {
"circle-color": [
"case",
["==", ["feature-state", "value"], null], "#ff4d4d",
[">=", ["feature-state", "value"], 1], "#33cc33",
"#ff4d4d"
],
"circle-radius": [
"case",
["==", ["feature-state", "value"], null], 9,
[">=", ["feature-state", "value"], 1], 12,
6
],
"circle-opacity" : [
"case",
["==", ["feature-state", "value"], null], 0.7,
[">=", ["feature-state", "value"], 1], 1,
0.7
]
},
});
Below is how I set the "feature-state"
:
map.setFeatureState({source: "cities", id : 124312}, {value: 1});
Here is a screenshot of the map when correctly zoomed in:
Here is a screenshot of the map when zoomed out (the red circle in the area marked with a white marker should be rendered green):
Upvotes: 1
Views: 1346
Reputation: 5213
This can be done with clusterProperties
option of the source object which takes custom expression to aggregate properties for a cluster point.
Note: clusterProperties
option does not support feature-state aggregation and can only work with properties. I'll explain it in steps below and there's also a codepen example attached at bottom.
{
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 80,
clusterProperties: {
/*
get the property numUser, then cast it to number or 0,
then sum it, then store the sum as cluster's numUser property
*/
numUsers: ["+", ["number", ["get", "numUsers"], 0]]
},
type: "geojson",
data: geojson,
}
feature-state
:paint: {
"circle-color": [
"case",
["==", ["get", "numUsers"], null], "#ff4d4d",
[">=", ["get", "numUsers"], 1], "#33cc33",
"#ff4d4d"
],
"circle-radius": [
"case",
["==", ["get", "numUsers"], null], 9,
[">=", ["get", "numUsers"], 1], 12,
6
],
"circle-opacity": [
"case",
["==", ["get", "numUsers"], null], 0.7,
[">=", ["get", "numUsers"], 1], 1,
0.7
]
}
// Update after 2 seconds
setTimeout(() => {
const newGeojson = {
...geojson,
features: geojson.features.map(feature => {
if ([0, 1].includes(feature.id)) { // update features selectively
feature.properties.numUsers = 1;
}
return feature;
})
};
map.getSource('geom').setData(newGeojson);
}, 2000);
Here's a working codepen: https://codepen.io/manishraj/full/wvwmNKR
There's a related example here, by mapbox: https://docs.mapbox.com/mapbox-gl-js/example/cluster-html/
Upvotes: 1