Типы маршрутов
Кратчайший по времени
По умолчанию прокладывается кратчайший по времени автомобильный маршрут с учётом текущих пробок. Чтобы указать тип маршрута явно, нужно добавить в запрос поле type
.
{
"points": [
{
"type": "walking",
"x": 82.93057,
"y": 54.943207
},
{
"type": "walking",
"x": 82.945039,
"y": 55.033879
}
],
"type": "jam"
}
Маршрут на определенное время
Вместо текущих пробок можно использовать статистическую информацию по пробкам. Для этого нужно указать тип маршрута statistic
и нужную дату-время в виде Unix-времени в поле utc
. Например, автомобильный маршрут на основе статистических данных по пробкам на 1 декабря 2020 года, 12 часов UTC.
{
"points": [
{
"type": "walking",
"x": 82.93057,
"y": 54.943207
},
{
"type": "walking",
"x": 82.945039,
"y": 55.033879
}
],
"type": "statistic",
"utc": 1606826131
}
Кратчайший по расстоянию
Чтобы построить самый короткий маршрут, даже если он не является оптимальным по времени, нужно указать тип shortest
.
{
"points": [
{
"type": "walking",
"x": 82.93057,
"y": 54.943207
},
{
"type": "walking",
"x": 82.945039,
"y": 55.033879
}
],
"type": "shortest"
}
С учётом полос общественного транспорта
Также можно строить маршруты с учётом полос общественного транспорта (удобно для такси и автобусов). Для этого нужно к выбранному типу маршрута добавить префикс "taxi_": 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"
}
Маршрут для экстренных служб
При использовании маршрутов для экстренных служб вносятся следующие изменения:
- разрешается движение по односторонним дорогам в противоположном направлении;
- разрешается использование проездов-дублёров;
- снимаются ограничения скорости движения (игнорируются знаки ограничения скорости).
Чтобы построить такой маршрут, нужно указать тип emergency
.
{
"points": [
{
"type": "walking",
"x": 82.93057,
"y": 54.943207
},
{
"type": "walking",
"x": 82.945039,
"y": 55.033879
}
],
"type": "emergency"
}
Пешеходный
Чтобы проложить пешеходный маршрут, нужно указать тип pedestrian
.
{
"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>
Чтобы построить пешеходный маршрут внутри зданий с поэтажными планами, нужно указать параметры "use_indoor": true
и "options": ["pedestrian_instructions"]
. При этом хотя бы одна из конечных точек маршрута должна находиться внутри здания или быть привязана к зданию с помощью параметра object_id
.
Идентификатор этажа для точки можно указать при помощи параметра floor_id
.
{
"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"]
}
Ответ будет содержать маршрут, построенный на основе этажных схем зданий, а также инструкции по пешеходной навигации: входы и выходы из зданий, перемещение между этажами на лифте, эскалаторе или по лестнице.
Велосипедный
Чтобы проложить велосипедный маршрут, нужно указать тип bicycle
.
{
"points": [
{
"type": "walking",
"x": 82.93057,
"y": 54.943207
},
{
"type": "walking",
"x": 82.945039,
"y": 55.033879
}
],
"type": "bicycle"
}
По умолчанию велосипедные маршруты включают лестницы, автомобильные дороги, подземные и надземные переходы. Чтобы их исключить, можно указать параметр filters
(см. Исключение типов дорог).
Типы точек
Начальные и конечные точки
Если начальная или конечная точка автомобильного маршрута расположена не на дороге, то в маршрут будет добавлен путь, соединяющий её с ближайшей дорогой. Для этого можно использовать два типа точек:
walking
- будет добавлен путь с обходом препятствий, таких как здания (пешеходный);stop
- будет добавлен прямой путь, игнорирующий препятствия.
"points": [
{
"type": "walking",
"x": 82.93057,
"y": 54.943207
},
{
"type": "stop",
"x": 82.945039,
"y": 55.033879
}
]
Для любого типа маршрута можно указать несколько начальных и конечных точек. Это может быть удобно в тех случаях, когда у здания есть несколько входов и выходов. При указании нескольких точек будет построен оптимальный маршрут от одной из начальных точек до одной из конечных.
Чтобы отделить начальные точки от конечных в массиве points
, можно использовать параметр start
или добавить промежуточные точки (см. следующий раздел).
"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
}
]
Промежуточные точки
В любой маршрут можно добавить промежуточные точки, указав тип pref
. Общее количество точек в маршруте не должно превышать 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
}
]
Исключение типов дорог
При построении маршрута можно исключить определенные типы дорог, такие как грунтовые и платные (для автомобильного маршрута) или лестницы и переходы (для велосипедного маршрута). Чтобы это сделать, нужно указать в запросе поле filters
.
Например, чтобы исключить грунтовые дороги из автомобильного маршрута, нужно указать значение "dirt_road":
{
"points": [...],
"filters": ["dirt_road"]
}
Чтобы исключить лестницы, подземные/надземные переходы и автомобильные дороги из велосипедного маршрута, нужно указать следующий массив значений:
{
"points": [...],
"type": "bicycle",
"filters": [
"ban_stairway",
"ban_over",
"ban_car_road"
]
}
Если маршрут без указанных типов дорог получается слишком длинным или его невозможно построить, часть получившегося маршрута может включать исключённые типы дорог.
Также можно исключить некоторые типы дорог из пешеходного маршрута. Полный список возможных значений можно найти в Справочнике API.
Исключение областей
В запросе можно указать области, которые будут избегаться при построении маршрута. Для этого используется поле exclude
.
Максимальное количество исключаемых областей - 25.
Область можно указать в виде круга, многоугольника или толстой линии. Для описания области используется три параметра:
type
- форма исключаемой области (круг, многоугольник или линия);points
- координаты области;extent
- размер области в метрах (радиус круга или ширина линии).
{
"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
}
]
}
Для каждой области можно дополнительно указать параметр severity
- насколько строго нужно избегать выбранную область (soft
- избегать по возможности; 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"
}
]
}
Информация о высоте
Чтобы получить информацию о высоте маршрута и её изменении на протяжении маршрута, нужно указать параметр need_altitudes
.
{
"points": [...],
"need_altitudes": true
}
При указании этого параметра ответ будет содержать следующую информацию:
- Суммарное увеличение и снижение высоты (в сантиметрах).
- Максимальная и минимальная высота над уровнем моря (в сантиметрах).
- Максимальный угол наклона.
- Угол наклона и высота над уровнем моря для каждого сегмента маршрута.
{
"altitudes_info": {
// Суммарное увеличение высоты.
"elevation_gain": 12440,
// Суммарное снижение высоты.
"elevation_loss": 11020,
// Максимальная высота над уровнем моря.
"max_altitude": 10700,
// Минимальная высота над уровнем моря.
"min_altitude": 6600,
// Максимальный угол наклона.
"max_road_angle": 8
},
"geometry": [
{
// Угол наклона.
"angles": "LINESTRING(1, -1)",
"color": "ignore",
"length": 22,
// Высота над уровнем моря (третье значение).
"selection": "LINESTRING(82.930722 54.943655 9200, 82.930815 54.943650 9220, 82.930926 54.943640 9190)",
"style": "normal"
}
]
}
Специальные точки
В некоторых случаях ответ может содержать дополнительное поле route_points
, в котором будут перечислены специальные типы точек, встречающиеся на маршруте. Например, если маршрут включает проезд по платной дороге, поле route_points
будет содержать координаты начальной и конечной точек платного участка.
{
"route_points": [
{
// Координаты точки.
"coordinates": {
"lat": 55.73942822546596,
"lon": 37.37259908712576
},
// Расстояние от начала маршрута (в метрах).
"distance": 746,
// Тип специальной точки.
"type": "TollRoadBegin"
},
{
"coordinates": {
"lat": 55.71525675255834,
"lon": 37.31850882892307
},
"distance": 5784,
"type": "TollRoadEnd"
}
]
}