Skip to content

Measure Distances in Maptoolkit Maps JS

Measuring distances on a map combines click event handling, GeoJSON source updates, and Turf.js’s length function. Each click adds a new point to the measurement path, and the total geodesic distance is recalculated and displayed after every click. Use this as a base for route planning tools, field measurement utilities, or any feature that lets users draw and measure paths on the map.

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');

    const geojson = { type: 'FeatureCollection', features: [] };
    const linestring = { type: 'Feature', geometry: { type: 'LineString', coordinates: [] } };

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

        map.addLayer({ id: 'measure-points', type: 'circle', source: 'geojson',
            paint: { 'circle-radius': 5, 'circle-color': '#ee8a65' },
            filter: ['==', '$type', 'Point']
        });

        map.addLayer({ id: 'measure-lines', type: 'line', source: 'geojson',
            paint: { 'line-color': '#888', 'line-width': 2.5, 'line-dasharray': [3, 2] },
            filter: ['==', '$type', 'LineString']
        });

        map.on('click', (e) => {
            const point = { type: 'Feature', geometry: { type: 'Point', coordinates: [e.lngLat.lng, e.lngLat.lat] } };
            if (geojson.features.length > 1) geojson.features.pop();
            geojson.features.push(point);

            if (geojson.features.length > 1) {
                linestring.geometry.coordinates = geojson.features.map(f => f.geometry.coordinates);
                geojson.features.push(linestring);
                const dist = turf.length(linestring, { units: 'kilometers' });
                document.getElementById('distance').textContent = `Distance: ${dist.toFixed(2)} km`;
            }

            map.getSource('geojson').setData(geojson);
        });

        map.on('mouseenter', 'measure-points', () => { map.getCanvas().style.cursor = 'crosshair'; });
        map.on('mouseleave', 'measure-points', () => { map.getCanvas().style.cursor = ''; });
        map.getCanvas().style.cursor = 'crosshair';
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Measure Distances - Maptoolkit Maps JS</title>
    <meta property="og:description" content="Click the map to place points and measure the distance between them using Turf.js." />
    <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" />
    <script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
    <style>
        html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
        #map { width: 100%; height: 100%; }
        #distance {
            position: absolute;
            top: 10px;
            left: 10px;
            background: white;
            padding: 10px 14px;
            border-radius: .4rem;
            font-family: sans-serif;
            font-size: 14px;
        }
    </style>
</head>
<body>
<div id="map"></div>
<div id="distance">Click to add points and measure distance</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');

    const geojson = { type: 'FeatureCollection', features: [] };
    const linestring = { type: 'Feature', geometry: { type: 'LineString', coordinates: [] } };

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

        map.addLayer({ id: 'measure-points', type: 'circle', source: 'geojson',
            paint: { 'circle-radius': 5, 'circle-color': '#ee8a65' },
            filter: ['==', '$type', 'Point']
        });

        map.addLayer({ id: 'measure-lines', type: 'line', source: 'geojson',
            paint: { 'line-color': '#888', 'line-width': 2.5, 'line-dasharray': [3, 2] },
            filter: ['==', '$type', 'LineString']
        });

        map.on('click', (e) => {
            const point = { type: 'Feature', geometry: { type: 'Point', coordinates: [e.lngLat.lng, e.lngLat.lat] } };
            if (geojson.features.length > 1) geojson.features.pop();
            geojson.features.push(point);

            if (geojson.features.length > 1) {
                linestring.geometry.coordinates = geojson.features.map(f => f.geometry.coordinates);
                geojson.features.push(linestring);
                const dist = turf.length(linestring, { units: 'kilometers' });
                document.getElementById('distance').textContent = `Distance: ${dist.toFixed(2)} km`;
            }

            map.getSource('geojson').setData(geojson);
        });

        map.on('mouseenter', 'measure-points', () => { map.getCanvas().style.cursor = 'crosshair'; });
        map.on('mouseleave', 'measure-points', () => { map.getCanvas().style.cursor = ''; });
        map.getCanvas().style.cursor = 'crosshair';
    });
</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]. Allow clicking to place points and measure the distance between them, displaying the total distance in kilometers.

How it works

Three pieces: clicks collect coordinates, a GeoJSON source holds them, and Turf.js measures the line.

Each click pushes a point into the collection, rebuilds the LineString from every point so far, and calls setData. The whole source is replaced each time rather than appended to, because a GeoJSON source has no incremental update path.

Distance comes from turf.length, which measures along the great circle rather than in screen space. The number is the distance over the ground, and it does not change as you zoom.

Clicking an existing point removes it, which is why the click handler checks for a hit before adding. Without that, points can only ever be added.

Two layers draw one source: circle for the points and line for the segments between them. A single layer cannot do both.

This measures straight lines between points. For distance along a road, the Routing API returns the real travelled distance instead.

Next steps

Distance is the first measurement people want and rarely the last. Area for a drawn polygon and the bearing of each leg are the usual additions, and both come from the same click-collected coordinates.

If the line is meant to be travelled rather than spanned, the Routing API returns the real distance along roads and paths, which is a different and usually larger number than the straight line this measures.