Navigation | Directions API | Examples | Urbi Documentation
Directions API

By default, the server returns the shortest car route in time using current traffic data. To build a specific type of route, set the type parameter in the request.

{
    "points": [
        {
            "type": "walking",
            "x": 82.93057,
            "y": 54.943207
        },
        {
            "type": "walking",
            "x": 82.945039,
            "y": 55.033879
        }
    ],
    "type": "jam"
}

Instead of current traffic data, you can build a route using statistical traffic data. To do this, specify the statistic route type and the required timestamp as Unix time in the utc parameter. Car route using statistical traffic data on December 1, 2020, 12 hours UTC.

{
    "points": [
        {
            "type": "walking",
            "x": 82.93057,
            "y": 54.943207
        },
        {
            "type": "walking",
            "x": 82.945039,
            "y": 55.033879
        }
    ],
    "type": "statistic",
    "utc": 1606826131
}

To build the shortest route in distance, even if it is not the fastest one, specify the shortest route type.

{
    "points": [
        {
            "type": "walking",
            "x": 82.93057,
            "y": 54.943207
        },
        {
            "type": "walking",
            "x": 82.945039,
            "y": 55.033879
        }
    ],
    "type": "shortest"
}

You can also include public transport lanes when building a car route, which can be useful for taxi and bus routes. To do this, add the "taxi_" prefix to the required route type: taxi_jam, taxi_statistic, taxi_shortest.

{
    "points": [
        {
            "type": "walking",
            "x": 82.93057,
            "y": 54.943207
        },
        {
            "type": "walking",
            "x": 82.945039,
            "y": 55.033879
        }
    ],
    "type": "taxi_jam"
}

For emergency vehicles, the following changes will be made when building a route:

  • Driving in the opposite direction on one-way roads is allowed.
  • Frontage roads can be used to bypass traffic congestion.
  • Speed limit signs and other speed limitations are ignored.

To build an emergency route, specify the emergency route type.

{
    "points": [
        {
            "type": "walking",
            "x": 82.93057,
            "y": 54.943207
        },
        {
            "type": "walking",
            "x": 82.945039,
            "y": 55.033879
        }
    ],
    "type": "emergency"
}

To build a pedestrian route, specify the pedestrian route type.

{
    "points": [
        {
            "type": "walking",
            "x": 82.93057,
            "y": 54.943207
        },
        {
            "type": "walking",
            "x": 82.945039,
            "y": 55.033879
        }
    ],
    "type": "pedestrian"
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>2GIS Directions API floors</title>
    <meta name="description" content="Using Directions API through floors plans" />
    <meta name="category" content="Directions API" />

    <style>
        html,
        body,
        #map {
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }

        .buttons {
            position: absolute;
            top: 5px;
            left: 5px;
        }

        .buttons button {
            background: #fff;
            border: none;
            border-radius: 4px;
            box-shadow: 0 1px 3px 0 rgb(38 38 38 / 50%);
            cursor: pointer;
            padding: 5px 10px;
        }

        .buttons button:hover {
            color: #777;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <div class="buttons">
        <button id="show-always">Disable dependency on floors</button>
        <button id="toggle-points">Toggle points</button>
    </div>
    <script src="https://mapgl.2gis.com/api/js/v1"></script>
    <script>
        const key = 'Your API access key';
        const directionsKey = 'Your directions API access key';

        const map = new mapgl.Map('map', {
            center: [82.89050491182851, 54.98378006147128],
            zoom: 18.5,
            key,
        });
        window.addEventListener('resize', () => map.invalidateSize());

        // Enable floor control on the right
        const floorControl = new mapgl.FloorControl(map, {
            position: 'topRight',
        });

        let showPoints = true;
        let showAlways = false;
        map.setStyleState({
            showPoints,
            showAlways,
        });
        document.querySelector('#toggle-points').addEventListener('click', () => {
            showPoints = !showPoints;
            map.setStyleState({
                showPoints,
                showAlways,
            });
        });
        document.querySelector('#show-always').addEventListener('click', (ev) => {
            showAlways = !showAlways;
            ev.target.innerHTML = showAlways
                ? 'Enable dependency on floors'
                : 'Disable dependency on floors';
            map.setStyleState({
                showPoints,
                showAlways,
            });
        });

        // Add styles for points and segments
        map.once('styleload', () => {
            const whiteLineStyle = {
                width: 9,
                color: '#fff',
            };
            const lineStyle = {
                width: 5,
                color: ['match', ['get', 'index'], [-1], '#ccc', [0], '#00ff00', [1], '#0000ff', '#ff0000'],
            };

            // Lines which are showing under houses
            const lineFilter = [
                'all',
                ['==', ['sourceAttr', 'foo'], 'bar'],
                ['==', ['get', 'type'], 'path'],
                ['==', ['global', 'showAlways'], false],
                [
                    'any',
                    ['==', ['get', 'floorId'], null],
                    ['in', ['get', 'floorId'], ['global', '_activeFloorIds']],
                ],
            ];
            map.addLayer(
                {
                    id: 'my-line-white',
                    type: 'line',
                    filter: lineFilter,
                    style: whiteLineStyle,
                },
                '344517',
            );
            map.addLayer(
                {
                    id: 'my-line',
                    type: 'line',
                    filter: lineFilter,
                    style: lineStyle,
                },
                '344517',
            );

            // Lines which are showing under houses
            const lineAboveFilter = [
                'all',
                ['==', ['sourceAttr', 'foo'], 'bar'],
                ['==', ['get', 'type'], 'path'],
                ['==', ['global', 'showAlways'], true],
            ];
            map.addLayer({
                id: 'my-line-white-above',
                type: 'line',
                filter: lineAboveFilter,
                style: whiteLineStyle,
            });
            map.addLayer({
                id: 'my-line-above',
                type: 'line',
                filter: lineAboveFilter,
                style: lineStyle,
            });

            map.addLayer({
                id: 'my-point',
                type: 'point',
                filter: [
                    'all',
                    ['global', 'showPoints'],
                    ['==', ['sourceAttr', 'foo'], 'bar'],
                    ['==', ['get', 'type'], 'point'],
                    [
                        'any',
                        ['==', ['global', 'showAlways'], true],
                        ['==', ['get', 'floorId'], null],
                        ['in', ['get', 'floorId'], ['global', '_activeFloorIds']],
                    ],
                ],
                style: {
                    iconImage: 'ent',
                    iconWidth: 15,
                    textFont: 'Noto_Sans',
                    textFontSize: 10,
                    textField: ['get', 'comment'],
                    iconPriority: 1000,
                    textPriority: 1000,
                    textHaloWidth: 1,
                    textHaloColor: '#fff',
                    allowOverlap: true,
                },
            });
            map.addLayer({
                id: 'my-point-end',
                type: 'point',
                filter: ['all', ['==', ['sourceAttr', 'foo'], 'bar'], ['==', ['get', 'type'], 'end']],
                style: {
                    iconImage: [
                        'match',
                        [
                            'any',
                            ['==', ['get', 'floorId'], null],
                            ['==', ['global', 'showAlways'], true],
                            ['in', ['get', 'floorId'], ['global', '_activeFloorIds']],
                        ],
                        [true],
                        'ent_i',
                        'ent',
                    ],
                    iconWidth: 30,
                    textFont: 'Noto_Sans_Semibold',
                    textFontSize: 14,
                    textField: ['get', 'comment'],
                    iconPriority: 2000,
                    textPriority: 2000,
                    textColor: '#fff',
                    textPlacement: 'centerCenter',
                },
            });
        });

        const points = [
            {
                type: 'pedo',
                x: 82.88828966022959,
                y: 54.983109254770376,
            },
            {
                type: 'pedo',
                x: 82.89149408367815,
                y: 54.98388809715867,
                object_id: '141265770013202',
                floor_id: '141832716803532',
            },
        ];

        fetchAndDrawRoute();

        function fetchAndDrawRoute() {
            const query = {
                type: 'pedestrian',
                points,
                use_indoor: true,
                options: ['pedestrian_instructions'],
            };

            return fetch(`https://catalog.api.2gis.ru/carrouting/6.0.0/global?key=${directionsKey}`, {
                method: 'post',
                body: JSON.stringify(query),
            })
                .then((r) => {
                    if (r.status !== 200) {
                        throw new Error(`HTTP code is ${r.status}`);
                    }
                    return r.json();
                })
                .then((r) => drawRoute(query.points, r.result && r.result[0]))
                .catch((reason) => console.error(reason));
        }

        const geojsonSource = new mapgl.GeoJsonSource(map, {
            data: {
                type: 'FeatureCollection',
                features: [],
            },
            attributes: {
                foo: 'bar',
            },
        });

        function drawRoute(points, result) {
            if (!result) {
                return;
            }

            const data = {
                type: 'FeatureCollection',
                features: [
                    {
                        type: 'Feature',
                        properties: {
                            type: 'end',
                            comment: 'A',
                            floorId: points[0].floor_id,
                        },
                        geometry: {
                            type: 'Point',
                            coordinates: [points[0].x, points[0].y],
                        },
                    },
                    {
                        type: 'Feature',
                        properties: {
                            type: 'end',
                            comment: 'B',
                            floorId: points[1].floor_id,
                        },
                        geometry: {
                            type: 'Point',
                            coordinates: [points[1].x, points[1].y],
                        },
                    },
                ],
            };

            let colorIndex = 0;
            let isFirstSegmentAdded = false;
            let lastPoint = {
                coordinates: [points[0].x, points[0].y],
                floorId: points[0].floor_id,
            };

            result.maneuvers.forEach((maneuver) => {
                if (maneuver.outcoming_path && maneuver.outcoming_path.geometry.length) {
                    const firstCoord = parserLineStringWKT(
                        maneuver.outcoming_path.geometry[0].selection,
                    )[0];

                    if (maneuver.comment) {
                        data.features.push({
                            type: 'Feature',
                            properties: {
                                type: 'point',
                                comment: maneuver.comment,
                                floorId: maneuver.outcoming_path.floor_from,
                            },
                            geometry: {
                                type: 'Point',
                                coordinates: firstCoord,
                            },
                        });
                    }

                    if (!isFirstSegmentAdded) {
                        isFirstSegmentAdded = true;
                        data.features.push({
                            type: 'Feature',
                            properties: {
                                type: 'path',
                                index: -1,
                                floorId: maneuver.outcoming_path.floor_from,
                            },
                            geometry: {
                                type: 'LineString',
                                coordinates: [[points[0].x, points[0].y], firstCoord],
                            },
                        });
                    }

                    maneuver.outcoming_path.geometry.forEach((geometry) => {
                        const coordinates = parserLineStringWKT(geometry.selection);
                        data.features.push({
                            type: 'Feature',
                            properties: {
                                type: 'path',
                                index: colorIndex++ % 3,
                                floorId: maneuver.outcoming_path.floor_to,
                            },
                            geometry: {
                                type: 'LineString',
                                coordinates,
                            },
                        });
                        lastPoint = {
                            coordinates: coordinates[coordinates.length - 1],
                            floorId: maneuver.outcoming_path.floor_to,
                        };
                    });
                } else if (maneuver.comment) {
                    data.features.push({
                        type: 'Feature',
                        properties: {
                            type: 'point',
                            comment: maneuver.comment,
                            floorId: lastPoint.floorId,
                        },
                        geometry: {
                            type: 'Point',
                            coordinates: lastPoint.coordinates,
                        },
                    });
                }
            });

            if (lastPoint) {
                data.features.push({
                    type: 'Feature',
                    properties: {
                        type: 'path',
                        floorId: lastPoint.floorId,
                        index: -1,
                    },
                    geometry: {
                        type: 'LineString',
                        coordinates: [lastPoint.coordinates, [points[1].x, points[1].y]],
                    },
                });
            }

            geojsonSource.setData(data);
        }

        map.on('click', (event) => {
            if (event.targetData?.floorId) {
                points.push({
                    type: 'pedo',
                    x: event.lngLat[0],
                    y: event.lngLat[1],
                    floor_id: event.targetData.floorId,
                    object_id: event.targetData.id,
                });
            } else {
                points.push({
                    type: 'pedo',
                    x: event.lngLat[0],
                    y: event.lngLat[1],
                });
            }

            points.splice(0, 1);
            fetchAndDrawRoute();
        });

        function parserLineStringWKT(wkt) {
            return wkt
                .slice('LINESTRING('.length, -1)
                .split(',')
                .map((c) => c.trim().split(' ').map(Number));
        }
    </script>
</body>

</html>

To build a pedestrian route inside buildings, specify the parameters "use_indoor": true and "options": ["pedestrian_instructions"]. At least one of the starting or ending points must be inside a building or be bound to a building using the object_id parameter.

You can specify the floor ID for a point using the floor_id parameter.

{
    "points": [
        {
            "type": "walking",
            "x": 82.891385,
            "y": 54.983477,
            "object_id": "70000001057266023",
            "floor_id": "141832716803532"
        },
        {
            "type": "walking",
            "x": 82.897328,
            "y": 54.980198,
            "floor_id": "70030076256452036"
        }
    ],
    "type": "pedestrian",
    "use_indoor": true,
    "options": ["pedestrian_instructions"]
}

The response will include an indoors route based on the floor plans of the buildings, as well as pedestrian navigation instructions: entrances and exits of buildings, movements between floors by elevators, escalators, or stairs.

To build a bicycle route, specify the bicycle route type.

{
    "points": [
        {
            "type": "walking",
            "x": 82.93057,
            "y": 54.943207
        },
        {
            "type": "walking",
            "x": 82.945039,
            "y": 55.033879
        }
    ],
    "type": "bicycle"
}

By default, bicycle routes include stairways, overground crossings, underground crossings, and car roads. You can exclude them from the route by using the filters parameter (see Avoiding road types).

If the starting or ending point of a car route is not located on a road, a path will be added to the route connecting it with the nearest road. You can adjust this by using one of two point types for the start or end point:

  • walking - add a pedestrian path avoiding all obstacles such as buildings
  • stop - add a simple straight path that ignores all obstacles
"points": [
   {
       "type": "walking",
       "x": 82.93057,
       "y": 54.943207
   },
   {
       "type": "walking",
       "x": 82.945039,
       "y": 55.033879
   }
]

For any type of route, you can set several start and end points, which can be useful, for example, if a building has multiple entrances or exits. When multiple points are specified, only one of them (the most convenient) will be used to build an optimal route.

To separate start and end points in the points array, you can use the start parameter or add intermediate points to the route (see the next section).

"points": [
   {
       "type": "stop",
       "x": 82.93057,
       "y": 54.943207,
       "start": true
   },
   {
       "type": "stop",
       "x": 82.93856,
       "y": 54.943112,
       "start": true
   },
   {
       "type": "stop",
       "x": 82.945039,
       "y": 55.033879
   }
]

You can add intermediate points to any route by using the pref point type. The total number of route points must not exceed 10.

"points": [
   {
       "type": "walking",
       "x": 82.93057,
       "y": 54.943207
   },
   {
       "type": "pref",
       "x": 82.941984,
       "y": 54.974563
   },
   {
       "type": "walking",
       "x": 82.945039,
       "y": 55.033879
   }
]

When building a route, you can exclude certain types of roads, such as dirt roads and toll roads (for a car route) or stairways and overground/underground crossings (for a bicycle route). To do this, use the filters parameter.

For example, to exclude dirt roads from a car route, specify the value "dirt_road":

{
    "points": [...],
    "filters": ["dirt_road"]
}

To exclude stairways, overground crossings, underground crossings, and car roads from a bicycle route, specify the following array of values:

{
    "points": [...],
    "type": "bicycle",
    "filters": [
        "ban_stairway",
        "ban_over",
        "ban_car_road"
    ]
}

If the route without the specified road types is too long or impossible to build, parts of the resulting route may still include the excluded road types.

You can also exclude certain types of roads from a pedestrian route. For a complete list of possible values, see API Reference.

To exclude specific areas from the route, use the exclude parameter.

Maximum 25 areas can be excluded.

Areas can be specified as circles, polygons, or thick lines. To specify an area, use the following parameters:

  • type - shape of the area (circle, polygon, or line)
  • points - coordinates of the area
  • extent - area size in meters (radius of a circle, width of a line)
{
    "points": [...],
    "exclude": [
        {
            "type": "point",
            "points": [
                {
                    "x": 82.03057,
                    "y": 54.043207
                }
            ],
            "extent": 100
        },
        {
            "type": "polyline",
            "points": [
                {
                    "x": 82.13057,
                    "y": 54.143207
                },
                {
                    "x": 82.23057,
                    "y": 54.243207
                }
            ],
            "extent": 1000
        }
    ]
}

For each area, you can additionally specify the severity parameter, which determines how strictly the area should be avoided: if possible (soft) or always (hard).

{
    "points": [...],
    "exclude": [
        {
            "type": "polygon",
            "points": [
                {"x": 55.28770929, "y": 25.22069944},
                {"x": 55.28976922, "y": 25.25656786},
                {"x": 55.33302789, "y": 25.25687836},
                {"x": 55.33096795, "y": 25.22007825},
                {"x": 55.28770929, "y": 25.22069944}
            ],
            "severity": "hard"
        }
    ]
}

To get altitude information, specify the need_altitudes parameter.

{
    "points": [...],
    "need_altitudes": true
}

If this parameter is specified, the response will contain the following information:

  • Total elevation gain and loss (in centimeters).
  • Maximum and minimum altitude on the route (height above sea level in centimeters).
  • Maximum elevation angle on the route.
  • Elevation angle and altitude for each segment of the route.
{
    "altitudes_info": {
        "elevation_gain": 12440,
        "elevation_loss": 11020,
        "max_altitude": 10700,
        "min_altitude": 6600,
        "max_road_angle": 8
    },
    "geometry": [
        {
            // Elevation angle.
            "angles": "LINESTRING(1, -1)",
            "color": "ignore",
            "length": 22,
            // Third value is the altitude.
            "selection": "LINESTRING(82.930722 54.943655 9200, 82.930815 54.943650 9220, 82.930926 54.943640 9190)",
            "style": "normal"
        }
    ]
}

In some cases, the route may contain special types of points, which will be listed in the route_points field. For example, if the route includes a toll road segment, route_points will contain information about the starting and ending points of that segment.

{
    "route_points": [
        {
            // Point coordinates.
            "coordinates": {
                "lat": 55.73942822546596,
                "lon": 37.37259908712576
            },
            // Distance from the start of the route (in meters).
            "distance": 746,
            // Special point type.
            "type": "TollRoadBegin"
        },
        {
            "coordinates": {
                "lat": 55.71525675255834,
                "lon": 37.31850882892307
            },
            "distance": 5784,
            "type": "TollRoadEnd"
        }
    ]
}