Документация
Техническое описание встраивания виджета и серверного API. Актуальная версия виджета: 1.5.0 (неверсионированный karty.js всегда указывает на последнюю).
Способы встраивания
Способ 1 — одна строка JS
<div id="map" style="width:100%; height:400px;"></div>
<script src="https://kartrout.ru/widget/karty.js"></script>
<script>
Karty.map('map', {
key: 'ВАШ_КЛЮЧ', // публичный ключ (pk_live_...), выдаётся в личном кабинете
style: 'warm', // тема оформления: warm | light | dark | white | grayscale | black
center: [37.6173, 55.7558], // [долгота, широта]
zoom: 12
});
</script>
Способ 2 — совсем без JavaScript
Просто добавьте <div> с нужными атрибутами — карта появится сама после загрузки страницы:
<div class="map-box" style="width:100%; height:400px;"
data-karty-map
data-karty-key="ВАШ_КЛЮЧ"
data-karty-style="warm"
data-karty-lon="37.6173"
data-karty-lat="55.7558"
data-karty-zoom="12"
data-karty-search></div>
<script src="https://kartrout.ru/widget/karty.js"></script>
data-karty-search — необязательный атрибут, добавляет поле поиска по адресу в левый верхний угол карты.
Метки и кластеризация
Одна метка:
const map = Karty.map('map', { key: 'ВАШ_КЛЮЧ' });
map.onReady(() => {
map.addMarker([37.62, 55.75], { popupHtml: '<b>Наш офис</b><br>ул. Примерная, 1' });
});
Для десятков-сотен точек addMarker() в цикле не подходит — каждая метка живёт как отдельный HTML-элемент, браузер начинает тормозить уже на паре сотен. Для больших наборов — setMarkers(), рисует точки как слой карты и группирует их в кружки-кластеры при отдалении:
const handle = map.setMarkers(
[
{ lngLat: [83.76, 53.35], name: 'Точка А' },
{ lngLat: [83.77, 53.36], name: 'Точка Б' },
],
{
cluster: true, // по умолчанию true
popupHtml: (item) => `<b>${item.name}</b>`,
onClick: (item) => console.log('кликнули', item.name),
}
);
handle.update(newItems); // заменить весь набор точек
handle.remove(); // убрать с карты
Сохранённый набор точек (загрузка по ссылке)
Если точек сотни или тысячи (список судов, магазинов, пунктов выдачи по всей России) и хранить их у себя на странице неудобно — можно хранить набор у нас и ссылаться на него по id:
map.loadPoints('ВАШ_ID_НАБОРА'); // GET /v1/points/{id}, дальше рисует как setMarkers()
Или без JS — атрибут на том же <div>:
<div data-karty-map data-karty-key="ВАШ_КЛЮЧ" data-karty-points="ВАШ_ID_НАБОРА"></div>
Названия точек всегда показываются как обычный текст в попапе, не HTML — набор может быть загружен через импорт чужих данных. Запрос /v1/points/{id} не расходует квоту — набор тарифицируется количеством точек в нём, не количеством показов на странице.
Тепловая карта плотности
const heat = map.setHeatmap(
[
{ lngLat: [83.76, 53.35], weight: 1 },
{ lngLat: [83.77, 53.36], weight: 2.5 },
],
{ radiusMeters: 400 }
);
heat.update(newPoints);
heat.remove();
radiusMeters — радиус в метрах на земле, не в пикселях экрана. Интенсивность подбирается автоматически по фактической плотности точек; своя — через { intensity: 2 }.
Поиск по адресу
map.attachSearch({
placeholder: 'Введите адрес…',
onResult: (result) => console.log(result.display_name, result.lat, result.lon),
});
Поиск запускается по Enter, не на каждое нажатие клавиши. До 5 вариантов в выпадающем списке, ARIA combobox для скринридеров. Автодополнение «по мере набора» (пилот, Алтайский край): map.attachSearch({ autocomplete: true }).
Построение маршрута
map.onReady(() => {
map.route([37.62, 55.75], [37.60, 55.76])
.then((route) => console.log(route.distance, route.duration))
.catch((err) => console.error(err.message));
});
Зоны доступности (изохроны) — пилот, Алтайский край
map.onReady(() => {
map.isochrone([83.76, 53.35], { minutes: [5, 10, 15], costing: 'auto' })
.then((geojson) => console.log(geojson.features.length, 'зон'))
.catch((err) => console.error(err.message));
});
costing: auto (по умолчанию), pedestrian, bicycle, truck. До трёх контуров за раз, каждый не больше 60 минут. Ориентировочно, без учёта пробок — по ограничениям скорости дорог.
Население внутри зоны (опционально): GET /v1/isochrone?...&population=1 добавляет в каждый контур поля population, populationSource, populationYear, populationAttribution — оценка по открытому растру WorldPop.org (ячейка около 1 км, CC BY 4.0).
Матрица расстояний — серверный API, требует secret-ключ
curl -H "Authorization: Bearer sk_live_..." \
"https://kartrout.ru/v1/matrix/driving/83.76,53.36;83.75,53.35;83.74,53.34"
До 25 точек в запросе. Квота считается по числу ячеек матрицы (источники × назначения), не по числу запросов — 25×25 стоит как 625 обычных запросов.
Пакетный геокодинг — серверный API, требует secret-ключ
curl -X POST "https://kartrout.ru/v1/geocode/batch" \
-H "Authorization: Bearer sk_live_..." \
-d '{"queries": ["проспект Ленина 1, Барнаул", "улица Гагарина 2"]}'
До 50 адресов за вызов, каждый не длиннее 200 символов. Один не найденный адрес не валит весь пакет. Квота — по количеству адресов в пачке, как обычный геокодинг.
Оптимизация маршрутов (мультистоп, VRP) — серверный API, требует secret-ключ
curl -X POST "https://kartrout.ru/v1/optimize" \
-H "Authorization: Bearer sk_live_..." \
-d '{
"jobs": [{"id": 1, "location": [83.75, 53.35]}],
"vehicles": [{"id": 1, "start": [83.7636, 53.3478]}]
}'
До 90 точек суммарно (задачи + по 2 на каждую машину), до 10 машин за вызов. Квота — по числу задач (jobs). Пока не поддерживаются: грузоподъёмность, навыки водителя, парные забор-доставка, перерывы.
Статичная картинка карты
GET https://kartrout.ru/v1/staticmap?lon=83.76&lat=53.35&zoom=12&width=600&height=400&key=pk_live_...
Единственный продукт этого раздела, что работает с publishable-ключом (как тайлы) — типичное использование это <img src="..."> прямо в письме/странице. Параметры: width/height до 1280px, scale=2 для Retina, style=light|dark|warm. Метки — до 10, через повторяющийся marker=lon,lat. Линии — до 3, через path=lon1,lat1|lon2,lat2|... (точки разделены |, не ; — точка с запятой внутри значения query-параметра отбрасывается вместе со всем параметром стандартным разбором URL). Повторный запрос с теми же параметрами не тратит лишнюю квоту сверх первого рендера.
Важно
- Ключ виден в исходном коде страницы — это нормально, так работают все встраиваемые карты. Защита — в привязке ключа к вашим доменам, не в сокрытии ключа.
- Атрибуция «© OpenStreetMap» всегда отображается и не может быть убрана — требование лицензии данных (ODbL), не наша опция.
- Секретный ключ — только в заголовке
Authorization: Bearer, никогда в?key=— иначе он осядет в логах доступа.
Если карта не появилась
| Сообщение | Причина |
|---|---|
| «неверный или отозванный ключ доступа» | опечатка в ключе, или ключ отозван |
| «этот домен не разрешён для данного ключа» | сайт открыт не с того домена, что указан для ключа |
| «исчерпан месячный лимит тарифа» | закончилась квота тарифа |
| «превышен лимит запросов» | слишком много запросов за минуту |
Параметры Karty.map(container, opts)
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
key | string | обязателен | публичный API-ключ |
style | string | warm | warm|light|dark|white|grayscale|black |
center | [lon, lat] | Москва | начальный центр карты |
zoom | number | 10 | начальный масштаб |
navigationControl | boolean | true | кнопки +/- и компас |