Skip to content

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>