Skip to content
Fit to the Bounds of a LineString

Fit to the Bounds of a LineString in Maptoolkit Maps JS

To show an entire route or path on the map, you calculate the bounding box of the LineString using Turf.js’s bbox function and pass the result to map.fitBounds. This ensures the full line is visible regardless of its length or orientation. Use this when displaying routes, tracks, or any linear feature where the user should see the whole path at once before exploring in detail.

const API_KEY = 'YOUR_API_KEY';

    const geojson = {
        type: 'FeatureCollection',
        features: [{
            type: 'Feature',
            geometry: {
                type: 'LineString',
                properties: {},
                coordinates: [
                    [-77.0366048812866,  38.89873175227713],
                    [-77.03364372253417, 38.89876515143842],
                    [-77.03364372253417, 38.89549195896866],
                    [-77.02982425689697, 38.89549195896866],
                    [-77.02400922775269, 38.89387200688839],
                    [-77.01519012451172, 38.891416957534204],
                    [-77.01521158218382, 38.892068305429156],
                    [-77.00813055038452, 38.892051604275686],
                    [-77.00832366943358, 38.89143365883688],
                    [-77.00818419456482, 38.89082405874451],
                    [-77.00815200805664, 38.88989712255097]
                ]
            }
        }]
    };

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

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

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

        map.addLayer({
            id: 'LineString',
            type: 'line',
            source: 'LineString',
            layout: {
                'line-join': 'round',
                'line-cap': 'round'
            },
            paint: {
                'line-color': '#BF93E4',
                'line-width': 5
            }
        });

        document.getElementById('zoomto').addEventListener('click', () => {
            const coordinates = geojson.features[0].geometry.coordinates;

            // Calculate the bounding box of the LineString
            const bounds = coordinates.reduce((bounds, coord) => {
                return bounds.extend(coord);
            }, new maptoolkit.LngLatBounds(coordinates[0], coordinates[0]));

            map.fitBounds(bounds, { padding: 20 });
        });
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Fit to the Bounds of a LineString - Maptoolkit Maps JS</title>
    <meta property="og:description" content="Fit the map view to the bounding box of a GeoJSON LineString." />
    <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%; }
        .btn-control {
            font: bold 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
            background-color: #3386c0;
            color: #fff;
            position: absolute;
            top: 20px;
            left: 50%;
            z-index: 1;
            border: none;
            width: 200px;
            margin-left: -100px;
            display: block;
            cursor: pointer;
            padding: 10px 20px;
            border-radius: 3px;
        }
        .btn-control:hover { background-color: #4ea0da; }
    </style>
</head>
<body>
<div id="map"></div>
<button id="zoomto" class="btn-control">Zoom to bounds</button>
<script>
    const API_KEY = 'YOUR_API_KEY';

    const geojson = {
        type: 'FeatureCollection',
        features: [{
            type: 'Feature',
            geometry: {
                type: 'LineString',
                properties: {},
                coordinates: [
                    [-77.0366048812866,  38.89873175227713],
                    [-77.03364372253417, 38.89876515143842],
                    [-77.03364372253417, 38.89549195896866],
                    [-77.02982425689697, 38.89549195896866],
                    [-77.02400922775269, 38.89387200688839],
                    [-77.01519012451172, 38.891416957534204],
                    [-77.01521158218382, 38.892068305429156],
                    [-77.00813055038452, 38.892051604275686],
                    [-77.00832366943358, 38.89143365883688],
                    [-77.00818419456482, 38.89082405874451],
                    [-77.00815200805664, 38.88989712255097]
                ]
            }
        }]
    };

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

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

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

        map.addLayer({
            id: 'LineString',
            type: 'line',
            source: 'LineString',
            layout: {
                'line-join': 'round',
                'line-cap': 'round'
            },
            paint: {
                'line-color': '#BF93E4',
                'line-width': 5
            }
        });

        document.getElementById('zoomto').addEventListener('click', () => {
            const coordinates = geojson.features[0].geometry.coordinates;

            // Calculate the bounding box of the LineString
            const bounds = coordinates.reduce((bounds, coord) => {
                return bounds.extend(coord);
            }, new maptoolkit.LngLatBounds(coordinates[0], coordinates[0]));

            map.fitBounds(bounds, { padding: 20 });
        });
    });
</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 [-77.0214, 38.897]. Draw a LineString route through Washington DC and add a button that fits the map to its bounds.

How it works

fitBounds needs a rectangle, and a route is a line, so the bounding box has to be computed first. turf.bbox returns [minX, minY, maxX, maxY], which is west, south, east, north.

The order is the thing to get right: fitBounds wants [[west, south], [east, north]], so the flat Turf array is reshaped into two corners rather than passed straight through.

This is the natural follow-up to drawing a route from the Routing API, whose geometry arrives as an encoded polyline you decode into coordinates first.

padding matters more for routes than for areas, since a line fitted exactly runs into the container edge at both ends.

Next steps

The natural next step is fitting a route the user actually asked for. The Routing API returns the geometry, and fitting it is what should happen the moment a route comes back.

Refitting when the container resizes is the detail that is easy to miss: a route framed on a desktop is cropped on a phone, and the fit has to be recomputed rather than the camera restored.