Skip to content
Center the Map on a Clicked Symbol

Center the Map on a Clicked Symbol in Maptoolkit Maps JS

Centering the map on a clicked symbol requires listening to the click event on a symbol layer and reading the geometry coordinates from the returned feature. Passing those coordinates to map.flyTo animates the camera to that location with a smooth transition. Use this pattern in place directories, store locators, or any map where clicking a point of interest should bring it into focus.

const API_KEY = 'YOUR_API_KEY';

    const map = new maptoolkit.Map({
        container: 'map',
        apiKey: API_KEY,
        style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
        center: [12.0, 47.5],
        zoom: 7,
        attributionControl: { compact: false }
    });

    map.addControl(new maptoolkit.NavigationControl(), 'top-right');

    map.on('load', () => {
        map.addSource('cities', {
            type: 'geojson',
            data: {
                type: 'FeatureCollection',
                features: [
                    { type: 'Feature', geometry: { type: 'Point', coordinates: [11.39085, 47.27574] }, properties: { name: 'Innsbruck' } },
                    { type: 'Feature', geometry: { type: 'Point', coordinates: [16.3738, 48.2082] }, properties: { name: 'Vienna' } },
                    { type: 'Feature', geometry: { type: 'Point', coordinates: [13.0550, 47.8095] }, properties: { name: 'Salzburg' } },
                    { type: 'Feature', geometry: { type: 'Point', coordinates: [15.4395, 47.0707] }, properties: { name: 'Graz' } }
                ]
            }
        });

        map.addLayer({
            id: 'cities-circle',
            type: 'circle',
            source: 'cities',
            paint: {
                'circle-radius': 10,
                'circle-color': '#ee4b2b',
                'circle-stroke-width': 2,
                'circle-stroke-color': '#ffffff'
            }
        });

        map.addLayer({
            id: 'cities-label',
            type: 'symbol',
            source: 'cities',
            layout: {
                'text-field': ['get', 'name'],
                'text-offset': [0, 1.5],
                'text-anchor': 'top',
                'text-size': 13
            }
        });

        map.on('click', 'cities-circle', (e) => {
            map.flyTo({ center: e.features[0].geometry.coordinates, zoom: 14 });
        });

        map.on('mouseenter', 'cities-circle', () => { map.getCanvas().style.cursor = 'pointer'; });
        map.on('mouseleave', 'cities-circle', () => { map.getCanvas().style.cursor = ''; });
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Center the Map on a Clicked Symbol - Maptoolkit Maps JS</title>
    <meta property="og:description" content="Fly to a symbol's location when the user clicks on it." />
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.css" />
    <style>
        html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
        #map { width: 100%; height: 100%; }
    </style>
</head>
<body>
<div id="map"></div>
<script>
    const API_KEY = 'YOUR_API_KEY';

    const map = new maptoolkit.Map({
        container: 'map',
        apiKey: API_KEY,
        style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
        center: [12.0, 47.5],
        zoom: 7,
        attributionControl: { compact: false }
    });

    map.addControl(new maptoolkit.NavigationControl(), 'top-right');

    map.on('load', () => {
        map.addSource('cities', {
            type: 'geojson',
            data: {
                type: 'FeatureCollection',
                features: [
                    { type: 'Feature', geometry: { type: 'Point', coordinates: [11.39085, 47.27574] }, properties: { name: 'Innsbruck' } },
                    { type: 'Feature', geometry: { type: 'Point', coordinates: [16.3738, 48.2082] }, properties: { name: 'Vienna' } },
                    { type: 'Feature', geometry: { type: 'Point', coordinates: [13.0550, 47.8095] }, properties: { name: 'Salzburg' } },
                    { type: 'Feature', geometry: { type: 'Point', coordinates: [15.4395, 47.0707] }, properties: { name: 'Graz' } }
                ]
            }
        });

        map.addLayer({
            id: 'cities-circle',
            type: 'circle',
            source: 'cities',
            paint: {
                'circle-radius': 10,
                'circle-color': '#ee4b2b',
                'circle-stroke-width': 2,
                'circle-stroke-color': '#ffffff'
            }
        });

        map.addLayer({
            id: 'cities-label',
            type: 'symbol',
            source: 'cities',
            layout: {
                'text-field': ['get', 'name'],
                'text-offset': [0, 1.5],
                'text-anchor': 'top',
                'text-size': 13
            }
        });

        map.on('click', 'cities-circle', (e) => {
            map.flyTo({ center: e.features[0].geometry.coordinates, zoom: 14 });
        });

        map.on('mouseenter', 'cities-circle', () => { map.getCanvas().style.cursor = 'pointer'; });
        map.on('mouseleave', 'cities-circle', () => { map.getCanvas().style.cursor = ''; });
    });
</script>
</body>
</html>

Use the prompt below with any LLM to get the same result. Make sure the Maptoolkit MCP server is connected first — check out AI Integration & MCP to get started.

Use the Maptoolkit Connector. Create an interactive map with zoom level 7, centered around [12.0, 47.5]. Add circle markers with labels for Innsbruck, Vienna, Salzburg, and Graz. Clicking a marker should fly to that city.

How it works

The click handler is registered on a layer id, not on the map. That filtering matters: map.on('click', 'layer-id', handler) fires only for features in that layer, where map.on('click', handler) fires for every click anywhere and leaves you to work out what was hit.

e.features holds what was clicked, and e.features[0].geometry.coordinates is the point’s position. Reading the geometry rather than the cursor position is what centres the map on the symbol itself rather than wherever the user happened to click within it.

The handler is wired inside map.on('load') because the layer has to exist before you can listen to it. Registering against a layer that is not there yet silently never fires.

Changing the cursor on mouseenter and back on mouseleave is what tells a user the symbol is clickable at all.

Next steps

Centring is feedback rather than an outcome, so the next step is what the click actually does: open a detail panel with the feature’s data, load data for that feature, or update a list beside the map. Keeping a list and a map in sync in both directions is the pattern most people are really building.

Selection state is the piece that makes it feel finished, so the clicked feature stays visibly chosen rather than snapping back the moment the camera stops.