Filter Features Within a Layer ​
Show or hide specific map features dynamically using setFilter() without reloading data.
How It Works ​
setFilter() applies a filter expression to a layer — only features that match the expression are displayed. The data stays in the source; only the rendering changes.
Basic Filter Patterns ​
javascript
// Show all features (clear filter)
map.setFilter('my-layer', null);
// Match exact string value
map.setFilter('my-layer', ['==', ['get', 'type'], 'capital']);
// Match boolean property
map.setFilter('my-layer', ['==', ['get', 'port'], true]);
// Numeric comparison
map.setFilter('my-layer', ['>=', ['get', 'population'], 1000000]);
// Multiple conditions (AND)
map.setFilter('my-layer', [
'all',
['==', ['get', 'type'], 'capital'],
['>=', ['get', 'population'], 1000000]
]);
// Multiple conditions (OR)
map.setFilter('my-layer', [
'any',
['==', ['get', 'type'], 'capital'],
['==', ['get', 'port'], true]
]);Filter by Text Search ​
javascript
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', (e) => {
const query = e.target.value.toLowerCase();
if (!query) {
map.setFilter('cities-layer', null);
return;
}
// Filter by name containing the search text
map.setFilter('cities-layer', [
'in',
query,
['downcase', ['get', 'name']]
]);
});Complete Example ​
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
<script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
<style>#map { height: 500px; width: 100%; }</style>
</head>
<body>
<div id="map"></div>
<div>
<button onclick="filterBy('all')">All</button>
<button onclick="filterBy('capital')">Capitals</button>
<button onclick="filterBy('city')">Cities</button>
</div>
<script>
const map = new mapmetricsgl.Map({
container: 'map',
style: '<StyleFile_URL_with_Token>',
center: [5, 48],
zoom: 4
});
map.on('load', () => {
map.addSource('cities', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [
{ type: 'Feature', properties: { name: 'Paris', type: 'capital' }, geometry: { type: 'Point', coordinates: [2.349902, 48.852966] } },
{ type: 'Feature', properties: { name: 'London', type: 'capital' }, geometry: { type: 'Point', coordinates: [-0.1276, 51.5074] } },
{ type: 'Feature', properties: { name: 'Hamburg', type: 'city' }, geometry: { type: 'Point', coordinates: [9.9937, 53.5511] } },
{ type: 'Feature', properties: { name: 'Lyon', type: 'city' }, geometry: { type: 'Point', coordinates: [4.8357, 45.764] } },
]
}
});
map.addLayer({
id: 'cities-layer',
type: 'circle',
source: 'cities',
paint: {
'circle-radius': 10,
'circle-color': ['match', ['get', 'type'], 'capital', '#ef4444', '#3b82f6'],
'circle-stroke-width': 2,
'circle-stroke-color': '#fff'
}
});
});
function filterBy(type) {
if (type === 'all') {
map.setFilter('cities-layer', null);
} else {
map.setFilter('cities-layer', ['==', ['get', 'type'], type]);
}
}
</script>
</body>
</html>jsx
import React, { useEffect, useRef } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';
const citiesData = {
type: 'FeatureCollection',
features: [
{ type: 'Feature', properties: { name: 'Paris', type: 'capital' }, geometry: { type: 'Point', coordinates: [2.349902, 48.852966] } },
{ type: 'Feature', properties: { name: 'London', type: 'capital' }, geometry: { type: 'Point', coordinates: [-0.1276, 51.5074] } },
{ type: 'Feature', properties: { name: 'Hamburg', type: 'city' }, geometry: { type: 'Point', coordinates: [9.9937, 53.5511] } },
{ type: 'Feature', properties: { name: 'Lyon', type: 'city' }, geometry: { type: 'Point', coordinates: [4.8357, 45.764] } },
]
};
const FilterLayer = () => {
const mapContainer = useRef(null);
const map = useRef(null);
useEffect(() => {
if (map.current) return;
map.current = new mapmetricsgl.Map({
container: mapContainer.current,
style: '<StyleFile_URL_with_Token>',
center: [5, 48],
zoom: 4
});
map.current.on('load', () => {
map.current.addSource('cities', { type: 'geojson', data: citiesData });
map.current.addLayer({
id: 'cities-layer',
type: 'circle',
source: 'cities',
paint: {
'circle-radius': 10,
'circle-color': ['match', ['get', 'type'], 'capital', '#ef4444', '#3b82f6'],
'circle-stroke-width': 2,
'circle-stroke-color': '#fff'
}
});
});
return () => { map.current?.remove(); map.current = null; };
}, []);
const filterBy = (type) => {
if (!map.current) return;
if (type === 'all') {
map.current.setFilter('cities-layer', null);
} else {
map.current.setFilter('cities-layer', ['==', ['get', 'type'], type]);
}
};
return (
<div>
<div ref={mapContainer} style={{ height: '500px', width: '100%' }} />
<div style={{ marginTop: '8px', display: 'flex', gap: '8px' }}>
<button onClick={() => filterBy('all')} style={{ padding: '8px 16px', background: '#3b82f6', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' }}>All</button>
<button onClick={() => filterBy('capital')} style={{ padding: '8px 16px', background: '#ef4444', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' }}>Capitals</button>
<button onClick={() => filterBy('city')} style={{ padding: '8px 16px', background: '#22c55e', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' }}>Cities</button>
</div>
</div>
);
};
export default FilterLayer;For more information, visit the MapMetrics GitHub repository.