Яндекс.Карты API - Документация¶
Обзор¶
Яндекс.Карты API предоставляет инструменты для встраивания интерактивных карт в веб-приложения, геокодирования адресов и работы с геоданными.
Официальная документация: https://yandex.com/maps-api/docs/js-api/index.html
Компоненты API¶
- JavaScript API 3.0 - клиентская библиотека для интерактивных карт
- Geocoder HTTP API - HTTP API для геокодирования
- React интеграция - готовые компоненты для React приложений
Получение API ключа¶
1. Регистрация¶
- Перейдите на https://developer.tech.yandex.ru/
- Авторизуйтесь через Яндекс ID
- Создайте новый проект
2. Подключение API¶
Выберите пакет "JavaScript API и HTTP Геокодер": - JavaScript API 3.0 для интерактивных карт - Geocoder HTTP API для геокодирования
3. Получение ключа¶
- В настройках проекта нажмите "Получить ключ"
- Укажите домены для JavaScript API (например,
localhost,silent-meadow.com) - Сохраните API ключ
ВАЖНО: JavaScript API 3.0 работает только с ключами, у которых заполнено поле "Ограничение по HTTP Referer".
4. Активация¶
Ключ активируется в течение 15 минут после создания.
JavaScript API 3.0¶
Подключение¶
Базовое подключение¶
<!DOCTYPE html>
<html>
<head>
<script src="https://api-maps.yandex.ru/3.0/?apikey=YOUR_API_KEY&lang=ru_RU"></script>
<script type="module">
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer} = ymaps3;
const map = new YMap(
document.getElementById('map'),
{
location: {
center: [36.234567, 55.523456], // [lng, lat] для ДНП Тихие Луга
zoom: 15
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
map.addChild(new YMapDefaultFeaturesLayer());
</script>
</head>
<body>
<div id="map" style="width: 100%; height: 600px;"></div>
</body>
</html>
С динамической загрузкой¶
// lib/ymaps.ts
export async function loadYandexMaps(apiKey: string) {
return new Promise((resolve, reject) => {
if (window.ymaps3) {
resolve(window.ymaps3);
return;
}
const script = document.createElement('script');
script.src = `https://api-maps.yandex.ru/3.0/?apikey=${apiKey}&lang=ru_RU`;
script.async = true;
script.onload = async () => {
await window.ymaps3.ready;
resolve(window.ymaps3);
};
script.onerror = reject;
document.head.appendChild(script);
});
}
Основные сущности¶
1. YMap - Карта¶
Главный объект карты.
const map = new YMap(
document.getElementById('map'),
{
location: {
center: [37.415663, 55.721749], // [longitude, latitude]
zoom: 10,
duration: 300 // Анимация перехода (мс)
},
mode: 'vector', // 'vector' | 'raster'
behaviors: ['drag', 'scrollZoom', 'dblClick', 'multiTouch']
}
);
Параметры:
- center - центр карты [lng, lat]
- zoom - уровень масштабирования (0-21)
- mode - тип карты (vector или raster)
- behaviors - массив включенных поведений
2. YMapDefaultSchemeLayer - Слой карты¶
Базовый слой с картой местности.
map.addChild(new YMapDefaultSchemeLayer({
customization: [
{
tags: 'water',
elements: 'geometry',
stylers: [{color: '#00ccff'}]
}
]
}));
3. YMapDefaultFeaturesLayer - Слой объектов¶
Слой для отображения меток, линий, полигонов.
4. YMapMarker - Метки¶
Отображение маркеров на карте.
import {YMapMarker} from '@yandex/ymaps3-types';
const marker = new YMapMarker(
{
coordinates: [37.415663, 55.721749],
draggable: false
},
// HTML контент метки
document.createElement('div')
);
// Добавить метку на карту
map.addChild(marker);
Пример с кастомным маркером:
const markerElement = document.createElement('div');
markerElement.className = 'custom-marker';
markerElement.innerHTML = `
<div class="marker-icon">
<span class="marker-label">Участок №502</span>
</div>
`;
const marker = new YMapMarker(
{
coordinates: [36.234567, 55.523456],
onClick: () => {
console.log('Участок №502 выбран');
}
},
markerElement
);
map.addChild(marker);
5. YMapListener - События¶
Обработка событий карты.
import {YMapListener} from '@yandex/ymaps3-types';
const listener = new YMapListener({
onClick: (object, event) => {
console.log('Координаты клика:', event.coordinates);
},
onMouseMove: (object, event) => {
console.log('Координаты курсора:', event.coordinates);
}
});
map.addChild(listener);
6. YMapControls - Элементы управления¶
Добавление кнопок управления картой.
import {
YMapZoomControl,
YMapGeolocationControl
} from '@yandex/ymaps3-types/packages/controls';
// Кнопки зума
const zoomControl = new YMapZoomControl({});
map.addChild(zoomControl);
// Кнопка геолокации
const geolocationControl = new YMapGeolocationControl({});
map.addChild(geolocationControl);
Кластеризация меток¶
Для большого количества меток (например, 436 участков).
import {
YMapClusterer,
clusterByGrid
} from '@yandex/ymaps3-types/packages/clusterer';
// Создать массив маркеров
const markers = properties.map(property => ({
type: 'Feature',
id: property.id,
geometry: {
type: 'Point',
coordinates: [property.longitude, property.latitude]
},
properties: {
name: `Участок №${property.number}`,
price: property.price
}
}));
// Создать кластеризатор
const clusterer = new YMapClusterer({
method: clusterByGrid({gridSize: 64}),
features: markers,
marker: (feature) => {
const element = document.createElement('div');
element.className = 'property-marker';
element.innerHTML = `
<div class="marker-content">
${feature.properties.name}
</div>
`;
return new YMapMarker(
{
coordinates: feature.geometry.coordinates,
onClick: () => handlePropertyClick(feature.id)
},
element
);
},
cluster: (coordinates, features) => {
const element = document.createElement('div');
element.className = 'cluster-marker';
element.innerHTML = `<span>${features.length}</span>`;
return new YMapMarker(
{
coordinates,
onClick: () => {
map.setLocation({
center: coordinates,
zoom: map.zoom + 2,
duration: 300
});
}
},
element
);
}
});
map.addChild(clusterer);
Geocoder HTTP API¶
Прямое геокодирование (адрес → координаты)¶
GET https://geocode-maps.yandex.ru/1.x/?apikey=YOUR_API_KEY&geocode=Московская+область,+Можайский+район,+ДНП+Тихие+Луга&format=json&lang=ru_RU
Response:
{
"response": {
"GeoObjectCollection": {
"featureMember": [
{
"GeoObject": {
"Point": {
"pos": "36.234567 55.523456"
},
"name": "ДНП Тихие Луга",
"description": "Можайский район, Московская область, Россия",
"boundedBy": {
"Envelope": {
"lowerCorner": "36.230000 55.520000",
"upperCorner": "36.240000 55.530000"
}
}
}
}
]
}
}
}
Обратное геокодирование (координаты → адрес)¶
GET https://geocode-maps.yandex.ru/1.x/?apikey=YOUR_API_KEY&geocode=36.234567,55.523456&format=json&lang=ru_RU
Response:
{
"response": {
"GeoObjectCollection": {
"featureMember": [
{
"GeoObject": {
"name": "ДНП Тихие Луга",
"description": "Можайский район, Московская область, Россия",
"Point": {
"pos": "36.234567 55.523456"
}
}
}
]
}
}
}
Параметры запроса¶
| Параметр | Тип | Описание |
|---|---|---|
apikey |
string | API ключ (обязательно) |
geocode |
string | Адрес или координаты для геокодирования |
format |
string | Формат ответа: json, xml (default: xml) |
lang |
string | Язык ответа: ru_RU, en_US, tr_TR |
results |
number | Количество результатов (default: 10, max: 100) |
skip |
number | Пропустить первые N результатов |
kind |
string | Тип объекта: house, street, metro, district, locality |
rspn |
number | Ограничить область поиска (используется с ll и spn) |
ll |
string | Центр области поиска longitude,latitude |
spn |
string | Размер области поиска width,height |
bbox |
string | Альтернатива ll+spn: left,bottom~right,top |
Пример в коде¶
async function geocodeAddress(address: string): Promise<{lat: number, lng: number} | null> {
const apiKey = process.env.YANDEX_MAPS_API_KEY;
const url = `https://geocode-maps.yandex.ru/1.x/?apikey=${apiKey}&geocode=${encodeURIComponent(address)}&format=json&lang=ru_RU`;
try {
const response = await fetch(url);
const data = await response.json();
const geoObject = data.response.GeoObjectCollection.featureMember[0]?.GeoObject;
if (!geoObject) return null;
const [lng, lat] = geoObject.Point.pos.split(' ').map(Number);
return {lat, lng};
} catch (error) {
console.error('Geocoding error:', error);
return null;
}
}
// Использование
const coords = await geocodeAddress('Московская область, Можайский район, ДНП Тихие Луга');
console.log(coords); // {lat: 55.523456, lng: 36.234567}
React интеграция¶
Вариант 1: Официальный @yandex/ymaps3-reactify¶
Настройка¶
// lib/ymaps.ts
import {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapMarker} from '@yandex/ymaps3-types';
import reactify from '@yandex/ymaps3-reactify';
let ymaps: typeof import('@yandex/ymaps3-types') | null = null;
export async function initYMaps(apiKey: string) {
if (ymaps) return ymaps;
await new Promise((resolve) => {
const script = document.createElement('script');
script.src = `https://api-maps.yandex.ru/3.0/?apikey=${apiKey}&lang=ru_RU`;
script.onload = resolve;
document.head.appendChild(script);
});
await window.ymaps3.ready;
ymaps = window.ymaps3;
return ymaps;
}
export async function getReactComponents(apiKey: string) {
const ymaps = await initYMaps(apiKey);
const reactify = await import('@yandex/ymaps3-reactify');
const {
YMap: YMapReact,
YMapDefaultSchemeLayer: YMapDefaultSchemeLayerReact,
YMapDefaultFeaturesLayer: YMapDefaultFeaturesLayerReact,
YMapMarker: YMapMarkerReact
} = reactify.reactify.module(ymaps);
return {
YMapReact,
YMapDefaultSchemeLayerReact,
YMapDefaultFeaturesLayerReact,
YMapMarkerReact
};
}
Использование в компоненте¶
// components/PropertiesMap.tsx
import React, {useEffect, useState} from 'react';
import {getReactComponents} from '@/lib/ymaps';
interface Property {
id: string;
number: string;
latitude: number;
longitude: number;
price: number;
status: 'available' | 'reserved' | 'sold';
}
interface PropertiesMapProps {
properties: Property[];
onPropertyClick: (propertyId: string) => void;
}
export function PropertiesMap({properties, onPropertyClick}: PropertiesMapProps) {
const [components, setComponents] = useState<any>(null);
useEffect(() => {
const apiKey = import.meta.env.VITE_YANDEX_MAPS_API_KEY;
getReactComponents(apiKey).then(setComponents);
}, []);
if (!components) {
return <div className="flex items-center justify-center h-[600px]">Загрузка карты...</div>;
}
const {YMapReact, YMapDefaultSchemeLayerReact, YMapDefaultFeaturesLayerReact, YMapMarkerReact} = components;
return (
<YMapReact
location={{
center: [36.234567, 55.523456],
zoom: 14
}}
mode="vector"
className="w-full h-[600px]"
>
<YMapDefaultSchemeLayerReact />
<YMapDefaultFeaturesLayerReact />
{properties.map((property) => (
<YMapMarkerReact
key={property.id}
coordinates={[property.longitude, property.latitude]}
onClick={() => onPropertyClick(property.id)}
>
<div className={`
property-marker
${property.status === 'available' ? 'bg-green-500' :
property.status === 'reserved' ? 'bg-yellow-500' : 'bg-gray-500'}
text-white px-3 py-2 rounded-lg shadow-lg cursor-pointer
hover:scale-110 transition-transform
`}>
<div className="text-xs font-bold">№{property.number}</div>
<div className="text-xs">{(property.price / 1000).toFixed(0)}K ₽</div>
</div>
</YMapMarkerReact>
))}
</YMapReact>
);
}
Вариант 2: Сторонняя библиотека @pbe/react-yandex-maps¶
Использование¶
import React from 'react';
import {YMaps, Map, Placemark, Clusterer} from '@pbe/react-yandex-maps';
interface PropertiesMapProps {
properties: Property[];
}
export function PropertiesMap({properties}: PropertiesMapProps) {
const apiKey = import.meta.env.VITE_YANDEX_MAPS_API_KEY;
return (
<YMaps query={{apikey: apiKey, lang: 'ru_RU'}}>
<Map
defaultState={{
center: [55.523456, 36.234567],
zoom: 14
}}
width="100%"
height="600px"
>
<Clusterer
options={{
preset: 'islands#greenClusterIcons',
groupByCoordinates: false,
clusterDisableClickZoom: false
}}
>
{properties.map((property) => (
<Placemark
key={property.id}
geometry={[property.latitude, property.longitude]}
properties={{
balloonContent: `
<div>
<h3>Участок №${property.number}</h3>
<p>Цена: ${property.price.toLocaleString('ru-RU')} ₽</p>
<p>Статус: ${property.status}</p>
</div>
`
}}
options={{
preset: property.status === 'available'
? 'islands#greenIcon'
: 'islands#grayIcon'
}}
/>
))}
</Clusterer>
</Map>
</YMaps>
);
}
Rate Limits и квоты¶
JavaScript API 3.0¶
- Бесплатный лимит:
- 25,000 загрузок карты в месяц
-
После превышения: 50 ₽ за 1000 загрузок
-
Подсчет загрузок:
- Каждое обращение к API (загрузка страницы с картой) = 1 загрузка
- Перезагрузка страницы = новая загрузка
Geocoder HTTP API¶
- Бесплатный лимит:
-
25,000 запросов в сутки
-
Rate limit:
- До 10 запросов в секунду
- При превышении: HTTP 429 (Too Many Requests)
Рекомендации¶
-
Кэшируйте результаты геокодирования:
const geocodeCache = new Map<string, {lat: number, lng: number}>(); async function geocodeWithCache(address: string) { if (geocodeCache.has(address)) { return geocodeCache.get(address)!; } const result = await geocodeAddress(address); if (result) { geocodeCache.set(address, result); } return result; } -
Используйте debounce для поиска:
-
Батчинг запросов: Если нужно геокодировать много адресов, делайте паузы между запросами:
Best Practices¶
1. Ленивая загрузка карты¶
Загружайте карту только когда она нужна:
import {lazy, Suspense} from 'react';
const PropertiesMap = lazy(() => import('./components/PropertiesMap'));
function PropertyPage() {
return (
<Suspense fallback={<div>Загрузка карты...</div>}>
<PropertiesMap properties={properties} />
</Suspense>
);
}
2. Оптимизация маркеров¶
Для большого количества участков используйте кластеризацию:
// Всегда используйте clusterByGrid для 436 участков
const clusterer = new YMapClusterer({
method: clusterByGrid({gridSize: 64}),
features: markers
});
3. Ограничение области карты¶
Ограничьте область просмотра районом Можайска:
const map = new YMap(element, {
location: {
center: [36.234567, 55.523456],
zoom: 14
},
restrictMapArea: [
[36.0, 55.4], // Юго-западный угол
[36.5, 55.7] // Северо-восточный угол
]
});
4. Мобильная оптимизация¶
const isMobile = window.innerWidth < 768;
const map = new YMap(element, {
location: {
center: [36.234567, 55.523456],
zoom: isMobile ? 13 : 14
},
behaviors: isMobile
? ['drag', 'multiTouch']
: ['drag', 'scrollZoom', 'dblClick']
});
5. TypeScript типы¶
/// <reference types="@yandex/ymaps3-types" />
import type {YMap, YMapMarker, LngLat} from '@yandex/ymaps3-types';
interface MapConfig {
center: LngLat;
zoom: number;
}
const config: MapConfig = {
center: [36.234567, 55.523456],
zoom: 14
};
Примеры использования в Silent Meadow¶
1. Карта участков с фильтрацией¶
// pages/properties/index.tsx
import {useState} from 'react';
import {PropertiesMap} from '@/components/PropertiesMap';
import {PropertyFilters} from '@/components/PropertyFilters';
export default function PropertiesPage() {
const [filters, setFilters] = useState({
minPrice: 0,
maxPrice: 1000000,
minArea: 0,
maxArea: 20,
status: 'available'
});
const {data: properties} = useQuery(
['properties', filters],
() => api.getProperties(filters)
);
return (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-1">
<PropertyFilters filters={filters} onChange={setFilters} />
</div>
<div className="lg:col-span-2">
<PropertiesMap
properties={properties || []}
onPropertyClick={(id) => router.push(`/properties/${id}`)}
/>
</div>
</div>
);
}
2. Страница детального просмотра участка¶
// pages/properties/[id].tsx
import {YMapReact, YMapMarkerReact} from '@/lib/ymaps';
export default function PropertyDetailPage() {
const {id} = useParams();
const {data: property} = useQuery(['property', id], () => api.getProperty(id));
if (!property) return <div>Загрузка...</div>;
return (
<div>
<h1>Участок №{property.number}</h1>
<YMapReact
location={{
center: [property.longitude, property.latitude],
zoom: 16
}}
className="w-full h-[400px] rounded-lg"
>
<YMapDefaultSchemeLayerReact />
<YMapDefaultFeaturesLayerReact />
<YMapMarkerReact coordinates={[property.longitude, property.latitude]}>
<div className="w-8 h-8 bg-green-500 rounded-full border-4 border-white shadow-lg"></div>
</YMapMarkerReact>
</YMapReact>
<div className="mt-6">
<p>Адрес: {property.full_address}</p>
<p>Площадь: {property.area_sotok} соток</p>
<p>Цена: {property.price.toLocaleString('ru-RU')} ₽</p>
</div>
</div>
);
}
3. Геокодирование при добавлении участка¶
// pages/admin/properties/new.tsx
import {geocodeAddress} from '@/lib/yandex-geocoder';
export default function NewPropertyPage() {
const [form, setForm] = useState({
number: '',
address: '',
latitude: 0,
longitude: 0
});
const handleGeocodeAddress = async () => {
const coords = await geocodeAddress(form.address);
if (coords) {
setForm(prev => ({
...prev,
latitude: coords.lat,
longitude: coords.lng
}));
toast.success('Координаты найдены!');
} else {
toast.error('Не удалось найти адрес');
}
};
return (
<form>
<input
value={form.address}
onChange={(e) => setForm({...form, address: e.target.value})}
placeholder="Адрес участка"
/>
<button type="button" onClick={handleGeocodeAddress}>
Найти координаты
</button>
<input value={form.latitude} disabled placeholder="Широта" />
<input value={form.longitude} disabled placeholder="Долгота" />
</form>
);
}
Обработка ошибок¶
// lib/yandex-maps-error-handler.ts
export class YandexMapsError extends Error {
constructor(
message: string,
public code: string,
public details?: any
) {
super(message);
this.name = 'YandexMapsError';
}
}
export async function safeGeocode(address: string) {
try {
const result = await geocodeAddress(address);
return {success: true, data: result};
} catch (error) {
if (error.response?.status === 403) {
return {
success: false,
error: new YandexMapsError(
'Неверный API ключ',
'INVALID_API_KEY'
)
};
}
if (error.response?.status === 429) {
return {
success: false,
error: new YandexMapsError(
'Превышен лимит запросов',
'RATE_LIMIT_EXCEEDED'
)
};
}
return {
success: false,
error: new YandexMapsError(
'Ошибка геокодирования',
'GEOCODE_ERROR',
error
)
};
}
}
Полезные ссылки¶
- JavaScript API 3.0 - Документация
- JavaScript API - Справочник
- Geocoder HTTP API - Документация
- React интеграция - Официальная
- React Yandex Maps - Библиотека
- TypeScript типы
- Примеры использования
Обновлено: 2026-02-16