Настройка фильтрации точек на карте магазинов 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Настройка фильтрации точек на карте магазинов 1С-Битрикс
Простая
~1 рабочий день
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1167
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    563
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    743
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Настройка фильтрации точек на карте магазинов 1С-Битрикс

Сеть магазинов — 50 точек по городам, разные форматы, разный режим работы. Пользователь хочет найти ближайший магазин с нужным ассортиментом, открытый прямо сейчас. Стандартный компонент bitrix:map.yandex.view просто показывает все метки без фильтрации. Фильтрация — кастомный функционал.

Хранение данных о магазинах

Точки магазинов удобнее хранить в инфоблоке, не в стандартном справочнике b_catalog_store. Инфоблок даёт гибкость в полях, мультиязычность, удобный редактор в административной части.

Инфоблок Магазины (например, STORES):

Свойство Код Тип
Адрес ADDRESS Строка
Город CITY Список
Формат FORMAT Список (Гипермаркет / Супермаркет / Магазин у дома)
Режим работы SCHEDULE Строка
Широта LAT Число
Долгота LON Число
Телефон PHONE Строка
Метро METRO Строка

API эндпоинт для карты

Фронтенд карты работает через AJAX. PHP-эндпоинт принимает параметры фильтра и возвращает точки:

// /local/ajax/stores.php
\Bitrix\Main\Application::getInstance()->initializeExtended();

$cityId  = (int)($_GET['city']   ?? 0);
$format  = trim($_GET['format']  ?? '');
$openNow = ($_GET['open_now']    ?? '') === '1';

$filter = [
    'IBLOCK_ID' => STORES_IBLOCK_ID,
    'ACTIVE'    => 'Y',
];

if ($cityId) {
    $filter['PROPERTY_CITY'] = $cityId;
}
if ($format) {
    $filter['PROPERTY_FORMAT'] = $format;
}

$res = \CIBlockElement::GetList(
    ['NAME' => 'ASC'],
    $filter,
    false,
    false,
    ['ID', 'NAME', 'PROPERTY_LAT', 'PROPERTY_LON', 'PROPERTY_ADDRESS',
     'PROPERTY_PHONE', 'PROPERTY_SCHEDULE', 'PROPERTY_FORMAT', 'PROPERTY_CITY']
);

$stores = [];
while ($el = $res->GetNext()) {
    $lat  = (float)$el['PROPERTY_LAT_VALUE'];
    $lon  = (float)$el['PROPERTY_LON_VALUE'];

    if (!$lat || !$lon) continue;

    if ($openNow && !isOpenNow($el['PROPERTY_SCHEDULE_VALUE'])) {
        continue;
    }

    $stores[] = [
        'id'       => $el['ID'],
        'name'     => $el['NAME'],
        'address'  => $el['PROPERTY_ADDRESS_VALUE'],
        'phone'    => $el['PROPERTY_PHONE_VALUE'],
        'schedule' => $el['PROPERTY_SCHEDULE_VALUE'],
        'format'   => $el['PROPERTY_FORMAT_VALUE'],
        'lat'      => $lat,
        'lon'      => $lon,
    ];
}

header('Content-Type: application/json; charset=utf-8');
echo json_encode(['stores' => $stores, 'count' => count($stores)]);

Определение «открыт сейчас»

Режим работы хранится в виде строки «Пн-Пт: 9:00-21:00, Сб-Вс: 10:00-20:00». Функция парсит строку и проверяет текущее время:

function isOpenNow(string $schedule): bool
{
    $now     = new DateTime('now', new DateTimeZone('Europe/Moscow'));
    $dayNum  = (int)$now->format('N'); // 1=Пн, 7=Вс
    $timeStr = $now->format('H:i');

    // Парсим шаблон "Пн-Пт: 9:00-21:00"
    preg_match_all('/([А-Яа-я-]+):\s*(\d+:\d+)-(\d+:\d+)/u', $schedule, $matches, PREG_SET_ORDER);

    foreach ($matches as $m) {
        if (dayRangeCovers($m[1], $dayNum) && timeInRange($timeStr, $m[2], $m[3])) {
            return true;
        }
    }
    return false;
}

Фронтенд: Яндекс Карты + фильтр

// Инициализация карты и фильтрации
ymaps.ready(async function() {
    const map      = new ymaps.Map('store-map', { center: [55.76, 37.64], zoom: 10 });
    const clusterer = new ymaps.Clusterer({ preset: 'islands#invertedBlueClusterIcons' });

    async function loadStores() {
        const params = new URLSearchParams({
            city:     document.getElementById('filter-city').value,
            format:   document.getElementById('filter-format').value,
            open_now: document.getElementById('filter-open').checked ? '1' : '0',
        });

        const data = await fetch('/local/ajax/stores.php?' + params).then(r => r.json());

        clusterer.removeAll();
        map.geoObjects.remove(clusterer);

        const placemarks = data.stores.map(store => {
            const pm = new ymaps.Placemark(
                [store.lat, store.lon],
                {
                    balloonContentHeader: store.name,
                    balloonContentBody:
                        `<b>${store.address}</b><br>${store.phone}<br>${store.schedule}`,
                    hintContent: store.name,
                },
                { preset: 'islands#blueDotIcon' }
            );
            return pm;
        });

        clusterer.add(placemarks);
        map.geoObjects.add(clusterer);

        document.getElementById('store-count').textContent = data.count;
    }

    // Загрузка при изменении фильтров
    document.querySelectorAll('.store-filter').forEach(el => {
        el.addEventListener('change', loadStores);
    });

    loadStores();
});

Геолокация «Рядом со мной»

При клике «Показать ближайшие» браузер запрашивает координаты пользователя и сортирует точки по расстоянию:

navigator.geolocation.getCurrentPosition(pos => {
    const userLat = pos.coords.latitude;
    const userLon = pos.coords.longitude;

    // Сортировка по расстоянию (формула Haversine — достаточно для небольших расстояний)
    stores.sort((a, b) => {
        const da = Math.hypot(a.lat - userLat, a.lon - userLon);
        const db = Math.hypot(b.lat - userLat, b.lon - userLon);
        return da - db;
    });

    // Перемещаем карту к пользователю
    map.panTo([userLat, userLon], { duration: 500 });
});

Кеширование

Список магазинов меняется редко. Данные кешируются в файловом кеше Битрикс на 3600 секунд и инвалидируются при редактировании элемента инфоблока через обработчик события OnAfterIBlockElementUpdate.

Конфигурация Срок
Базовая карта с фильтрами город/формат 3–4 дня
+ геолокация, «открыт сейчас», кластеризация +2–3 дня
+ интеграция с ассортиментом (фильтр по товарам в точке) +1 неделя