I'd like to have a map using OpenStreetMap showing location of flowers. My point is to have LayersControl with colours and type and be able to check for example Orange and Tulip and see only orange tulips on the map but it seems hard from what i read on React LeafLet documentation.
To be easier to understand i will add some code :
Flower datas example:
const flowers = [
{
"type": "Tulip",
"colour": "Orange",
"latlng": [52.081222, 5.235965],
},
{
"type": "Crocus",
"colour": "Red",
"latlng": [52.081421, 5.235534],
},
]
LeafletMap.jsx (Partial):
const LeafletMap: React.FC = () => {
return (
<MapContainer id="mapId"
center={averagePos}
zoom={zoom}>
{flowerItems.map((flower, index) => (
//Maybe do something here like sorting and creating
//multiple layers
//or having already a layer for every type of search
//but if i want to add more colours ou type it can be very hard to update
))}
</LayersControl>
</MapContainer>
)
}
You could maintain the selected layers using state variables - one array to track the type (Crocus or Tulip) and another to track the colour (red or orange). Initially, the states are setup to show everything:
const [type, setType] = useState(['Tulip', 'Crocus']);
const [colour, setColour] = useState(['Orange', 'Red']);
For each type and colour you could create a LayersControl where you hook into the add and remove event handlers and update the corresponding state (type or colour) when the layer is checked or unchecked by the user:
<LayersControl.Overlay name="Crocus" checked="true">
<LayerGroup
eventHandlers={{
add: (e) => {
updateTypeState('Crocus', true);
},
remove: (e) => {
updateTypeState('Crocus', false);
},
}}
></LayerGroup>
</LayersControl.Overlay>
The functions to update the state look like this (there is one function for updating type and one for updating colour):
const updateTypeState = (key: string, value: boolean) => {
setType((prevState) => {
if (value) {
prevState = [...prevState, key];
} else {
prevState = prevState.filter((e) => e !== key);
}
console.log(prevState);
return prevState;
});
};
const updateColourState = (key: string, value: boolean) => {
setColour((prevState) => {
if (value) {
prevState = [...prevState, key];
} else {
prevState = prevState.filter((e) => e !== key);
}
return prevState;
});
};
You could then render the markers using the map function as you suggested:
{flowers
.filter((flower) => {
if (type.length == 0 && colour.length == 0) {
// No layers selected, so show all
return true;
}
if (type.length > 0 && colour.length > 0) {
// Colours and types selected
return (
type.indexOf(flower.type) >= 0 &&
colour.indexOf(flower.colour) >= 0
);
}
if (type.length > 0) {
// Type selected, no colour selected
return type.indexOf(flower.type) >= 0;
}
// Colour selected, no type selected
return colour.indexOf(flower.colour) >= 0;
})
.map((flower, index) => (
<Marker position={flower.latlng}>
<Popup>
{flower.type}, {flower.colour}
</Popup>
</Marker>
))}
There's a working StackBlitz here, but please note the marker images do not display properly due to this issue, but you should be able to see a broken image icon and click on it to view details of the flower.