Skip to content

Filter Symbols by Text Input ​

Filter map features dynamically as the user types in a search box using setFilter().

Filter by Text Input ​

javascript
const searchInput = document.getElementById('search');

searchInput.addEventListener('input', (e) => {
  const query = e.target.value.trim().toLowerCase();

  if (!query) {
    map.setFilter('my-layer', null); // show all
    return;
  }

  // Filter: feature name contains the query string
  map.setFilter('my-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>
    <input id="search" type="text" placeholder="Search..." style="padding:8px;margin-bottom:8px;width:300px;" />
    <div id="map"></div>
    <script>
      const map = new mapmetricsgl.Map({ container: 'map', style: '<StyleFile_URL_with_Token>', center: [10, 50], zoom: 3 });
      map.on('load', () => {
        map.addSource('cities', {
          type: 'geojson',
          data: {
            type: 'FeatureCollection',
            features: [
              { type: 'Feature', properties: { name: 'Paris' }, geometry: { type: 'Point', coordinates: [2.349902, 48.852966] } },
              { type: 'Feature', properties: { name: 'London' }, geometry: { type: 'Point', coordinates: [-0.1276, 51.5074] } },
              { type: 'Feature', properties: { name: 'Berlin' }, geometry: { type: 'Point', coordinates: [13.405, 52.52] } },
            ]
          }
        });
        map.addLayer({ id: 'cities-layer', type: 'circle', source: 'cities', paint: { 'circle-radius': 9, 'circle-color': '#3b82f6' } });
      });
      document.getElementById('search').addEventListener('input', (e) => {
        const q = e.target.value.toLowerCase();
        map.setFilter('cities-layer', q ? ['in', q, ['downcase', ['get', 'name']]] : null);
      });
    </script>
  </body>
</html>
jsx
import React, { useEffect, useRef, useState } 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' }, geometry: { type: 'Point', coordinates: [2.349902, 48.852966] } },
    { type: 'Feature', properties: { name: 'London' }, geometry: { type: 'Point', coordinates: [-0.1276, 51.5074] } },
    { type: 'Feature', properties: { name: 'Berlin' }, geometry: { type: 'Point', coordinates: [13.405, 52.52] } },
  ]
};

const FilterByText = () => {
  const mapContainer = useRef(null);
  const map = useRef(null);
  const [query, setQuery] = useState('');

  useEffect(() => {
    if (map.current) return;
    map.current = new mapmetricsgl.Map({ container: mapContainer.current, style: '<StyleFile_URL_with_Token>', center: [10, 50], zoom: 3 });
    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': 9, 'circle-color': '#3b82f6' } });
    });
    return () => { map.current?.remove(); map.current = null; };
  }, []);

  const handleSearch = (e) => {
    const q = e.target.value.toLowerCase();
    setQuery(q);
    if (!map.current) return;
    map.current.setFilter('cities-layer', q ? ['in', q, ['downcase', ['get', 'name']]] : null);
  };

  return (
    <div>
      <input type="text" value={query} onChange={handleSearch} placeholder="Search cities..." style={{ padding: '8px', marginBottom: '8px', width: '300px' }} />
      <div ref={mapContainer} style={{ height: '500px', width: '100%' }} />
    </div>
  );
};

export default FilterByText;

For more information, visit the MapMetrics GitHub repository.