Location 26.500.0–26.600.0: офисы и плавные маркеры на карте отметок

3 мин чтения
Узнавайте о ломающих изменениях Битрикса раньше, чем они доедут до прода: свежие разборы — в канале @bxmax_updates

Location вышел двумя версиями подряд, 26.500.0 и 26.600.0, и обе меняют только JavaScript карты отметок мобильного Битрикс24, той самой, что в 26.400.0 получила движок MapLibre. В 26.500.0 маркер научился ехать к новой точке, линия маршрута растёт по одной вершине, а карта сообщает приложению, что пользователь сдвинул её рукой. В 26.600.0 на карте появились офисы с плашкой «название и кто приписан». PHP-API и схема БД не менялись, так что разбор нужен тем, кто шлёт карте команды, пишет к ней тесты или собирает свои карты на MapLibre и Leaflet.

Новое

Поставьте на карту офис (26.600.0)

Новый тип маркера MarkerType.OFFICE ('office') рисует белую каплю 40×48 px с иконкой здания, точка привязки внизу капли. Под каплей висит плашка с названием офиса и сотрудниками, которые к нему приписаны. Содержимое задают поля markerIcon.data:

  • title выводит плашку, с пустым заголовком её нет совсем;
  • active: true обводит офис кольцом выделения;
  • при isEmployeeListAvailable: true в плашке стопка аватаров из employees[] в формате {id, name, avatarUrl}, до пяти лиц, остальные свёрнуты в «+N», а остаток больше 99 подписан «99+»;
  • без этого флага плашка показывает текст assignedLabel или число assignedCount;
  • officeId попадает в data-testid, без него в консоли будет Office marker has no officeId, но маркер всё равно построится.

«+N» считается от assignedCount, поэтому хосту хватит прислать первые лица и общее число:

        // данные команды ADD_MARKERS ('addMarkers') для одного офиса
const data = {
	markers: [{
		id: 'office-7',
		config: {
			coords: [55.7579, 37.6136], // [lat, lng]
			markerIcon: {
				type: 'office',
				data: {
					officeId: 7,
					title: 'Офис на Тверской',
					isEmployeeListAvailable: true,
					assignedCount: 12, // два лица и «+10»
					employees: [
						{ id: 101, name: 'Анна Ветрова', avatarUrl: '/upload/main/a1.jpg' },
						{ id: 102, name: 'Илья Гусев', avatarUrl: '' },
					],
				},
			},
		},
	}],
};

    

Название, подписи и officeId проходят через escapeHtml, так что < в имени офиса разметку не сломает. В Playwright маркер находится по getByTestId('check-in-marker-office-7'). Конфигурацию иконки отдаёт статический MarkerIconFactory.getOfficeIconConfig(office), а одну разметку без размеров возвращает createOfficeIconHtml(office). Оба метода есть в BX.Location.CheckIn, там же теперь лежат константы OFFICE_PLATE_MAX_FACES (5) и PLATE_MIN_ZOOM (13).

Двигайте маркер вместо пересоздания (26.500.0)

Раньше маркер с тем же id в ADD_MARKERS пересоздавался. С animate: true в конфиге он едет в новые координаты за 600 мс с замедлением в конце, animateDuration задаёт своё время. Экземпляр маркера остаётся прежним, поэтому CSS-анимация иконки, например пульс живого сотрудника, не начинается заново. Работает в обоих движках и только для маркера вне кластера. Перед fitBounds и fitToLayers идущие поездки сразу заканчиваются в конечной точке, а включение кластеризации их отменяет. Узнать, едет ли маркер, и остановить поездку можно публичными методами сервисов карты isMarkerAnimating(id) и cancelMarkerAnimation(id).

Наращивайте линию по точке (26.500.0)

Полилиния в ADD_LAYERS получила два поля. appendPoints дописывает вершины к уже нарисованной линии с тем же id, всю линию пересылать не нужно. Если линии с таким id на карте нет, в консоли появится appendPoints has no layer of that id to grow, и команда для этого слоя ничего не сделает. followMarker с id маркера привязывает последнюю вершину к его текущему положению, включая промежуточные кадры поездки, и хвост маршрута не обгоняет сотрудника.

По комментарию в коде, пока приложение гнало всю линию смены через нативный мост на каждую новую точку, хвост получалось обновлять раз в десять секунд, а к концу смены в линии около 1350 вершин. Перерисовку линии за маркером движок ограничивает сам: 30 мс между кадрами до 300 вершин, дальше интервал растёт до 120 мс.

Новая GPS-точка сотрудника теперь укладывается в две короткие команды:

        const fix = [55.7601, 37.6187];

// ADD_MARKERS: аватар едет к точке, пульс не сбрасывается
const markersData = {
	markers: [{
		id: 'employee-42',
		config: {
			coords: fix,
			animate: true,
			animateDuration: 400,
			markerIcon: {
				type: 'employeeavatar',
				data: { id: 42, name: 'Анна Ветрова', avatarUrl: '', pulse: true },
			},
		},
	}],
};

// ADD_LAYERS: линия растёт на одну вершину
// followMarker повторяйте в каждой дозаписи, без него привязка снимается
const layersData = {
	layers: [{
		id: 'track-42',
		config: { type: 'polyline', appendPoints: [fix], followMarker: 'employee-42' },
	}],
};

    

Отдайте камеру пользователю (26.500.0)

В CheckInMapEventType из location.core новое событие MAP_MOVED_BY_USER ('mapMovedByUser') с пустыми данными. Карта шлёт его через BXNativeBridge, когда пальцы сдвинули карту или изменили расстояние между собой больше чем на 10 px, а также на прокрутке колёсиком (не чаще раза в 300 мс за жест). Ещё его вызывают команды ZOOM_IN, ZOOM_OUT и FIT_TO_LAYERS. Эти три команды приходят от кнопок нативной панели, нажатие на которые до WebView не доходит, поэтому карта засчитывает их как жест пользователя. Остальные команды камеры, FIT_BOUNDS и SET_ZOOM, события не вызывают. По этому событию приложение, которое ведёт камеру за живым маркером, может выключить слежение. Карта не различает, кто прислал ZOOM_IN, ZOOM_OUT или FIT_TO_LAYERS, так что хост, который шлёт их из своего кода, тоже получит MAP_MOVED_BY_USER.

Включайте пульс аватара отдельно (26.500.0)

У аватара сотрудника разделили выделение и живую позицию. active теперь рисует статичный ореол, как у остальных маркеров. Бегущее кольцо переехало в класс .ci-avatar--pulse и включается полем pulse: true в данных маркера. MarkerIconFactory.createEmployeeAvatarIconHtml() и getEmployeeAvatarIconConfig() получили шестой необязательный параметр pulse. Если ваш код вызывает фабрику сам или передаёт для живого сотрудника только active: true, вместо пульса будет неподвижный ореол. В приложении выделенный аватар больше не пульсирует, пульс остался только у живой позиции.

Шлите offset и в Leaflet (26.500.0)

fitBounds(bounds, options) в Leaflet-движке принимает offset (пиксельный сдвиг кадра, как в MapLibre) и skipClusterTransition. В MapLibre обе опции были и раньше, так что FIT_BOUNDS с ними теперь можно слать, не проверяя, какой движок включён.

Подпись OSM и крупные стрелки в MapLibre (26.500.0)

На карте MapLibre появилась атрибуция OpenStreetMap в правом нижнем углу, раньше её не было нигде. Подпись развёрнута в строку текста 10px. Компактный режим выключен, потому что на телефоне он сворачивает подпись в значок «i», а тот пропадает после первого сдвига карты. Ссылки на maplibre.org в ней нет, потому что в WebView тап по этой ссылке уводил с карты без возможности вернуться.

Стрелки направления на маршруте выросли вдвое, с 12 до 24 px. Стрелка, которая на текущем зуме длиннее своего отрезка, становится прозрачной и появляется, когда пользователь приблизит карту. Длину отрезка хост передаёт в свойстве точки стрелки edgeMercatorMeters, без него стрелка рисуется всегда.

Мелочи и находки

  • Скрытие плашек офисов на дальнем зуме пока только заготовлено (26.600.0). PLATE_MIN_ZOOM = 13 экспортирована, в CSS есть правило для класса ci-zoom-no-plate, но этот класс никто не ставит. Плашки видны на любом зуме, и строить свою логику на этой константе рано.

  • Тёмной темы у плашки офиса нет. Переопределений для #check-in-map.theme-dark в 26.600.0 не появилось, фон плашки остаётся #fff.

  • Если двигаете maplibregl.Marker на своей карте, не вешайте на него CSS-transition по transform (26.500.0). MapLibre переписывает transform маркера на каждом кадре движения камеры, и маркер с transition отстаёт от карты. Location интерполирует координату в requestAnimationFrame.

  • Символы MapLibre, которые не помещаются в свой отрезок, прячутся без слушателя zoom (26.500.0). Сравнить ["zoom"] со свойством фичи напрямую нельзя, он разрешён только на входе верхнеуровневого step или interpolate. Location строит step по целым зумам и в каждой ветке ставит case со своим порогом, а ниже 15-го зума слой стрелок не рисуется вовсе (minzoom: 15). Для своего слоя это выглядит так:

            const ICON_PX = 24;
    const METERS_PER_PX_Z0 = 78271.517; // мир MapLibre шириной 512 px, не 256
    
    // segmentMeters в фиче: длина отрезка в метрах проекции Меркатора
    const visibleAt = (zoom) => [
    	'case',
    	['>=', ['number', ['get', 'segmentMeters'], 1e9], (ICON_PX * METERS_PER_PX_Z0) / 2 ** zoom],
    	1,
    	0,
    ];
    
    // ниже первой точки step работает значение по умолчанию: до 15-го зума стрелок нет
    const fitOpacity = ['step', ['zoom'], 0];
    for (let zoom = 15; zoom <= 18; zoom++)
    {
    	fitOpacity.push(zoom, visibleAt(zoom));
    }
    
    map.setPaintProperty('route-arrows', 'icon-opacity', fitOpacity);
    
        

    Если взять константу для тайлов 256 px, каждый порог удвоится и стрелки, которые помещаются целиком, тоже пропадут.

Новая версия вышла — разбор уже в Telegram

В канале @bxmax_updates публикуем каждый свежий разбор: что сломается, что устарело и что появилось в API. Узнаете до того, как обновите прод.

Подписаться

Читайте дальше

Location 26.400.0: MapLibre GL для карты отметок в мобильном Битрикс24

Почти весь дифф location 26.400.0 — JavaScript карты отметок (check-in), которую показывает мобильный Битрикс24. У карты появился второй движок, MapLibre GL, он включается фича-флагом, а по умолчанию работает прежний Leaflet. PHP-API с [26.300.0](/bitrix-updates/location/location-26-300-0) не менялс…

2 мин

Location 26.300.0: батчевый обратный геокодинг — до 20 координат за один вызов

Релиз от 17 июня 2026 с одной, но цельной темой: в модуль `location` завезли батчевый обратный геокодинг — метод `findByCoordsList`, который превращает список координат в список локаций за один вызов сервиса. Если вы строите интеграции с картами или доставкой и до сих пор дёргали `findByCoords` в ци…

2 мин
voximplant 26.900.0 Заметное Свежее

Voximplant 26.900.0: подписанные параметры экспорта статистики

Voximplant 26.900.0 подписывает имя компонента при экспорте детализации статистики. Обновление также исправляет REST-сценарии, отметку пропущенного переадресованного звонка и чтение настроек прокси.

1 мин
superset 26.700.0 Заметное Свежее

Superset 26.700.0: пользовательский контекст и проверяемый act-as

Версия 26.700.0 добавляет пользовательский контекст Superset в публичные провайдеры и команды. Проверяемый act-as для SQL Lab включается явно, поэтому существующие вызовы продолжают работать по-прежнему. Все новые параметры необязательны, прежние значения по умолчанию сохранены.

2 мин
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…

Можно закрыть чат и перейти на другую страницу. Когда ответ будет готов, на кнопке Домового появится отметка.

Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти