В экосистеме HERE Technologies работа с внутренними пространствами зданий реализована через модель Venue / Indoor Mapping, где геометрия строится не как единая карта, а как набор уровней (floors), связанных общей структурой объекта. Каждый этаж рассматривается как отдельный слой данных, синхронизированный с географической привязкой здания и его POI-структурой.
В HERE Maps API поддержка этажности реализуется через механизм фильтрации пространственных объектов по атрибуту уровня (level, floorIndex, floorNumber), а также через управление видимостью слоёв в рендерере карты.
Внутренняя структура многоэтажного объекта обычно включает:
Каждый уровень содержит метаданные:
Фильтрация отображения основана на сопоставлении активного уровня и атрибутов объектов.
Работа с этажами начинается с включения indoor-слоя и загрузки venue-структуры:
const platform = new H.service.Platform({
apikey: 'API_KEY'
});
const defaultLayers = platform.createDefaultLayers();
const map = new H.Map(
document.getElementById('map'),
defaultLayers.vector.normal.map,
{
center: { lat: 52.5200, lng: 13.4050 },
zoom: 18,
pixelRatio: window.devicePixelRatio
}
);
После инициализации карты подключается сервис venue:
const venueService = platform.getVenueService();
const provider = new H.venues.Service(providerOptions);
const venues = new H.venues.Venues(provider);
map.addLayer(venues);
На этом этапе карта получает возможность отображать многоэтажные структуры, если они доступны в выбранной области.
Переключение этажей реализуется через изменение активного фильтра уровня отображения. Визуально это эквивалентно включению/выключению подмножества геометрии, относящейся к конкретному floorId.
Основные подходы:
В большинстве реализаций используется контроллер управления venue:
const venueProvider = venues.getProvider();
venueProvider.addEventListener('tap', (evt) => {
const venue = evt.target;
const floorSelector = venue.getFloorSelector();
floorSelector.setActiveFloor(2);
});
Метод setActiveFloor изменяет текущий отображаемый
уровень, скрывая остальные этажи.
Перед переключением этажей выполняется запрос структуры здания:
const floors = venue.getFloors();
floors.forEach(floor => {
console.log(floor.id, floor.level, floor.name);
});
Типичная структура объекта floor:
id — уникальный идентификаторlevel — числовой индекс (например, -1, 0, 1, 2)name — человекочитаемое название (Ground, First
Floor)geometryBounds — ограничивающий прямоугольникПри смене этажа выполняется фильтрация всех feature-слоёв:
function applyFloorFilter(activeFloor) {
venueProvider.setStyle(function (feature) {
const featureFloor = feature.getProperty('floor');
if (featureFloor === activeFloor) {
return { opacity: 1 };
}
return { opacity: 0, visible: false };
});
}
Такой подход обеспечивает:
Система генерирует события при изменении активного уровня:
venueProvider.addEventListener('floorchange', (event) => {
const previous = event.previousFloor;
const current = event.activeFloor;
console.log(previous, current);
});
События используются для синхронизации UI и внешних компонентов, например:
Типовой UI-компонент строится на основе списка floors:
function createFloorUI(floors) {
const container = document.createElement('div');
floors.forEach(floor => {
const button = document.createElement('button');
button.textContent = floor.name;
button.oncl ick = () => {
venue.getFloorSelector().setActiveFloor(floor.level);
};
container.appendChild(button);
});
return container;
}
UI синхронизируется с состоянием venue:
При отображении нескольких этажей одновременно используется режим partial visibility:
floorSelector.setVisibleFloors([0, 1]);
В этом режиме:
Стилизация этажей зависит от атрибутов:
floorColorhighlightedaccessibilityLevelusageTypeПример динамического стиля:
venueProvider.setStyle(function (feature) {
const isActive = feature.getProperty('active');
return {
fillColor: isActive ? '#4CAF50' : '#BDBDBD',
strokeColor: '#333333',
lineWidth: 1
};
});
Внутренняя навигация учитывает этажность как часть графа:
При расчёте маршрута учитывается:
При работе с большим количеством уровней применяется:
venueProvider.setLoadingStrategy({
preloadAdjacentFloors: true,
cacheSize: 50
});
При смене уровня часто выполняется автоматическое позиционирование камеры:
function focusFloor(floor) {
const bounds = floor.geometryBounds;
map.getViewModel().setLookAtData({
bounds: bounds,
tilt: 45,
zoom: 20
});
}
Это позволяет:
В сложных зданиях используется z-index stacking:
При наличии нескольких venue в области:
venues.on('venuefocus', (evt) => {
const activeVenue = evt.venue;
activeVenue.getFloorSelector().reset();
});
Если здание не содержит floor metadata: