Архитектура расширений построена вокруг строгого разделения ответственности между слоями карты, источниками данных, интеракциями, контролами и рендерингом. Каждая часть системы проектировалась как независимый модуль, который можно заменить, расширить или комбинировать без изменения ядра библиотеки.
OpenLayers использует модульную структуру ES Modules, где каждый функциональный блок находится в отдельном пространстве имён:
ol/Map — контейнер карты и координатор рендерингаol/layer/* — слои различных типовol/source/* — источники данныхol/interaction/* — взаимодействия пользователяol/control/* — UI-элементы управленияol/geom/* — геометрические примитивыol/format/* — парсинг геоданныхТакое разделение обеспечивает возможность точечного расширения функциональности без затрагивания остальной системы. Tree-shaking в сборщиках позволяет включать только используемые модули, что критично для производительности в веб-приложениях.
Центральной точкой расширения является базовый класс
ol/Object, реализующий наблюдаемую модель состояния. Почти
все ключевые сущности наследуются от него.
Ключевые свойства архитектуры:
Пример создания расширяемого объекта:
import BaseObject from 'ol/Object.js';
class CustomModel extends BaseObject {
constructor(options) {
super();
this.set('value', options.value || 0);
}
increment() {
const current = this.get('value');
this.set('value', current + 1);
}
}
Механизм set/get встроен в систему уведомлений, что
позволяет автоматически синхронизировать состояние карты и
представления.
Система событий основана на паттерне Observer. Практически любой объект может генерировать события:
Каждое событие имеет тип и контекст:
map.on('moveend', function (event) {
const center = map.getView().getCenter();
});
Расширения используют этот механизм для интеграции с ядром без необходимости модификации внутренних компонентов.
Слои (ol/layer) являются ключевым расширяемым уровнем
системы. Базовый класс BaseLayer определяет контракт:
Основные типы слоёв:
Создание собственного слоя возможно через наследование:
import Layer from 'ol/layer/Layer.js';
class CustomLayer extends Layer {
constructor(options) {
super(options);
}
render(frameState) {
const context = frameState.context;
// пользовательская логика отрисовки
}
}
Расширение слоя чаще всего связано с переопределением метода
render, который получает состояние текущего кадра
карты.
Источники (ol/source) определяют способ получения
данных:
Базовый класс Source реализует события загрузки и
обновления. Расширение источника позволяет интегрировать нестандартные
API.
Пример кастомного источника:
import Source from 'ol/source/Source.js';
class CustomSource extends Source {
constructor(options) {
super(options);
this.url = options.url;
}
load() {
fetch(this.url)
.then(r => r.json())
.then(data => {
this.dispatchEvent({ type: 'load', data });
});
}
}
Такой подход позволяет подключать любые внешние сервисы без изменения слоя.
Интеракции (ol/interaction) отвечают за поведение
пользователя:
Каждая интеракция реализует набор методов:
handleDownEventhandleDragEventhandleUpEventsetActiveПример кастомной интеракции:
import Interaction from 'ol/interaction/Interaction.js';
class CustomClickInteraction extends Interaction {
constructor() {
super();
}
handleDownEvent(evt) {
const coordinate = evt.coordinate;
console.log('Click at:', coordinate);
return true;
}
}
Интеракции добавляются в карту как независимые модули поведения:
map.addInteraction(new CustomClickInteraction());
Контролы (ol/control) отделены от логики карты и
предназначены для интерфейса:
Базовый класс Control предоставляет контейнер DOM и
методы жизненного цикла:
rendersetMapПример кастомного контроля:
import Control from 'ol/control/Control.js';
class CustomControl extends Control {
constructor() {
const button = document.createElement('button');
button.innerHTML = 'Action';
const element = document.createElement('div');
element.className = 'custom-control';
element.appendChild(button);
super({ element });
button.addEventListener('click', () => {
console.log('Control triggered');
});
}
}
Рендеринг карты основан на концепции frameState. Это
объект, содержащий:
Каждый кадр строится заново, что позволяет реализовать:
Слои получают frameState и решают, нужно ли
перерисовываться.
Модуль ol/format отвечает за преобразование
геоданных:
Каждый формат реализует интерфейс:
readFeatureswriteFeaturesПример расширения формата:
import TextFeature from 'ol/format/TextFeature.js';
class CustomFormat extends TextFeature {
readFeatures(text) {
const parsed = JSON.parse(text);
return parsed.features;
}
}
Форматы интегрируются в источники данных, что позволяет отделить транспорт данных от их интерпретации.
Ключевой механизм расширяемости — Observable. Он
обеспечивает:
Любое изменение свойства автоматически может инициировать перерасчёт рендеринга.
OpenLayers не использует единый плагинный реестр. Вместо этого расширения строятся через композицию:
Такой подход снижает связность и повышает гибкость архитектуры.
Типовая композиция расширений:
map.addLayer(customLayer);
map.addInteraction(customInteraction);
customLayer.setSource(customSource);
Архитектура модулей ориентирована на статический анализ импортов. Это позволяет:
Каждый модуль представляет собой автономную единицу, не зависящую от глобального состояния библиотеки.
Наиболее глубокий уровень расширения связан с:
renderРендеринг может быть полностью заменён для реализации специализированных визуализаций:
Такие расширения опираются на frameState и
низкоуровневый доступ к canvas/WebGL контексту, что позволяет обходить
стандартные слои отображения и реализовывать собственные графические
пайплайны.