Skip to content
YandexMapsLocator
YandexMapsLocator
Локатор точек на Яндекс.Картах для MODX 3. Free: карта и поиск. Pro: «открыто сейчас», MiniShop3, CSV и REST
  • MODX 3
  • PHP 8.2
  1. Компоненты
  2. YandexMapsLocator
  3. Интеграция на сайте
  4. Интерфейс

Интерфейс ​

Интерфейс Free: Fenom-чанки, locator.css и модули JS. Вид: BEM. Поведение: атрибуты data-yml-*.

Колонки и табы ​

На узком экране одна колонка и табы «Список» / «Карта». С 769px шире две колонки, табы прячутся.

Табы стоят в общей разметке, не внутри панели списка. Карту из HTML не удаляем: в режиме списка панель карты получает hidden. Перед балуном скрипт переключает вид на «Карта».

BEM ​

БлокНазначение
yml-locatorКорень, CSS-переменные
yml-searchФорма поиска
yml-storeКарточка точки
yml-balloonHTML внутри балуна

Состояние держите в data-атрибутах, не в CSS-модификаторах вроде is-active.

data-yml-* (контракт) ​

АтрибутГдеНазначение
data-yml-root.yml-locatorКорень. По нему locator.js находит разметку и поднимает экземпляр
data-yml-config<script type="application/json"> в корнеКарта и параметры запроса. Опционален: без него локатор стартует с пустым конфигом
data-yml-stores<script type="application/json"> в корнеСтартовый список точек
data-yml-view="list|map"кореньРежим на мобильном
data-yml-view-tabтабыПереключение «Список» / «Карта»
data-yml-emptyкореньПустой список
data-yml-locatedкореньАктивен геофильтр после locate()
data-yml-parentsкореньID родителей
data-yml-searchформаПоиск
data-yml-submitкнопка формыОтправка поиска
data-yml-submit-labelобёртка текста внутри data-yml-submitНадпись кнопки. Пока идёт запрос, JS подменяет текст на i18n.searching, потом возвращает исходный
data-yml-search-toolsблок под полемКонтейнер вторичных действий формы. Кнопка геолокации лежит внутри
data-yml-errorформаТекст ошибки поиска
data-yml-locateкнопка«Моё местоположение» / «Все точки»
data-yml-list / data-yml-mapпанелиСписок и карта
data-yml-panel="list|map"панелиТот же смысл для JS
data-yml-selectedтабАктивный таб. Присутствие атрибута без значения: JS ставит и снимает data-yml-selected, попутно обновляя aria-selected и tabindex
data-yml-store-idкарточкаID точки
data-yml-activeкарточкаАктивная точка в списке. Поведение одинаковое с data-yml-selected: присутствие без значения
data-yml-selectкнопка карточкиОткрыть точку на карте
data-yml-lat, data-yml-lngкарточкаКоординаты

Свой outer обязан содержать [data-yml-root] и подключать модуль:

html
<div class="yml-locator" data-yml-root data-yml-view="list">
    <script type="module" src="/assets/components/yandexmapslocator/js/locator.js"></script>
</div>

Скрипт сам поднимает экземпляр для каждого [data-yml-root]; повторная инициализация одного и того же узла блокируется флагом __yandexMapsLocator.

Pro добавляет data-yml-open-now и бейджи .yml-store__status («Открыто» / «Закрыто»).

Ключи data-yml-config ​

Сниппет кодирует конфиг в <script type="application/json" data-yml-config>. Правьте его, если собираете свой outer вручную.

КлючТипПо умолчаниюНазначение
providerstringyandexПровайдер карты
apiKeystring(пусто)Ключ из yandexmapslocator_api_key. Публичный JS-ключ, в HTML попадает
centerobject{latitude, longitude} из default_latitude / default_longitudeЦентр карты. Сниппет пересчитывает: при гео-origin берёт координаты запроса, иначе среднее по точкам (или точка, если она одна)
zoomnumber10Масштаб из yandexmapslocator_default_zoom
clusterbooleantrueКластеризация маркеров
assetsUrlstring{assets_url}components/yandexmapslocator/Относительный путь к файлам пакета
balloonobject{defaultImage: ""}Запасная картинка балуна
markerIconSizearray[32, 32]Размер своей иконки маркера
markerOptionsobject{preset: "islands#redDotIcon", balloonMaxWidth: 360, balloonMinWidth: 220}Параметры маркеров и ширина балуна
frontendModulesarray[]Модули от Extension API. Строкой или {src}
searchUrlstring{assetsUrl}/search.phpEndpoint Free
restApibooleanfalse в Freetrue, если есть capability pro, включён api_enabled и пуст api_token
apiUrlstring(нет в Free)URL REST Pro. Появляется только при restApi: true
parentsstring(пусто)ID родителей из критериев запроса
contextstring(текущий)Список context key через запятую
i18nobject20 ключей, см. нижеСтроки интерфейса и ошибок

Ключи config.i18n ​

Значения берутся из лексикона yandexmapslocator:default, поэтому тексты зависят от языка сайта. В таблице русские строки из lexicon/ru/default.inc.php.

КлючТекст по умолчаниюГде показывается
emptyМагазины не найдены.Пустая выдача
routeПостроить маршрутСсылка маршрута в карточке и балуне
showOnMapПоказать на картеТекст кнопки data-yml-select в карточке
locateMeМоё местоположениеКнопка геолокации
showAllВсе точкиКнопка геолокации, когда геофильтр активен
openNowОткрытоБейдж статуса в чанке точки
closedNowЗакрытоБейдж статуса в чанке точки
filterOpenNowТолько открытыеPro: подпись чекбокса фильтра
searchingИщем…Текст кнопки отправки во время запроса
errEmptyAddressУкажите адрес.Пустое поле адреса
errGeolocationDeniedДоступ к геолокации запрещён. Разрешите определение местоположения в браузере.Отказ браузера
errGeolocationUnavailableНе удалось определить местоположение.Ошибка геолокации
errGeolocationTimeoutИстекло время ожидания геолокации.Таймаут 15 с
errGeolocationFailedОшибка геолокации.Ошибка геолокации
errGeolocationUnsupportedГеолокация не поддерживается браузером.Нет navigator.geolocation
errRateLimitСлишком много запросов. Повторите через минуту.Ответ 429
errSearchFailedОшибка поиска.Ответ сервера с success: false
errInvalidResponseНекорректный ответ сервера.Тело ответа не читается как JSON
errProRequiredREST API доступен только с YandexMapsLocator Pro.REST запрошен без Pro

AJAX Free ​

Поиск с формы и геолокация идут на:

text
/assets/components/yandexmapslocator/search.php?parents=42&address=Омск,%20ул.%20Ленина,%2025&sortby=distance

Пример ответа:

json
{
  "success": true,
  "data": [
    {
      "id": 15,
      "pagetitle": "Магазин на Ленина",
      "address": "Омск, ул. Ленина, 25",
      "latitude": 54.9893,
      "longitude": 73.3682,
      "phone": "+7 3812 00-00-00",
      "distance": 0.4,
      "distance_formatted": "0.4 км",
      "context_key": "web"
    }
  ],
  "meta": { "total": 1 }
}

Запрос с той же страницы, без CORS и Bearer. Локатор на странице идёт в REST api.php только если стоят Pro, api_enabled=Да и пустой api_token. Если токен задан, api_enabled=No или Pro нет, страница остаётся на search.php. Bearer в HTML не попадает.

Если в запросе есть address, search.php тратит и бакет list (api_list_rate_limit, 120/мин), и бакет geocode (api_geocode_rate_limit, 30/мин).

Ошибки search.php (не REST):

КодHTTPКогда
parents_required400пустой parents
where_not_allowed400передан where
invalid_param400передан include, fields или route
invalid_context400неизвестный или запрещённый контекст
empty_address400запрос с пустым address дошёл до геокодера
missing_api_key400не задан yandexmapslocator_api_key, а адрес пришлось бы отправить в геокодер
network_error400Геокодер не ответил или вернул HTTP ≥ 400
invalid_response400ответ Геокодера не разобрался как JSON
method_not_allowed405не GET
rate_limit_exceeded429исчерпан лимит. Есть заголовок Retry-After: 60
internal_error500любое необработанное исключение, попадает в лог как [YandexMapsLocator search] …
modx_bootstrap500не нашлись index.php или сервис yandexmapslocator

Заголовки ответа ​

ЗаголовокКогда
X-Content-Type-Options: nosniffвсегда, и на успехе, и на ошибке
Cache-Control: private, max-age=60успешный ответ
Cache-Control: no-storeошибка
Retry-After: 60ответ 429

CORS-заголовков у search.php нет вообще. Запрос OPTIONS отбивается пустым ответом 204, но браузер всё равно не получит разрешающих заголовков: endpoint строго same-origin, JS ходит в него с credentials: 'same-origin'. Для клиента вне сайта нужен REST Pro.

JavaScript API ​

Класс: window.YandexMapsLocator.

javascript
const locator = new YandexMapsLocator('[data-yml-root]', { apiUrl, config, stores });

locator.search({ address: 'Омск, ул. Ленина, 25' });
locator.locate();
locator.clearLocation();
locator.showStore(15);
locator.setStores(stores);
locator.setCenter(54.98, 73.36);
locator.getStores();

locator.on('store:click', ({ id }) => console.log('card', id));
locator.on('marker:click', ({ id }) => console.log('marker', id));
locator.on('balloon:build', (payload) => {});
locator.on('search:start', (params) => {});
locator.on('search:complete', (data) => {});
locator.on('error', ({ message }) => {});

События JS:

СобытиеКогдаДанные
store:clickКлик по карточке в списке{id, element}
store:activeАктивная точка переключилась в списке{id, element}
marker:clickКлик по маркеру{id, store}
balloon:buildСборка содержимого балуна{store, properties, config}
marker:optionsПравка параметров маркера{store, options, config}
search:startЗапрос ушёлпараметры запроса
search:completeОтвет получен{success, results, meta}
geolocation:startЗапрошены координаты пользователя—
geolocation:completeКоординаты получены{latitude, longitude}
errorОшибка поиска, геолокации, карты или модуля{source, message, ...}

Pro на search:start дописывает filters=working_now.

Методы ​

МетодЧто делает
search(params)Запрос с формы или из кода, обновляет список и маркеры
locate()Геолокация, поиск по координатам с sortby: 'distance', центрирование карты
clearLocation()Сброс геофильтра, очистка поля адреса, возврат во вкладку «Список»
showStore(id)Активная точка в списке, открытие балуна на карте
setStores(stores)Заменить список целиком
setCenter(latitude, longitude, zoom)Переместить и масштабировать карту
getStores()Копия текущего списка
setView(view)Переключить вкладку: list или map. На узком экране прячет неактивную панель
setBusy(isBusy)aria-busy на корне и форме, disabled у кнопок, текст кнопки на i18n.searching
clearError()Скрыть блок ошибки
setLocationActive(active)Переключить состояние геофильтра: data-yml-located на корне и текст кнопки геолокации
ensureMapVisible()На узком экране переключиться на «Карту». Возвращает true, если переключение было
syncEmptyState(isEmpty)Проставить или снять data-yml-empty
loadFrontendModules()Загрузить модули из config.frontendModules и вызвать у каждого install(locator)
readJson(selector)Разобрать JSON из узла внутри корня. Битый JSON даёт null
syncEvents()Переподписать встроенные обработчики: store:click открывает точку, marker:click подсвечивает карточку

После locate() кнопка становится «Все точки» и сбрасывает геофильтр. На мобильном после геолокации открывается вкладка «Карта».

Открыть точку из своего кода ​

javascript
const root = document.querySelector('[data-yml-root]');
const card = root.querySelector('[data-yml-store-id="15"]');
card?.querySelector('[data-yml-select]')?.click();

Стилизация ​

Токены на .yml-locator (CSS-переменные --yml-*). Переопределяйте в теме сайта, файлы пакета не трогайте. JS ставит data-yml-active на карточку и классы is-open / is-closed на .yml-store__status.

css
.yml-locator {
  --yml-color-accent: #e11d48;
}