Markers | MapGL | Urbi Documentation
MapGL JS API

Markers

To add a Marker to the map, specify the required coordinates:

const marker = new mapgl.Marker(map, {
    coordinates: [55.31878, 25.23584],
});
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <meta name="description" content="A single marker example" />
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.31878, 25.23584],
                zoom: 13,
                key: 'Your API access key',
            });
            const marker = new mapgl.Marker(map, {
                coordinates: [55.31878, 25.23584],
            });
        </script>
    </body>
</html>

To add multiple Markers to the map, use a loop:

const coords = [
    [55.27414804174869, 25.257576991034284],
    [55.289254243403306, 25.211614202468652],
    [55.34418588368302, 25.215341562259866],
    [55.35036569359612, 25.26068195798851],
    [55.32976632814914, 25.238324424362062],
];
coords.forEach((coord) => {
    const marker = new mapgl.Marker(map, {
        coordinates: coord,
    });
});
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <meta name="description" content="Several markers example" />
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.31878, 25.23584],
                zoom: 13,
                key: 'Your API access key',
            });
            const coords = [
                [55.27414804174869, 25.257576991034284],
                [55.289254243403306, 25.211614202468652],
                [55.34418588368302, 25.215341562259866],
                [55.35036569359612, 25.26068195798851],
                [55.32976632814914, 25.238324424362062],
            ];
            coords.forEach((coord) => {
                const marker = new mapgl.Marker(map, {
                    coordinates: coord,
                });
            });
        </script>
    </body>
</html>

To change the Marker icon, specify the icon parameter:

const marker = new mapgl.Marker(map, {
    coordinates: [55.31878, 25.23584],
    icon: 'https://docs.2gis.com/img/mapgl/marker.svg',
});
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <meta name="description" content="Change marker icon example" />
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.31878, 25.23584],
                zoom: 13,
                key: 'Your API access key',
            });
            const marker = new mapgl.Marker(map, {
                coordinates: [55.31878, 25.23584],
                icon: 'https://docs.2gis.com/img/mapgl/marker.svg',
            });
        </script>
    </body>
</html>

To add a Marker with text, specify the label parameter:

const marker = new mapgl.Marker(map, {
    coordinates: [55.31878, 25.23584],
    label: {
        text: "The marker's label",
    },
});
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.31878, 25.23584],
                zoom: 13,
                key: 'Your API access key',
            });
            const marker = new mapgl.Marker(map, {
                coordinates: [55.31878, 25.23584],
                label: {
                    text: "The marker's label",
                },
            });
        </script>
    </body>
</html>

To change the position of the text, specify the relativeAnchor and offset parameters for the label (see LabelOptions for more information):

// Middle-right alignment
const rightCenter = new mapgl.Marker(map, {
    coordinates: [55.32878, 25.23584],
    icon: '/img/mapgl/marker.svg',
    label: {
        text: 'Right center placement',
        offset: [20, 0],
        relativeAnchor: [0, 0.5],
    },
});
// Top-left alignment
const leftTop = new mapgl.Marker(map, {
    coordinates: [55.30878, 25.22584],
    icon: '/img/mapgl/marker.svg',
    label: {
        text: 'Left top placement',
        offset: [-10, -10],
        relativeAnchor: [1, 1],
    },
});
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.31878, 25.23584],
                zoom: 13,
                key: 'Your API access key',
            });
            // The right center label placement,
            const rightCenter = new mapgl.Marker(map, {
                coordinates: [55.32878, 25.23584],
                icon: 'https://docs.2gis.com/img/mapgl/marker.svg',
                label: {
                    text: 'Right center placement',
                    offset: [20, 0],
                    relativeAnchor: [0, 0.5],
                },
            });
            // The left top label placement,
            const leftTop = new mapgl.Marker(map, {
                coordinates: [55.30878, 25.22584],
                icon: 'https://docs.2gis.com/img/mapgl/marker.svg',
                label: {
                    text: 'Left top placement',
                    offset: [-10, -10],
                    relativeAnchor: [1, 1],
                },
            });
        </script>
    </body>
</html>

To add a text label with a background image, specify the image parameter (see LabelImage for more information):

const marker = new mapgl.Marker(map, {
    coordinates: [55.31878, 25.23584],
    label: {
        text: "The marker's label",
        offset: [0, 25],
        relativeAnchor: [0.5, 0],
        image: {
            url: 'tooltip-top.svg',
            size: [100, 50],
            stretchX: [
                [10, 40],
                [60, 90],
            ],
            stretchY: [[20, 40]],
            padding: [20, 10, 10, 10],
        },
    },
});

See Label examples for more information on how to correctly stretch the image.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.31878, 25.23584],
                zoom: 13,
                key: 'Your API access key',
            });
            const marker = new mapgl.Marker(map, {
                coordinates: [55.31878, 25.23584],
                label: {
                    text: "The marker's label",
                    offset: [0, 25],
                    relativeAnchor: [0.5, 0],
                    image: {
                        url: 'https://docs.2gis.com/img/mapgl/tooltip-top.svg',
                        size: [100, 50],
                        stretchX: [
                            [10, 40],
                            [60, 90],
                        ],
                        stretchY: [[20, 40]],
                        padding: [20, 10, 10, 10],
                    },
                },
            });
        </script>
    </body>
</html>

To subscribe to events such as click on a marker, use the on() method (see DynamicObjectEventTable for the list of possible events):

const marker = new mapgl.Marker(map, {
    coordinates: [55.31878, 25.23584],
    icon: 'https://docs.2gis.com/img/mapgl/marker.svg',
});
marker.on('click', (e) => {
    alert('Marker is clicked');
});
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <meta name="description" content="Markers events handling example" />
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.31878, 25.23584],
                zoom: 13,
                key: 'Your API access key',
            });
            const marker = new mapgl.Marker(map, {
                coordinates: [55.31878, 25.23584],
                icon: 'https://docs.2gis.com/img/mapgl/marker.svg',
                label: {
                    text: "The marker's label",
                },
            });
            marker.on('click', (e) => {
                alert('Marker clicked');
            });
        </script>
    </body>
</html>

You can animate markers on the map:

You can also animate HTML markers using CSS or Lottie.

To animate a marker, first add a Marker object to the map and specify the coordinates of the marker center:

const marker = new mapgl.Marker(map, {
    coordinates: [55.31878, 25.23584],
});

The animation of a marker moving around a specified point is performed by changing the coordinates of the marker along the circle. New coordinates are calculated based on the current time and the rotation angle.

To add the animation of the movement along a circle, use the animateCircle function:

function animateCircle(marker, centerCoords, radius, duration) {
    const startTime = performance.now();

    function frame(time) {
        const elapsed = (time - startTime) % duration; // Time elapsed since the start of the current animation iteration
        const angle = (2 * Math.PI * elapsed) / duration; // Current angle in radians

        const newCoords = [
            centerCoords[0] + radius * Math.cos(angle), // Calculating longitude
            centerCoords[1] + radius * Math.sin(angle), // Calculating latitude
        ];

        marker.setCoordinates(newCoords); // Setting the new marker coordinates

        requestAnimationFrame(frame); // Scheduling the next frame
    }

    requestAnimationFrame(frame);
}

// Calling the animation function
animateCircle(marker, [55.31878, 25.23584], 0.01, 5000);

Specify the following parameters for the animateCircle function:

  • marker: marker object to animate.
  • centerCoords: coordinates of the circle center in the [longitude, latitude] format.
  • radius: radius of the circle in geographic coordinates (in degrees).
  • duration: duration of one full revolution in milliseconds.
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
<div id="container"></div>
<script src="https://mapgl.2gis.com/api/js/v1"></script>
<script>
        const map = new mapgl.Map('container', {
            center: [55.323, 25.235],
            zoom: 10.5,
            key: 'Your API access key',
        });

        const marker = new mapgl.Marker(map, {
            coordinates: [55.323, 25.235],
        });

        const centerCoords = [55.323, 25.235];
        const radius = 0.1;
        const duration = 5000;

        function animateMarkerInCircle(marker, centerCoords, radius, duration) {
            const startTime = performance.now();

            function frame(time) {
                const elapsed = (time - startTime) % duration;
                const angle = (2 * Math.PI * elapsed) / duration;
                const newCoords = [
                    centerCoords[0] + radius * Math.cos(angle),
                    centerCoords[1] + radius * Math.sin(angle),
                ];

                marker.setCoordinates(newCoords);
                requestAnimationFrame(frame);
            }

            requestAnimationFrame(frame);
        }

        animateMarkerInCircle(marker, centerCoords, radius, duration);
</script>
</body>
</html>

The jumping animation allows a marker to move up and down, creating a bounce effect.

To perform the animation, the vertical offset of the marker is calculated relatively to its base coordinates. To make the jump look the same regardless of the scale and correct when the camera position changes, the current map scale is considered.

To add the jumping animation, use the animateJump function:

function animateJump(marker, map, baseCoords, amplitude, duration) {
    const startTime = performance.now();

    function frame(time) {
        const elapsed = (time - startTime) % duration; // Time elapsed since the start of the current animation iteration
        const bounce = Math.sin((2 * Math.PI * elapsed) / duration) * amplitude; // Jump height

        // Converting geographic coordinates to pixel coordinates
        const basePixelCoords = map.project(baseCoords);

        // Applying Y-axis (vertical) offset in pixels
        const newPixelCoords = [
            basePixelCoords[0], // X remains unchanged
            basePixelCoords[1] - bounce, // Decreasing Y for jumping up
        ];

        // Converting pixel coordinates back to geographic coordinates
        const newGeoCoords = map.unproject(newPixelCoords);

        // Setting the new marker coordinates
        marker.setCoordinates(newGeoCoords);

        requestAnimationFrame(frame); // Scheduling the next animation frame
    }

    requestAnimationFrame(frame);
}

// Calling the animation function
animateJump(marker, map, [55.31878, 25.23584], 20, 1000);

Specify the following parameters for the animateJump function:

  • marker: marker object to animate.
  • map: map object used for coordinate transformation.
  • baseCoords: initial coordinates of the marker in the [longitude, latitude] format.
  • amplitude: jump amplitude (height of movement) in pixels.
  • duration: duration of one full jump (up and down) in milliseconds.
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
        const map = new mapgl.Map('container', {
            center: [55.323, 25.235],
            zoom: 10.5,
            key: 'Your API access key',
        });

        const marker = new mapgl.Marker(map, {
            coordinates: [55.323, 25.235],
        });

        const centerCoords = [55.323, 25.235];
        const radius = 0.1;
        const duration = 5000;

        function jumpMarkerAnimation(marker, map, baseCoords, amplitude, duration) {
            const startTime = performance.now();

            function frame(time) {
                const elapsed = (time - startTime) % duration;
                const bounce = Math.sin((2 * Math.PI * elapsed) / duration) * amplitude;

                const basePixelCoords = map.project(baseCoords);
                const newPixelCoords = [
                    basePixelCoords[0],
                    basePixelCoords[1] - bounce,
                ];
                const newGeoCoords = map.unproject(newPixelCoords);
                marker.setCoordinates(newGeoCoords);

                requestAnimationFrame(frame);
            }

            requestAnimationFrame(frame);
        }

        jumpMarkerAnimation(marker, map, [55.323, 25.235], 20, 1000);

    </script>
    </body>
</html>

The route-based animation is performed by changing the geographical coordinates of the marker.

To add the animation of the movement along coordinates, use the animateTravel function:

// Function for interpolating between two points
function interpolateCoordinates(coord1, coord2, t) {
    return [coord1[0] + (coord2[0] - coord1[0]) * t, coord1[1] + (coord2[1] - coord1[1]) * t];
}

function animateTravel(marker, route, durationPerSegment) {
    let segmentIndex = 0;

    function animateSegment(startTime) {
        const elapsedTime = performance.now() - startTime;
        const t = elapsedTime / durationPerSegment; // Percentage of segment completion

        if (t < 1) {
            // Interpolating coordinates
            const newCoords = interpolateCoordinates(
                route[segmentIndex],
                route[segmentIndex + 1],
                t,
            );
            marker.setCoordinates(newCoords);

            // Continuing animation of the current segment
            requestAnimationFrame(() => animateSegment(startTime));
        } else {
            // Moving to the next segment
            segmentIndex++;
            if (segmentIndex < route.length - 1) {
                animateSegment(performance.now());
            } else {
                // Looping the route
                segmentIndex = 0;
                animateSegment(performance.now());
            }
        }
    }

    // Starting the animation of the first segment
    if (route.length > 1) {
        animateSegment(performance.now());
    }
}

// Calling the animation function
const durationPerSegment = 2000;
animateTravel(marker, route, durationPerSegment);

Specify the following parameters for the animateTravel function:

  • marker: marker object to animate.
  • route: array of route coordinates in the [longitude, latitude] format.
  • durationPerSegment: duration of each segment in milliseconds.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>2GIS Map API - Courier Animation</title>
    <style>
        html,
        body,
        #container {
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
    </style>
</head>
<body>
<div id="container"></div>
<script src="https://mapgl.2gis.com/api/js/v1"></script>
<script>
    const map = new mapgl.Map('container', {
        center: [55.280, 25.249],
        zoom: 14,
        key: 'Your API access key',
    });
    const route  = `55.280324 25.249851,55.272991 25.239421,55.278568 25.235182,55.284862 25.246507,55.280324 25.249851`.split(',')
        .map(pair => pair.split(' ').map(Number));

    const marker = new mapgl.Marker(map, {
        coordinates: route[0],
        icon: 'https://disk.2gis.com/styles/assets/icons/poi_cars-66605ef515e3adca7dea4e3f1bac00195e250a1250a5bf9e313708cb25fd1467.svg',
        size: [20,20],
    });

    function interpolateCoordinates(coord1, coord2, t) {
        return [
            coord1[0] + (coord2[0] - coord1[0]) * t,
            coord1[1] + (coord2[1] - coord1[1]) * t,
        ];
    }

    function animateCourier(marker, route, durationPerSegment) {
        let segmentIndex = 0;

        function animateSegment(startTime) {
            const elapsedTime = performance.now() - startTime;
            const t = elapsedTime / durationPerSegment;

            if (t < 1) {
                // Интерполируем координаты
                const newCoords = interpolateCoordinates(
                    route[segmentIndex],
                    route[segmentIndex + 1],
                    t
                );
                marker.setCoordinates(newCoords);
                requestAnimationFrame(() => animateSegment(startTime));
            } else {
                segmentIndex++;
                if (segmentIndex < route.length - 1) {
                    animateSegment(performance.now());
                } else {
                    segmentIndex = 0;
                    animateSegment(performance.now());
                }
            }
        }

        if (route.length > 1) {
            animateSegment(performance.now());
        }
    }

    const durationPerSegment = 2000;
    animateCourier(marker, route, durationPerSegment);

    window.addEventListener('unload', () => map.destroy());
</script>
</body>
</html>

You can animate an HTML marker movement with CSS. By following the example below you can animate an HTML marker moving along a route.

  1. Create a CSS animation, for example:

    <style>
        html,
        body,
        #container {
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
        .marker_container {
            position: relative;
            width: 40px;
            height: 40px;
        }
        .marker_container::before {
            content: '';
            position: absolute;
            top: 10px;
            left: 10px;
            transform: translate(-50%, -50%);
            width: 80px;
            height: 80px;
            border-radius: 50%;
            background: radial-gradient(
                closest-side,
                rgba(255, 165, 0, 0.8),
                rgba(255, 69, 0, 0.5),
                transparent
            );
            animation: firePulse 1s infinite ease-in-out;
        }
        @keyframes firePulse {
            0% {
                transform: translate(-50%, -50%) scale(1);
                opacity: 1;
            }
            50% {
                transform: translate(-50%, -50%) scale(1.2);
                opacity: 0.7;
            }
            100% {
                transform: translate(-50%, -50%) scale(1);
                opacity: 1;
            }
        }
        .wave {
            position: absolute;
            top: 10px;
            left: 10px;
            width: 10px;
            height: 10px;
            background: rgba(0, 0, 255, 0.5);
            border-radius: 50%;
            transform: translate(-50%, -50%);
            animation: waveAnimation 2s infinite;
        }
        @keyframes waveAnimation {
            0% {
                transform: translate(-50%, -50%) scale(1);
                opacity: 1;
            }
            100% {
                transform: translate(-50%, -50%) scale(5);
                opacity: 0;
            }
        }
    </style>
    
  2. Create an HTML marker. The route-based animation is performed by changing the geographical coordinates of the marker:

    const htmlMarker = new mapgl.HtmlMarker(map, {
        coordinates: [55.323, 25.235],
        html:
            '<div class="marker_container"><div class="wave"></div><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 50 50">\n' +
            '    <circle cx="25" cy="25" r="25" fill="white"/>\n' +
            '</svg></div>\n',
    });
    
  3. Add the animation of the movement along coordinates using the animateTravel function:

// Function for interpolating between two points
function interpolateCoordinates(coord1, coord2, t) {
    return [coord1[0] + (coord2[0] - coord1[0]) * t, coord1[1] + (coord2[1] - coord1[1]) * t];
}

function animateTravel(htmlMarker, route, durationPerSegment) {
    let segmentIndex = 0;

    function animateSegment(startTime) {
        const elapsedTime = performance.now() - startTime;
        const t = elapsedTime / durationPerSegment; // Percentage of segment completion

        if (t < 1) {
            // Interpolating coordinates
            const newCoords = interpolateCoordinates(
                route[segmentIndex],
                route[segmentIndex + 1],
                t,
            );
            htmlMarker.setCoordinates(newCoords);

            // Continuing animation of the current segment
            requestAnimationFrame(() => animateSegment(startTime));
        } else {
            // Moving to the next segment
            segmentIndex++;
            if (segmentIndex < route.length - 1) {
                animateSegment(performance.now());
            } else {
                // Looping the route
                segmentIndex = 0;
                animateSegment(performance.now());
            }
        }
    }

    // Starting the animation of the first segment
    if (route.length > 1) {
        animateSegment(performance.now());
    }
}

// Calling the animation function
const durationPerSegment = 2000;
animateTravel(htmlMarker, route, durationPerSegment);

Specify the following parameters for the animateTravel function:

  • htmlMarker: HTML marker object to animate (created on step 2).
  • route: array of route coordinates in the [longitude, latitude] format.
  • durationPerSegment: duration of each segment in milliseconds.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>2GIS Map API - Courier CSS Animation</title>
    <style>
        html,
        body,
        #container {
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
        .marker_container {
            position: relative;
            width: 40px;
            height: 40px;
        }
        .marker_container::before {
            content: '';
            position: absolute;
            top: 10px;
            left: 10px;
            transform: translate(-50%, -50%);
            width: 80px;
            height: 80px;
            border-radius: 50%;
            background: radial-gradient(closest-side, rgba(255, 165, 0, 0.8), rgba(255, 69, 0, 0.5), transparent);
            animation: firePulse 1s infinite ease-in-out;
        }
        @keyframes firePulse {
            0% {
                transform: translate(-50%, -50%) scale(1);
                opacity: 1;
            }
            50% {
                transform: translate(-50%, -50%) scale(1.2);
                opacity: 0.7;
            }
            100% {
                transform: translate(-50%, -50%) scale(1);
                opacity: 1;
            }
        }
        .wave {
            position: absolute;
            top: 10px;
            left: 10px;
            width: 10px;
            height: 10px;
            background: rgba(0, 0, 255, 0.5);
            border-radius: 50%;
            transform: translate(-50%, -50%);
            animation: waveAnimation 2s infinite;
        }
        @keyframes waveAnimation {
            0% {
                transform: translate(-50%, -50%) scale(1);
                opacity: 1;
            }
            100% {
                transform: translate(-50%, -50%) scale(5);
                opacity: 0;
            }
        }

    </style>
</head>
<body>
<div id="container"></div>
<script src="https://mapgl.2gis.com/api/js/v1"></script>
<script>
    const map = new mapgl.Map('container', {
        center: [55.280, 25.249],
        zoom: 14,
        key: 'Your API access key',
    });
    const route  = `55.280324 25.249851,55.272991 25.239421,55.278568 25.235182,55.283162 25.246507,55.280324 25.249851`.split(',')
        .map(pair => pair.split(' ').map(Number));

    const htmlMarker = new mapgl.HtmlMarker(map, {
        coordinates: [55.323, 25.235],

        html: '<div class="marker_container"><div class="wave"></div><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 50 50">\n' +
            '    <circle cx="25" cy="25" r="25" fill="white"/>\n' +
            '</svg></div>\n',
    });

    function interpolateCoordinates(coord1, coord2, t) {
        return [
            coord1[0] + (coord2[0] - coord1[0]) * t,
            coord1[1] + (coord2[1] - coord1[1]) * t,
        ];
    }

    function animateCourier(marker, route, durationPerSegment) {
        let segmentIndex = 0;

        function animateSegment(startTime) {
            const elapsedTime = performance.now() - startTime;
            const t = elapsedTime / durationPerSegment;

            if (t < 1) {
                const newCoords = interpolateCoordinates(
                    route[segmentIndex],
                    route[segmentIndex + 1],
                    t
                );
                marker.setCoordinates(newCoords);
                requestAnimationFrame(() => animateSegment(startTime));
            } else {
                segmentIndex++;
                if (segmentIndex < route.length - 1) {
                    animateSegment(performance.now());
                } else {
                    segmentIndex = 0;
                    animateSegment(performance.now());
                }
            }
        }

        if (route.length > 1) {
            animateSegment(performance.now());
        }
    }

    const durationPerSegment = 2000;
    animateCourier(htmlMarker, route, durationPerSegment);

    window.addEventListener('unload', () => map.destroy());
</script>
</body>
</html>

You can animate an HTML marker with Lottie:

  1. Add Lottie:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.0/lottie.min.js"></script>
    
  2. Create an HTML marker:

    const markerHtml = `
            <div class="marker_container">
                <div class="lottie_animation" id="lottie"></div>
            </div>
        `;
    
    const htmlMarker = new mapgl.HtmlMarker(map, {
        coordinates: [55.280324, 25.249851],
        html: markerHtml,
    });
    
  3. Create a Lottie animation:

// Using MutationObserver to track the appearance of the element
// Alternatively, you can use setTimeout with a value of 0
const observer = new MutationObserver(() => {
    const lottieContainer = document.getElementById('lottie');
    if (lottieContainer) {
        observer.disconnect(); // Stop observing once the element is found
        lottie.loadAnimation({
            container: lottieContainer, // Container ID
            renderer: 'svg',
            loop: true,
            autoplay: true,
            path: '<your>.json', // Path to the JSON file
        });
    }
});

observer.observe(document.body, { childList: true, subtree: true });
<!DOCTYPE html>
<html lang="en">
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.0/lottie.min.js"></script>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>2GIS Map API - Lottie Animation</title>
    <style>
        html, body, #container {
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
        .marker_container {
            right: 20px;
            bottom: 20px;
            position: relative;
            width: 40px;
            height: 40px;
        }
        .lottie_animation {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
<div id="container"></div>
<script src="https://mapgl.2gis.com/api/js/v1"></script>
<script>
    const map = new mapgl.Map('container', {
        center: [55.280, 25.249],
        zoom: 14,
        key: 'Your API access key',
    });

    const markerHtml = `
        <div class="marker_container">
            <div class="lottie_animation" id="lottie"></div>
        </div>
    `;

    const htmlMarker = new mapgl.HtmlMarker(map, {
        coordinates: [55.280324, 25.249851],
        html: markerHtml,
    });

    const observer = new MutationObserver(() => {
        const lottieContainer = document.getElementById('lottie');
        if (lottieContainer) {
            observer.disconnect();
            lottie.loadAnimation({
                container: lottieContainer,
                renderer: 'svg',
                loop: true,
                autoplay: true,
                path: 'https://lottie.host/7401522f-2d8b-4049-ad18-eb0edb6af224/CE9lFrNlEH.json',
            });
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    window.addEventListener('unload', () => map.destroy());
</script>
</body>
</html>