Skip to content

Filter symbols by toggling a list

Filter a set of symbols based on a property value in the data.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Filter symbols by toggling a list</title>
    <meta property="og:description" content="Filter a set of symbols based on a property value in the data." />
    <meta charset='utf-8'>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/trackasia-gl.css" />
    <script src="https://unpkg.com/[email protected]/dist/trackasia-gl.js"></script>
    <style>
        body { margin: 0; padding: 0; }
        html, body, #map { height: 100%; }
        .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);
        }

        .filter-group input[type='checkbox'] + label {
            background-color: #3386c0;
            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="map"></div>
<nav id="filter-group" class="filter-group"></nav>

<script>
    const places = {
            'type': 'FeatureCollection',
            'features': [
                {
                    'type': 'Feature',
                    'properties': {
                        'icon': 'bank-11'
                    },
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [106.629018,10.780074]
                    }
                },
                {
                    'type': 'Feature',
                    'properties': {
                        'icon': 'bank-11'
                    },
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [106.66298,10.778281]                }
                },
                {
                    'type': 'Feature',
                    'properties': {
                        'icon': 'bank-11'
                    },
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [106.654097,10.778387]
                    }
                },
                {
                    'type': 'Feature',
                    'properties': {
                        'icon': 'bicycle'
                    },
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [106.693948,10.780074]
                    }
                },
                {
                    'type': 'Feature',
                    'properties': {
                        'icon': 'cafe-11'
                    },
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [106.665262,10.758994]
                    }
                },
                {
                    'type': 'Feature',
                    'properties': {
                        'icon': 'cafe-11'
                    },
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [106.663373,10.778556]
                    }
                },
                {
                    'type': 'Feature',
                    'properties': {
                        'icon': 'cafe-11'
                    },
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [106.690169,10.785807]
                    }
                },
                {
                    'type': 'Feature',
                    'properties': {
                        'icon': 'cafe-11'
                    },
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [106.692169,10.785707]
                    }
                }
            ]
        };

        const filterGroup = document.getElementById('filter-group');
        const map = new trackasiagl.Map({
            container: 'map',
            style: 'https://maps.track-asia.com/styles/v1/streets.json?key=public_key',
            center: {"lat":10.762622,"lng":106.660172},
            zoom: 11.5
        });

        map.on('load', () => {
            // Add a GeoJSON source containing place coordinates and information.
            map.addSource('places', {
                'type': 'geojson',
                'data': places
            });

            places.features.forEach((feature) => {
                const symbol = feature.properties['icon'];
                const layerID = 'poi-' + symbol;

                // Add a layer for this symbol type if it hasn't been added already.
                if (!map.getLayer(layerID)) {
                    map.addLayer({
                        'id': layerID,
                        'type': 'symbol',
                        'source': 'places',
                        'layout': {
                            'icon-image': `${symbol}-11`,
                            'icon-overlap': 'always'
                        },
                        'filter': ['==', 'icon', symbol]
                    });

                    // Add checkbox and label elements for the layer.
                    const input = document.createElement('input');
                    input.type = 'checkbox';
                    input.id = layerID;
                    input.checked = true;
                    filterGroup.appendChild(input);

                    const label = document.createElement('label');
                    label.setAttribute('for', layerID);
                    label.textContent = symbol;
                    filterGroup.appendChild(label);

                    // When the checkbox changes, update the visibility of the layer.
                    input.addEventListener('change', (e) => {
                        map.setLayoutProperty(
                            layerID,
                            'visibility',
                            e.target.checked ? 'visible' : 'none'
                        );
                    });
                }
            });
        });
</script>

</body>
</html>