Компонентный подход

Компонентный подход в OpenLayers основан на разделении карты на независимые, переиспользуемые и слабо связанные сущности, каждая из которых отвечает за строго ограниченную функциональность. Архитектура строится вокруг композиции объектов, а не наследования, что позволяет формировать сложные картографические приложения из набора базовых блоков.


Карта как контейнер компонентов

Центральный объект — Map — выступает контейнером, объединяющим все остальные компоненты. Он не реализует бизнес-логику, а лишь координирует взаимодействие:

  • отображение слоёв
  • управление взаимодействиями
  • обработка событий
  • компоновка UI-элементов
import Map from 'ol/Map.js';
import View from 'ol/View.js';

const map = new Map({
  target: 'map',
  view: new View({
    center: [0, 0],
    zoom: 2
  })
});

Map не содержит данных о геометрии, стилях или источниках данных — эти функции делегируются отдельным компонентам.


View как независимый компонент состояния

View в OpenLayers отвечает за визуальное состояние карты:

  • центр координат
  • масштаб
  • проекция
  • вращение
import View from 'ol/View.js';

const view = new View({
  center: [823000, 5930000],
  zoom: 6,
  projection: 'EPSG:3857'
});

Компонентный подход проявляется в том, что View можно заменять без изменения остальной архитектуры, например, для переключения между 2D и 3D-подобными режимами (через разные настройки).


Слои как независимые визуальные модули

Layer — ключевой компонент визуализации. Каждый слой инкапсулирует:

  • источник данных (Source)
  • стиль отображения
  • правила отрисовки

Типовая композиция:

import TileLayer from 'ol/layer/Tile.js';
import OSM from 'ol/source/OSM.js';

const osmLayer = new TileLayer({
  source: new OSM()
});

Слои могут быть:

  • тайловыми
  • векторными
  • изображениями
  • веб-тайлами

Компонентность позволяет комбинировать их независимо друг от друга.


Источники данных как отдельный слой абстракции

Source отделяет данные от их визуализации. Это один из ключевых принципов компонентной архитектуры.

import VectorSource from 'ol/source/Vector.js';
import GeoJSON from 'ol/format/GeoJSON.js';

const source = new VectorSource({
  url: '/data/points.geojson',
  format: new GeoJSON()
});

Слой не знает, откуда берутся данные — из файла, API или памяти. Это позволяет:

  • заменять источники без изменения слоя
  • переиспользовать один слой с разными данными
  • динамически обновлять данные

Контролы как UI-компоненты

Control — независимые элементы интерфейса:

  • масштабирование
  • атрибуция
  • переключение слоёв
  • кастомные панели
import Zoom from 'ol/control/Zoom.js';

map.addControl(new Zoom());

Компонентный принцип проявляется в том, что каждый контрол:

  • не зависит от других контролов
  • может быть добавлен или удалён динамически
  • может быть заменён собственной реализацией

Взаимодействия как отдельный слой поведения

Interaction управляет пользовательским вводом:

  • панорамирование
  • выделение объектов
  • рисование геометрий
import Draw from 'ol/interaction/Draw.js';

const draw = new Draw({
  source: source,
  type: 'Polygon'
});

map.addInteraction(draw);

Поведение карты формируется набором взаимодействий, а не монолитным обработчиком событий.


Overlays как независимые визуальные сущности

Overlay позволяет привязывать DOM-элементы к координатам карты:

  • всплывающие окна
  • подсказки
  • кастомные маркеры
import Overlay from 'ol/Overlay.js';

const popup = new Overlay({
  element: document.getElementById('popup'),
  positioning: 'bottom-center'
});

map.addOverlay(popup);

Overlay существует отдельно от слоёв и не участвует в рендеринге WebGL/Canvas, что делает его легковесным компонентом UI-уровня.


Композиция вместо наследования

Компонентная архитектура OpenLayers строится на принципе композиции:

  • карта собирается из независимых объектов
  • поведение определяется набором подключённых компонентов
  • расширение происходит через добавление новых сущностей

Пример композиции:

const map = new Map({
  target: 'map',
  layers: [osmLayer, vectorLayer],
  view: view,
  controls: [],
  interactions: []
});

Каждый массив — это точка расширения системы.


Динамическая сборка компонентов

Компоненты могут добавляться и удаляться во время выполнения:

map.addLayer(new TileLayer({ source: new OSM() }));
map.removeLayer(osmLayer);

map.addInteraction(draw);
map.removeInteraction(draw);

Такой подход позволяет строить адаптивные интерфейсы, где функциональность зависит от состояния приложения.


Событийная модель как связующий слой

Компоненты взаимодействуют через события, а не прямые зависимости:

map.on('click', function (event) {
  console.log(event.coordinate);
});

События позволяют:

  • отделять источники данных от логики обработки
  • реализовывать реактивное поведение
  • строить слабосвязанные модули

Пользовательские компоненты

Компонентный подход поддерживает создание собственных модулей на базе базовых сущностей.

Пример: кастомный слой с динамической стилизацией

import VectorLayer from 'ol/layer/Vector.js';

const customLayer = new VectorLayer({
  source: source,
  style: function (feature) {
    const value = feature.get('value');
    return value > 10 ? highStyle : lowStyle;
  }
});

Функциональность инкапсулируется внутри компонента без изменения ядра карты.


Изоляция ответственности компонентов

Каждый компонент в OpenLayers имеет строго ограниченную зону ответственности:

  • Map — координация
  • View — состояние отображения
  • Layer — визуализация данных
  • Source — данные
  • Interaction — поведение пользователя
  • Control — UI
  • Overlay — привязанный интерфейс

Такая декомпозиция снижает связанность и упрощает масштабирование приложений.


Переиспользование компонентов

Компоненты могут быть собраны в независимые модули:

export function createBaseMap(target) {
  return new Map({
    target,
    layers: [
      new TileLayer({ source: new OSM() })
    ],
    view: new View({
      center: [0, 0],
      zoom: 3
    })
  });
}

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


Конфигурационный стиль сборки карты

Компонентный подход позволяет описывать карту декларативно:

const config = {
  view: { center: [0, 0], zoom: 2 },
  layers: [
    { type: 'osm' },
    { type: 'vector', url: '/data.geojson' }
  ]
};

Далее конфигурация преобразуется в набор компонентов. Это отделяет описание системы от её реализации.


Масштабирование архитектуры через компоненты

При увеличении сложности приложения добавляются новые компоненты без изменения существующих:

  • кластеризация объектов
  • фильтрация слоёв
  • динамическая стилизация
  • подключение внешних сервисов

Компонентный подход сохраняет предсказуемость системы даже при росте числа элементов.