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>