Zoom контрол

В OpenLayers управление масштабом карты реализуется через контрол Zoom, входящий в стандартный набор ol.control. Он обеспечивает базовую навигацию по уровням детализации карты и тесно связан с системой разрешений (resolution) и зум-уровней (zoom levels), которые лежат в основе рендеринга тайлов и векторных слоёв.

Контрол масштабирования представлен классом ol.control.Zoom. Его задача — изменять текущий уровень зума карты, увеличивая или уменьшая значение view.zoom. При этом сам контрол не работает напрямую с пикселями или тайлами — он взаимодействует через объект ol.View, который управляет состоянием отображения.

Основные элементы:

  • кнопка увеличения масштаба (zoom in)
  • кнопка уменьшения масштаба (zoom out)
  • связь с View
  • ограничения minZoom и maxZoom

Контрол является частью системы ol.control.Control, что позволяет ему быть расширяемым и заменяемым.

Добавление Zoom-контрола на карту

По умолчанию контрол масштабирования уже включён в стандартный набор управления картой. Однако его можно явно конфигурировать или переопределять.

import Map from 'ol/Map.js';
import View from 'ol/View.js';
import Zoom from 'ol/control/Zoom.js';
import TileLayer from 'ol/layer/Tile.js';
import OSM from 'ol/source/OSM.js';

const map = new Map({
  target: 'map',
  layers: [
    new TileLayer({
      source: new OSM()
    })
  ],
  view: new View({
    center: [0, 0],
    zoom: 2
  }),
  controls: [
    new Zoom()
  ]
});

В этом случае создаётся минимальная конфигурация управления, содержащая только кнопки масштабирования.

Параметры Zoom-контрола

Конструктор ol.control.Zoom принимает объект настроек:

  • className — CSS-класс контейнера
  • zoomInLabel — содержимое кнопки увеличения масштаба
  • zoomOutLabel — содержимое кнопки уменьшения масштаба
  • zoomInTipLabel — текст подсказки
  • zoomOutTipLabel — текст подсказки
  • duration — длительность анимации изменения масштаба

Пример настройки:

new Zoom({
  duration: 250,
  zoomInLabel: '+',
  zoomOutLabel: '−',
  zoomInTipLabel: 'Увеличить масштаб',
  zoomOutTipLabel: 'Уменьшить масштаб'
});

Связь с View и ограничениями масштаба

Zoom-контрол изменяет значение zoom внутри View. Ограничения задаются через:

  • minZoom
  • maxZoom
  • constrainResolution
new View({
  center: [0, 0],
  zoom: 5,
  minZoom: 3,
  maxZoom: 10
});

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

Если включён constrainResolution: true, изменения происходят дискретно, строго по доступным уровням разрешения тайловой сетки.

Взаимодействие с разрешением (resolution)

Внутренне OpenLayers работает не с zoom как с числом, а с resolution. Каждому zoom соответствует определённый масштаб:

resolution = initialResolution / 2^zoom

При изменении масштаба через Zoom-контрол происходит пересчёт resolution, после чего обновляются слои.

Это важно для:

  • тайловых слоёв (XYZ, WMTS)
  • векторного рендеринга
  • кластеризации объектов

Кастомизация внешнего вида

Контрол имеет стандартную HTML-структуру:

<div class="ol-zoom ol-unselectable ol-control">
  <button class="ol-zoom-in">+</button>
  <button class="ol-zoom-out">−</button>
</div>

Изменение внешнего вида выполняется через CSS:

.ol-zoom {
  top: 10px;
  left: 10px;
  background: rgba(30, 30, 30, 0.8);
  border-radius: 6px;
}

.ol-zoom button {
  color: white;
  background: transparent;
  width: 32px;
  height: 32px;
}

.ol-zoom button:hover {
  background: rgba(255, 255, 255, 0.2);
}

Контрол полностью отделён от логики карты, что позволяет свободно менять визуальную часть без вмешательства в JavaScript.

Позиционирование контрола

Как и другие элементы управления, Zoom размещается через ol.control.defaults или через CSS-классы позиционирования:

import defaults from 'ol/control/defaults.js';

const map = new Map({
  controls: defaults({
    zoom: true
  })
});

CSS-классы:

  • ol-top-left
  • ol-top-right
  • ol-bottom-left
  • ol-bottom-right

Пример перемещения:

.ol-zoom {
  top: auto;
  bottom: 20px;
  left: 20px;
}

Отключение стандартного Zoom

В некоторых интерфейсах кнопки масштабирования заменяются жестами или внешними компонентами. В этом случае стандартный контрол отключается:

import defaults from 'ol/control/defaults.js';

const map = new Map({
  controls: defaults({
    zoom: false
  })
});

Альтернативой выступают:

  • колесо мыши (mouse wheel zoom interaction)
  • pinch-zoom на сенсорных устройствах
  • программное управление через view.setZoom()

Программное управление масштабом

Zoom-контрол является лишь интерфейсом. Само изменение масштаба доступно напрямую через View:

const view = map.getView();

view.setZoom(8);
view.setZoom(view.getZoom() + 1);
view.animate({
  zoom: 10,
  duration: 300
});

Это позволяет синхронизировать внешние UI-компоненты с картой.

Обработка событий изменения масштаба

View генерирует события при изменении zoom:

map.getView().on('change:zoom', () => {
  console.log('Текущий zoom:', map.getView().getZoom());
});

Это используется для:

  • динамической подгрузки данных
  • изменения стилей слоёв
  • адаптации интерфейса

Ограничения и особенности поведения

Zoom-контрол работает в рамках нескольких ограничений:

  • дискретность уровней тайлов (обычно целые числа)
  • зависимость от maxResolution и minResolution
  • влияние DPI и pixel ratio

При использовании нестандартных проекций поведение zoom может отличаться, так как resolution вычисляется относительно координатной системы.

Использование кастомных контролов вместо стандартного Zoom

При необходимости полного контроля UI создаются кастомные реализации:

import Control from 'ol/control/Control.js';

class CustomZoom extends Control {
  constructor() {
    const element = document.createElement('div');

    const zoomIn = document.createElement('button');
    zoomIn.textContent = '+';

    const zoomOut = document.createElement('button');
    zoomOut.textContent = '−';

    element.appendChild(zoomIn);
    element.appendChild(zoomOut);

    super({ element });

    zoomIn.addEventListener('click', () => {
      const view = this.getMap().getView();
      view.setZoom(view.getZoom() + 1);
    });

    zoomOut.addEventListener('click', () => {
      const view = this.getMap().getView();
      view.setZoom(view.getZoom() - 1);
    });
  }
}

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

Поведение на мобильных устройствах

Zoom-контрол часто дублирует жесты:

  • pinch-to-zoom
  • double tap zoom

На мобильных устройствах кнопки могут быть скрыты и заменены жестовым управлением через ol/interaction/PinchZoom.

Влияние анимации на изменение масштаба

Параметр duration определяет плавность перехода между уровнями zoom. При больших значениях создаётся эффект инерции:

  • 0 — мгновенное переключение
  • 200–300 — стандартная плавность
  • 500+ — выраженная анимация

Анимация выполняется внутри View.animate, что обеспечивает синхронизацию с рендерингом слоёв.

Интеграция Zoom-контрола в сложные интерфейсы

Zoom часто используется совместно с:

  • слайдерами масштаба
  • индикаторами уровня zoom
  • кнопками быстрого перехода (fit, extent)

Пример синхронизации со слайдером:

const slider = document.getElementById('zoomSlider');

slider.addEventListener('input', (e) => {
  map.getView().setZoom(Number(e.target.value));
});

map.getView().on('change:zoom', () => {
  slider.value = map.getView().getZoom();
});

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