В библиотеке OpenLayers управление масштабом карты основано не на дискретных «ступенях приближения», а на модели разрешения (resolution) и уровня зума (zoom), между которыми существует прямое преобразование. Это позволяет строить как мгновенные переходы, так и плавные анимации с интерполяцией состояний камеры карты.
Ключевая идея: карта в OpenLayers — это не просто набор тайлов, а камера, которая может изменять масштаб непрерывно, а уже слой тайлов подстраивается под текущий resolution.
Каждому уровню zoom соответствует определённое разрешение:
В стандартной конфигурации используется логарифмическая зависимость:
import Map from 'ol/Map.js';
import View from 'ol/View.js';
const view = new View({
center: [0, 0],
zoom: 2
});
Внутри View хранится непрерывное значение resolution, даже если zoom кажется дискретным.
Основной механизм плавного изменения зума — метод
animate.
view.animate({
zoom: 10,
duration: 1200
});
Этот вызов не устанавливает zoom мгновенно, а интерполирует текущее состояние камеры до целевого значения.
Пример комбинированной анимации:
view.animate({
center: [1000000, 6000000],
zoom: 8,
duration: 1500
});
Плавность определяется не только временем, но и функцией интерполяции.
Типовые функции:
Пример:
import { easeOut } from 'ol/easing.js';
view.animate({
zoom: 12,
duration: 1000,
easing: easeOut
});
Easing влияет на восприятие движения: при easeOut приближение кажется «естественным», поскольку камера замедляется перед остановкой.
Колёсико мыши является главным источником резких скачков масштаба. Для сглаживания используется настройка interaction.
import MouseWheelZoom from 'ol/interaction/MouseWheelZoom.js';
const map = new Map({
target: 'map',
view: view,
interactions: [
new MouseWheelZoom({
duration: 400
})
]
});
При увеличении duration движение становится более «кинематографичным», но может снижаться отзывчивость.
Один из ключевых аспектов плавности — сохранение точки фокуса.
new MouseWheelZoom({
useAnchor: true,
duration: 300
});
При включённом anchor:
Это создаёт эффект естественного приближения к месту интереса.
Часто требуется не просто изменить масштаб, а «перелететь» к объекту с масштабированием.
view.animate({
center: [3560000, 5390000],
zoom: 14,
duration: 2000
});
При необходимости усиления эффекта добавляется промежуточная стадия:
view.animate({
zoom: view.getZoom() + 2,
duration: 500
}, {
center: [3560000, 5390000],
zoom: 14,
duration: 1500
});
Так создаётся эффект ступенчатого приближения с последующим наведением.
Плавность масштабирования напрямую зависит от диапазона допустимых значений:
const view = new View({
center: [0, 0],
zoom: 5,
minZoom: 2,
maxZoom: 18
});
При узком диапазоне переходы становятся резче, поскольку меньше пространства для интерполяции.
При работе с тайловыми картами важно, чтобы zoom соответствовал дискретным уровням tile grid.
const view = new View({
constrainResolution: true,
smoothResolutionConstraint: true
});
Эффект:
smoothResolutionConstraint создаёт промежуточное сглаживание, даже если итоговые уровни дискретны.
На сенсорных экранах используется PinchZoom interaction:
import PinchZoom from 'ol/interaction/PinchZoom.js';
new PinchZoom({
duration: 200
});
Особенности поведения:
При слишком высокой нагрузке возможны пропуски кадров, что визуально нарушает плавность.
Внутренне OpenLayers почти всегда работает через resolution:
view.animate({
resolution: view.getResolution() * 0.5,
duration: 1000
});
Это позволяет:
Плавное масштабирование часто сочетается с перемещением камеры:
view.animate({
center: [2000000, 5000000],
zoom: 6,
duration: 1200,
easing: easeInOut
});
При сложных траекториях используется цепочка анимаций:
view.animate({
center: [1000000, 4000000],
duration: 600
}, {
zoom: 12,
duration: 900
});
Каждый шаг обрабатывается как отдельная стадия интерполяции.
Плавный зум требует постоянного пересчёта:
Критические факторы:
При перегрузке возможны:
Векторные слои реагируют на zoom иначе, чем растровые:
При анимации важно учитывать, что промежуточные значения zoom существуют постоянно, поэтому стили могут изменяться плавно:
style: function(feature, resolution) {
return new Style({
strokeWidth: Math.max(1, 10 / resolution)
});
}
Инерционность создаётся сочетанием:
Дополнительный эффект достигается через увеличение duration при быстром скролле и уменьшение при одиночных событиях.
В сложных приложениях часто комбинируются параметры:
const view = new View({
center: [0, 0],
zoom: 3,
smoothResolutionConstraint: true,
constrainResolution: true,
minZoom: 1,
maxZoom: 20
});
И взаимодействия:
new MouseWheelZoom({
duration: 250,
useAnchor: true
});
Так достигается баланс между: