Работа с пользовательскими событиями в OpenLayers строится вокруг системы событий карты, взаимодействий (Interactions) и низкоуровневых pointer-событий, которые проксируются из браузерной модели событий. Обработка кликов и перемещений мыши является ключевым механизмом для реализации выбора объектов, подсветки, всплывающих окон, интерактивных слоёв и аналитики действий пользователя.
Основной объект, через который проходит вся интерактивность, —
экземпляр ol/Map. Он наследует EventTarget-подобную модель
и генерирует события разного уровня:
click, dblclick,
singleclick)pointermove,
pointerdrag)moveend,
movestart, postrender)Базовая регистрация обработчика:
map.on('click', function (event) {
console.log(event.coordinate);
});
Объект event содержит важные данные:
coordinate — координаты в системе картыpixel — пиксель на холстеmap — ссылка на картуoriginalEvent — исходное DOM-событиеВ OpenLayers событие click может конфликтовать с
drag-операциями, поэтому чаще используется singleclick.
click — срабатывает сразу при нажатии/отпусканииsingleclick — срабатывает после определения, что это не
drag и не double clickmap.on('singleclick', function (event) {
console.log('Одиночный клик:', event.coordinate);
});
Использование singleclick предпочтительно при работе с
выбором объектов.
Одна из наиболее частых задач — определить, по каким объектам кликнул пользователь.
map.on('singleclick', function (event) {
const features = map.getFeaturesAtPixel(event.pixel);
features.forEach(f => {
console.log(f.get('name'));
});
});
Метод работает через рендер-слой и быстро возвращает все объекты в точке.
Более гибкий вариант:
map.on('singleclick', function (event) {
map.forEachFeatureAtPixel(event.pixel, function (feature, layer) {
console.log('Feature:', feature);
console.log('Layer:', layer);
});
});
Позволяет:
OpenLayers предоставляет удобные методы трансформации пикселей в координаты карты:
map.on('click', function (event) {
const coord = event.coordinate;
console.log(coord);
});
Также возможно ручное вычисление:
const coordinate = map.getCoordinateFromPixel(event.pixel);
Это полезно при работе вне событий карты.
Событие pointermove используется для:
map.on('pointermove', function (event) {
const pixel = event.pixel;
map.forEachFeatureAtPixel(pixel, function (feature) {
feature.setStyle(highlightStyle);
});
});
Событие pointermove генерируется очень часто, поэтому
требуется контроль частоты обработки.
let lastTime = 0;
map.on('pointermove', function (event) {
const now = Date.now();
if (now - lastTime < 50) return;
lastTime = now;
// обработка
});
let pending = false;
map.on('pointermove', function (event) {
if (pending) return;
pending = true;
requestAnimationFrame(() => {
pending = false;
map.forEachFeatureAtPixel(event.pixel, function (feature) {
// обработка hover
});
});
});
Типовой сценарий — изменение стиля объекта при наведении.
let lastFeature = null;
map.on('pointermove', function (event) {
if (lastFeature) {
lastFeature.setStyle(undefined);
lastFeature = null;
}
map.forEachFeatureAtPixel(event.pixel, function (feature) {
feature.setStyle(highlightStyle);
lastFeature = feature;
return true;
});
});
Важно сбрасывать стиль при уходе курсора с объекта, иначе состояние останется изменённым.
Изменение курсора при наведении на объект реализуется через DOM-стиль контейнера карты:
map.on('pointermove', function (event) {
const hit = map.hasFeatureAtPixel(event.pixel);
map.getTargetElement().style.cursor = hit ? 'pointer' : '';
});
Это создаёт привычный UX как в интерактивных веб-картах.
OpenLayers различает движение карты и движение указателя:
pointerdrag — пользователь тащит картуpointermove — движение без перетаскиванияmap.on('pointerdrag', function (event) {
console.log('Карта перемещается');
});
Это важно для отключения hover-логики во время drag:
let isDragging = false;
map.on('pointerdrag', () => isDragging = true);
map.on('moveend', () => isDragging = false);
Для выбора объектов часто используется встроенная интеракция:
import Select fr om 'ol/interaction/Select.js';
const select = new Select();
map.addInteraction(select);
select.on('select', function (event) {
console.log(event.selected);
});
Преимущества:
Ключевое различие:
pixel — координаты на canvas (в пикселях экрана)coordinate — координаты карты (в проекции слоя)Пример преобразования:
map.on('click', function (event) {
const pixel = event.pixel;
const coordinate = event.coordinate;
});
Использование pixel критично для hit detection,
coordinate — для геоданных.
Иногда необходимо реагировать только на определённые слои:
map.on('singleclick', function (event) {
map.forEachFeatureAtPixel(event.pixel, function (feature, layer) {
if (layer.get('name') === 'cities') {
console.log(feature.getProperties());
}
});
});
Частый сценарий — открытие всплывающего окна:
map.on('singleclick', function (event) {
const coordinate = event.coordinate;
overlay.setPosition(coordinate);
popup.innerHTML = 'Информация об объекте';
});
Overlay привязывается к координатам карты, а не к пикселям.
Типовая архитектура интерактивной карты:
pointermove — hover-подсветкаsingleclick — выбор объектаdblclick — zoom или дополнительное действиеmap.on('pointermove', hoverHandler);
map.on('singleclick', clickHandler);
map.on('dblclick', zoomHandler);
Разделение логики снижает конфликт событий и улучшает отзывчивость интерфейса.
При сложных взаимодействиях важно учитывать:
Подход с проверкой пикселя:
map.on('singleclick', function (event) {
const hit = map.hasFeatureAtPixel(event.pixel);
if (!hit) return;
});
Для повышения удобства выбора можно расширять область попадания:
map.on('singleclick', function (event) {
map.forEachFeatureAtPixel(event.pixel, function (feature) {
console.log(feature);
}, {
hitTolerance: 5
});
});
Это особенно полезно для точечных объектов.
Помимо мыши, движение карты также влияет на взаимодействие:
map.on('moveend', function () {
console.log('Перемещение завершено');
});
Используется для: