Реактивная модель в OpenLayers строится вокруг событийной системы и наблюдаемых свойств, которые позволяют связывать изменения состояния карты с автоматическим обновлением визуального представления. В отличие от фреймворков с полноценным виртуальным DOM, здесь реактивность реализована на уровне отдельных объектов: карты, представления, слоёв и источников данных.
Базовым строительным блоком является система Observable
и BaseObject. Почти каждый значимый объект в библиотеке
наследует возможность:
Типичный пример — изменение центра карты:
map.getView().setCenter([0, 0]);
В этот момент срабатывает цепочка событий:
center изменяется внутри
View;change:center;Ключевая особенность — отсутствие глобального реактивного графа. Каждый объект отвечает за собственные изменения и сам уведомляет слушателей.
Основной способ наблюдения — метод on. Он позволяет
подписываться на конкретные события, включая изменения свойств.
const view = map.getView();
view.on('change:zoom', () => {
console.log('Zoom изменился:', view.getZoom());
});
Подобный подход используется практически для всех сущностей:
Map — изменения размера, движений и
взаимодействий;View — центр, масштаб, вращение;Layer — видимость, источник данных, стиль;Source — добавление и удаление объектов.Важно, что события не агрегируются автоматически. При частых изменениях, например при анимации, слушатель будет вызываться многократно.
Внутри OpenLayers реализован механизм set/get свойств с
автоматической генерацией событий изменения. Это позволяет использовать
«watchers» на уровне именованных ключей.
layer.on('change:opacity', () => {
console.log('Новая прозрачность:', layer.getOpacity());
});
Схема работы:
set('opacity', value) изменяет внутреннее
состояние;dispatchEvent('propertychange');change:opacity;Такой механизм можно считать низкоуровневым аналогом watchers, где каждый ключ — отдельная реактивная точка.
Объект View является одним из самых «реактивных»
элементов системы. Он отслеживает три ключевых параметра:
Каждое изменение этих параметров вызывает перерасчёт матрицы отображения.
view.on('change:rotation', () => {
const rotation = view.getRotation();
console.log('Поворот карты:', rotation);
});
Реактивная цепочка включает:
Важно учитывать, что несколько изменений подряд могут привести к
серии рендеров, если не использовать оптимизацию через
requestAnimationFrame.
Слои в OpenLayers обладают собственной системой наблюдения. Основные реактивные свойства:
visible;opacity;zIndex;source;style.Пример наблюдения за источником данных:
layer.on('change:source', () => {
console.log('Источник данных слоя изменился');
});
При смене источника происходит:
Source;Особенно важно поведение при работе с TileSource, где
изменение параметров может привести к полной перегрузке тайлов.
Источники данных — одна из наиболее динамичных частей системы.
Векторные источники (VectorSource) генерируют события при
изменении коллекции объектов:
vectorSource.on('addfeature', (event) => {
console.log('Добавлен объект:', event.feature);
});
vectorSource.on('removefeature', (event) => {
console.log('Удалён объект:', event.feature);
});
Каждое изменение автоматически отражается в:
При массовых изменениях используется событие change,
которое сигнализирует о необходимости полной переработки состояния.
Геометрические объекты (Feature) поддерживают
собственные наблюдаемые свойства. Это позволяет реализовывать реактивные
визуализации данных.
feature.on('change', () => {
console.log('Изменилось одно из свойств feature');
});
Для более точного контроля можно использовать:
feature.on('change:geometry', () => {
console.log('Геометрия изменена');
});
Такая модель особенно важна при:
Любая реактивная подписка должна быть управляемой. Метод
un или unByKey используется для удаления
слушателей.
const key = view.on('change:center', handler);
// позже
unByKey(key);
Без явной отписки возможны:
Особенно критично это при создании временных слоёв и динамических интерфейсов.
При высокой частоте изменений реактивная система может становиться узким местом. Основные подходы оптимизации:
let timeout;
view.on('change:center', () => {
clearTimeout(timeout);
timeout = setTimeout(() => {
console.log('Стабилизированный центр:', view.getCenter());
}, 100);
});
view.setCenter([0, 0]);
view.setZoom(5);
view.setRotation(0);
При таком подходе движок старается объединить изменения в один цикл рендеринга.
Чем меньше активных watchers, тем ниже нагрузка на event loop.
Практика — подписываться только на реально используемые свойства,
избегая универсальных change.
Функция style может выступать как реактивный вычисляемый
слой:
layer.setStyle((feature) => {
const value = feature.get('value');
return value > 10 ? styleA : styleB;
});
При изменении свойств feature автоматически происходит перерасчёт стиля, что делает систему похожей на вычисляемые зависимости.
Реактивная модель OpenLayers не является централизованной. Она строится по принципу распределённого реагирования:
Такая архитектура обеспечивает:
При этом сложные цепочки watchers требуют аккуратного проектирования, чтобы избежать каскадных перерисовок и избыточных вычислений.