Skip to content
Animate a Symbol to Follow the Mouse

Animate a Symbol to Follow the Mouse in Maptoolkit Maps JS

Following the mouse with a symbol layer requires listening to the map’s mousemove event and calling setData on a GeoJSON source with the cursor’s geographic coordinates on each event. Because setData is lightweight for a single point, the update is fast enough to appear smooth at typical cursor speeds. Use this to build crosshair overlays, drag-to-place interactions, or custom cursor replacements that show geographic context.

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: [11.39085, 47.27574],
        zoom: 12,
        attributionControl: { compact: false }
    });

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

    const dot = {
        type: 'Feature',
        geometry: { type: 'Point', coordinates: [0, 0] }
    };

    map.on('load', () => {
        map.addSource('cursor', { type: 'geojson', data: dot });

        map.addLayer({
            id: 'cursor-circle',
            type: 'circle',
            source: 'cursor',
            paint: {
                'circle-radius': 12,
                'circle-color': 'transparent',
                'circle-stroke-width': 2,
                'circle-stroke-color': '#ee8a65'
            }
        });

        map.on('mousemove', (e) => {
            dot.geometry.coordinates = [e.lngLat.lng, e.lngLat.lat];
            map.getSource('cursor').setData(dot);
        });
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Animate a Symbol to Follow the Mouse - Maptoolkit Maps JS</title>
    <meta property="og:description" content="Move a symbol layer to the mouse position on each mousemove event." />
    <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%; cursor: none; }
    </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: [11.39085, 47.27574],
        zoom: 12,
        attributionControl: { compact: false }
    });

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

    const dot = {
        type: 'Feature',
        geometry: { type: 'Point', coordinates: [0, 0] }
    };

    map.on('load', () => {
        map.addSource('cursor', { type: 'geojson', data: dot });

        map.addLayer({
            id: 'cursor-circle',
            type: 'circle',
            source: 'cursor',
            paint: {
                'circle-radius': 12,
                'circle-color': 'transparent',
                'circle-stroke-width': 2,
                'circle-stroke-color': '#ee8a65'
            }
        });

        map.on('mousemove', (e) => {
            dot.geometry.coordinates = [e.lngLat.lng, e.lngLat.lat];
            map.getSource('cursor').setData(dot);
        });
    });
</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 12, centered around [11.39085, 47.27574]. Add a circle symbol that follows the mouse cursor.

How it works

mousemove gives e.lngLat, and each event rebuilds the one-feature source through setData, so the symbol tracks the cursor.

This is driven by events rather than frames, which is the right choice here: there is nothing to draw between mouse movements, so a requestAnimationFrame loop would recompute an unchanged position.

mousemove can fire more often than the screen refreshes. For anything heavier than moving one point, buffer the latest position and apply it once per frame instead of on every event.

There is no touch equivalent, so a cursor-following symbol simply does not exist on a phone.

Next steps

A symbol tracking the cursor is most useful when it previews an action: where a marker would land, which point would be selected, what the click will do.

Snapping is what usually comes next, pulling the symbol to the nearest feature or road rather than following the cursor exactly, which turns a decoration into a placement tool.