Понятие View и управление видом карты

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

Архитектурно View отделён от объекта карты (Map). Карта отвечает за отображение слоёв и взаимодействие с пользователем, а View хранит параметры отображения пространства координат.

Наиболее важные характеристики объекта View:

  • центр карты (center);
  • масштабирование (zoom);
  • разрешение (resolution);
  • поворот карты (rotation);
  • ограничения масштаба и области просмотра;
  • методы анимации и программного управления отображением.

Схематически взаимодействие выглядит следующим образом:

Map
 ├── Layers
 ├── Controls
 ├── Interactions
 └── View
       ├── Center
       ├── Zoom
       ├── Resolution
       └── Rotation

Без объекта View карта не может определить, какой участок данных необходимо отображать.


Создание объекта View

Обычно объект создаётся одновременно с картой.

import Map from 'ol/Map';
import View from 'ol/View';

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

Здесь задаются два основных параметра:

  • center — координаты центра карты;
  • zoom — начальный уровень масштабирования.

Центр карты

Центр определяет координаты точки, которая будет находиться в середине окна карты.

const view = new View({
    center: [4180000, 7500000],
    zoom: 5
});

Получение текущего центра:

const center = view.getCenter();

console.log(center);

Изменение центра:

view.setCenter([5000000, 7000000]);

После вызова метода карта автоматически перерисуется.


Системы координат и центр карты

По умолчанию OpenLayers использует проекцию Web Mercator (EPSG:3857).

Поэтому координаты центра обычно задаются не в градусах широты и долготы, а в метрах.

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

import { fromLonLat } from 'ol/proj';

const view = new View({
    center: fromLonLat([37.6176, 55.7558]),
    zoom: 10
});

Здесь:

  • 37.6176 — долгота;
  • 55.7558 — широта.

После преобразования карта будет центрирована на Москве.


Масштабирование карты

Параметр zoom определяет уровень детализации.

const view = new View({
    center: [0, 0],
    zoom: 4
});

Получение текущего масштаба:

const zoom = view.getZoom();

Установка нового масштаба:

view.setZoom(8);

Увеличение масштаба:

view.setZoom(view.getZoom() + 1);

Уменьшение масштаба:

view.setZoom(view.getZoom() - 1);

Чем больше значение масштаба, тем ближе отображается карта.

Примерная зависимость:

Zoom Масштаб
0 Весь мир
3 Континенты
6 Страны
10 Города
15 Районы
18+ Улицы и здания

Понятие Resolution

Внутри OpenLayers основным параметром отображения является не масштаб, а разрешение (resolution).

Разрешение показывает количество метров на пиксель.

Например:

const resolution = view.getResolution();

Установка разрешения:

view.setResolution(500);

Чем меньше значение разрешения:

  • тем больше увеличение;
  • тем выше детализация.

Связь между масштабом и разрешением вычисляется автоматически.

Поэтому разработчики чаще работают через zoom, а OpenLayers преобразует его в resolution.


Управление поворотом карты

Объект View поддерживает вращение карты.

Поворот задаётся в радианах.

const view = new View({
    center: [0, 0],
    zoom: 5,
    rotation: Math.PI / 4
});

Здесь карта повернётся на 45 градусов.

Получение текущего угла:

const rotation = view.getRotation();

Изменение угла:

view.setRotation(Math.PI / 2);

Сброс поворота:

view.setRotation(0);

Ограничение масштаба

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

Для этого используются параметры:

const view = new View({
    center: [0, 0],
    zoom: 5,
    minZoom: 2,
    maxZoom: 18
});

Теперь:

  • меньше 2 карта не уменьшится;
  • больше 18 карта не увеличится.

Такие ограничения часто применяются при работе с собственными тайловыми слоями.


Ограничение разрешения

Вместо масштаба можно ограничивать разрешение.

const view = new View({
    center: [0, 0],
    minResolution: 5,
    maxResolution: 10000
});

Подобный подход используется в специализированных ГИС-приложениях, где требуется точный контроль отображения.


Ограничение области просмотра

Иногда требуется запретить перемещение карты за пределы определённого региона.

Для этого используется параметр extent.

const view = new View({
    center: [0, 0],
    zoom: 5,
    extent: [
        -5000000,
        -5000000,
         5000000,
         5000000
    ]
});

Структура массива:

[minX, minY, maxX, maxY]

Пользователь не сможет прокручивать карту за границы указанного прямоугольника.


Получение текущего состояния View

Объект предоставляет методы доступа ко всем ключевым параметрам.

const center = view.getCenter();
const zoom = view.getZoom();
const resolution = view.getResolution();
const rotation = view.getRotation();

Пример:

console.log({
    center: view.getCenter(),
    zoom: view.getZoom(),
    rotation: view.getRotation()
});

Подобная информация часто используется для сохранения пользовательского состояния интерфейса.


Перемещение карты к заданной точке

Простейший способ изменить отображение — установить новый центр.

view.setCenter(
    fromLonLat([30.3141, 59.9386])
);

После выполнения карта переместится к Санкт-Петербургу.

Одновременно можно изменить масштаб.

view.setCenter(
    fromLonLat([30.3141, 59.9386])
);

view.setZoom(12);

Использование метода fit()

Метод fit() автоматически подбирает центр и масштаб таким образом, чтобы заданная область полностью поместилась на экране.

view.fit([
    4000000,
    7000000,
    5000000,
    8000000
]);

После вызова:

  • вычисляется подходящий центр;
  • рассчитывается оптимальный масштаб;
  • весь прямоугольник становится видимым.

Подгонка под размеры элемента

Обычно метод используется вместе с геометриями.

const extent = feature
    .getGeometry()
    .getExtent();

view.fit(extent);

Если объект находится далеко от текущей области просмотра, карта автоматически переместится к нему.


Отступы при использовании fit()

Для предотвращения прилипания объекта к краям окна используются внутренние отступы.

view.fit(extent, {
    padding: [50, 50, 50, 50]
});

Порядок значений:

[top, right, bottom, left]

Анимация отображения карты

Метод animate() позволяет плавно изменять параметры отображения.

Пример плавного перемещения:

view.animate({
    center: fromLonLat([37.6176, 55.7558]),
    duration: 2000
});

Карта переместится в течение двух секунд.


Анимация масштабирования

view.animate({
    zoom: 12,
    duration: 1500
});

Переход будет происходить плавно.


Одновременное изменение нескольких параметров

view.animate({
    center: fromLonLat([37.6176, 55.7558]),
    zoom: 10,
    rotation: Math.PI / 6,
    duration: 3000
});

Изменяются сразу:

  • положение карты;
  • масштаб;
  • угол поворота.

Последовательные анимации

Метод позволяет создавать цепочки переходов.

view.animate(
    {
        zoom: 5,
        duration: 1000
    },
    {
        center: fromLonLat([37.6176, 55.7558]),
        duration: 1000
    },
    {
        zoom: 12,
        duration: 1000
    }
);

Последовательность будет следующей:

  1. уменьшение масштаба;
  2. перемещение;
  3. увеличение масштаба.

Такой эффект часто используется для навигации между объектами.


Получение объекта View из карты

Если объект создавался внутри карты, получить его можно через метод getView().

const view = map.getView();

После этого становятся доступны все методы управления отображением.

view.setZoom(10);
view.setCenter(
    fromLonLat([37.6176, 55.7558])
);

Отслеживание изменений состояния

Объект View генерирует события изменения параметров.

Отслеживание масштаба:

view.on('change:resolution', () => {
    console.log(view.getZoom());
});

Отслеживание центра:

view.on('change:center', () => {
    console.log(view.getCenter());
});

Отслеживание поворота:

view.on('change:rotation', () => {
    console.log(view.getRotation());
});

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


Сохранение состояния карты

Частая задача — сохранять текущую позицию карты между сеансами работы.

view.on('change:center', saveState);
view.on('change:resolution', saveState);

function saveState() {
    localStorage.setItem(
        'mapState',
        JSON.stringify({
            center: view.getCenter(),
            zoom: view.getZoom()
        })
    );
}

Восстановление состояния:

const state = JSON.parse(
    localStorage.getItem('mapState')
);

if (state) {
    view.setCenter(state.center);
    view.setZoom(state.zoom);
}

Основные методы объекта View

Наиболее востребованные методы:

Метод Назначение
getCenter() Получение центра
setCenter() Установка центра
getZoom() Получение масштаба
setZoom() Установка масштаба
getResolution() Получение разрешения
setResolution() Установка разрешения
getRotation() Получение угла поворота
setRotation() Установка угла поворота
fit() Подгонка области под экран
animate() Плавное изменение параметров
calculateExtent() Получение текущей видимой области

Метод calculateExtent()

Иногда требуется узнать координаты участка карты, который отображается в текущий момент.

const extent = view.calculateExtent(
    map.getSize()
);

console.log(extent);

Результат:

[
    minX,
    minY,
    maxX,
    maxY
]

Эти данные используются для:

  • загрузки объектов в пределах экрана;
  • пространственных запросов;
  • кластеризации;
  • оптимизации производительности.

Практический пример управления видом карты

import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import { fromLonLat } from 'ol/proj';

const view = new View({
    center: fromLonLat([37.6176, 55.7558]),
    zoom: 8,
    minZoom: 3,
    maxZoom: 18
});

const map = new Map({
    target: 'map',
    layers: [
        new TileLayer({
            source: new OSM()
        })
    ],
    view: view
});

document
    .getElementById('zoomIn')
    .addEventListener('click', () => {
        view.setZoom(
            view.getZoom() + 1
        );
    });

document
    .getElementById('zoomOut')
    .addEventListener('click', () => {
        view.setZoom(
            view.getZoom() - 1
        );
    });

document
    .getElementById('goToMoscow')
    .addEventListener('click', () => {
        view.animate({
            center: fromLonLat([37.6176, 55.7558]),
            zoom: 12,
            duration: 2000
        });
    });

Данный пример демонстрирует основные возможности объекта View:

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