Filter POI's by toggling a list
With this code example, you can display a map with different points of interest (POI). Users can toggle the visibility of each POI by checking or unchecking the corresponding checkbox.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.smartmaps.cloud/packages/smartmaps/smartmaps-gl/v2/umd/smartmaps-gl.min.js"></script>
<style>
body,
html,
#map {
margin: 0;
padding: 0;
height: 100%;
}
/* Styling for checkboxes and labels */
.filter-group {
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-weight: 600;
position: absolute;
top: 10px;
right: 10px;
z-index: 1;
border-radius: 3px;
width: 120px;
color: #fff;
}
.filter-group input[type='checkbox']:first-child+label {
border-radius: 3px 3px 0 0;
}
.filter-group label:last-child {
border-radius: 0 0 3px 3px;
border: none;
}
.filter-group input[type='checkbox'] {
display: none;
}
.filter-group input[type='checkbox']+label {
background-color: #3386c0;
display: block;
cursor: pointer;
padding: 10px;
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
text-transform: capitalize;
}
.filter-group input[type='checkbox']+label:hover,
.filter-group input[type='checkbox']:checked+label {
background-color: #4ea0da;
}
.filter-group input[type='checkbox']:checked+label:before {
content: '✔';
margin-right: 5px;
}
</style>
</head>
<body>
<div id="filter-group" class="filter-group">
<input type="checkbox" id="cafeCheckbox" checked>
<label for="cafeCheckbox">Café</label>
<input type="checkbox" id="cinemaCheckbox" checked>
<label for="cinemaCheckbox">Cinema</label>
<input type="checkbox" id="marketplaceCheckbox" checked>
<label for="marketplaceCheckbox">Marketplace</label>
<input type="checkbox" id="restaurantCheckbox" checked>
<label for="restaurantCheckbox">Restaurant</label>
<input type="checkbox" id="toiletsCheckbox" checked>
<label for="toiletsCheckbox">Toilet</label>
</div>
<div id="map"></div>
<script>
// Initialize the map
const map = new smartmapsgl.Map({
apiKey: "INSERT API-KEY",
container: "map",
center: [8.399830018049352, 49.01264948779226],
zoom: 14,
style: smartmapsgl.MapStyle.AUTO
});
// Define icons and their corresponding image paths
const icons = {
cafe: "../images/cafe.png",
cinema: "../images/cinema.png",
marketplace: "../images/marketplace.png",
restaurant: "../images/restaurant.png",
toilets: "../images/toilet.png"
};
// Function to load an image and return it as an HTMLImageElement
const loadImage = (url) => new Promise((resolve, reject) => {
const img = new Image();
img.src = url;
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`Failed to load image: ${url}`));
});
// Function to add a new layer to the map using a specific icon
const addLayer = (id, icon, filter) => map.addLayer({
id, type: "symbol", source: "smartmaps", "source-layer": "poi",
layout: { "icon-image": icon, "icon-size": 0.5, "icon-overlap": 'always' },
filter: ["==", ["get", "amenity"], filter]
});
// Function to load and add all icons dynamically
const loadAndAddIcons = async () => {
await Promise.all(Object.entries(icons).map(async ([key, url]) => {
try {
const img = await loadImage(url);
const iconId = `${key}-icon`, layerId = `${key}-layer`;
map.addImage(iconId, img);
addLayer(layerId, iconId, key);
} catch (error) {
console.error(error);
}
}));
};
// Load the icons and layers once the map is fully initialized
map.on("load", loadAndAddIcons);
// Event listener for checkboxes
["cafe", "cinema", "marketplace", "restaurant", "toilets"].forEach(type => {
document.getElementById(`${type}Checkbox`).addEventListener("change", (event) => {
map.setLayoutProperty(
`${type}-layer`,
"visibility",
event.target.checked ? "visible" : "none"
);
});
});
</script>
</body>
</html>