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>