В системе рендеринга MapLibre GL JS слой является декларативным описанием того, как конкретный тип географических данных должен отображаться на карте. Каждый слой содержит набор свойств стиля, которые делятся на две большие группы: layout-параметры (определяют структуру и размещение геометрии) и paint-параметры (отвечают за визуальное оформление).
Анимация в контексте слоёв MapLibre GL JS связана преимущественно с изменением paint-свойств во времени. Архитектура движка основана на WebGL и декларативном стиле описания, поэтому «анимация» не является встроенной сущностью уровня CSS keyframes, а реализуется через интерполяцию значений, выражения (expressions) и программное обновление стиля.
Каждый слой в стиле описывается JSON-структурой:
id — идентификатор слояtype — тип (fill, line, circle, symbol, heatmap и
др.)source — источник данныхpaint — визуальные свойстваlayout — структурные свойстваПрямое изменение свойств слоя мгновенно приводит к перерендеру. Это означает, что без дополнительных механизмов перехода любые изменения будут «резкими».
Ключевое ограничение: MapLibre GL JS не хранит историю состояний слоя, поэтому анимация всегда строится как промежуточная интерполяция между двумя значениями.
Анимация строится на трёх базовых подходах:
Каждый подход имеет собственную область применения и ограничения.
В стилях MapLibre GL JS можно задать глобальные параметры перехода:
map.setStyle({
version: 8,
sources: {...},
layers: [...],
transition: {
duration: 1000,
delay: 0
}
});
Также переходы можно задавать точечно:
map.setPaintProperty('water-layer', 'fill-opacity-transition', {
duration: 800,
delay: 0
});
Или напрямую изменять значение:
map.setPaintProperty('water-layer', 'fill-opacity', 0.5);
При изменении свойства движок:
Интерполяция линейная по умолчанию, но может быть уточнена через expressions.
Наиболее мощный механизм анимации основан на выражении
interpolate.
Пример изменения прозрачности в зависимости от зума:
'fill-opacity': [
'interpolate',
['linear'],
['zoom'],
5, 0.2,
10, 0.8
]
Здесь значение автоматически изменяется при изменении zoom-уровня карты.
Для более сложных сценариев используется программное изменение свойств.
let opacity = 0;
function animate() {
opacity += 0.01;
map.setPaintProperty('building-layer', 'fill-opacity', opacity);
if (opacity < 1) {
requestAnimationFrame(animate);
}
}
animate();
Этот подход даёт полный контроль над траекторией изменения.
requestAnimationFrame синхронизируется с частотой обновления экрана. Это критично для MapLibre GL JS, так как WebGL-рендерер работает в том же цикле кадров.
Типовой шаблон:
const start = performance.now();
const duration = 2000;
function animate(time) {
const t = Math.min((time - start) / duration, 1);
const eased = t * t * (3 - 2 * t); // smoothstep
map.setPaintProperty('roads', 'line-width', 1 + eased * 5);
if (t < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
Цветовые свойства в MapLibre GL JS поддерживают интерполяцию по компонентам.
Пример изменения цвета линии:
map.setPaintProperty('route', 'line-color', [
'interpolate',
['linear'],
['zoom'],
5, 'rgb(0, 0, 255)',
10, 'rgb(255, 0, 0)'
]);
При этом движок разбивает цвет на каналы:
Каждый канал интерполируется отдельно, что обеспечивает визуально гладкие переходы.
Одним из наиболее часто используемых свойств является прозрачность:
fill-opacityline-opacityicon-opacitytext-opacityПример:
map.setPaintProperty('city-labels', 'text-opacity', [
'interpolate',
['linear'],
['zoom'],
8, 0,
12, 1
]);
Такой подход используется для появления подписей при увеличении масштаба.
Свойство line-width часто используется для визуализации
динамики маршрутов:
map.setPaintProperty('highways', 'line-width', [
'interpolate',
['exponential', 1.5],
['zoom'],
5, 1,
14, 10
]);
Экспоненциальная интерполяция создаёт более «естественное» увеличение толщины.
Для circle слоёв часто применяется изменение
радиуса:
map.setPaintProperty('points', 'circle-radius', [
'interpolate',
['linear'],
['zoom'],
5, 2,
15, 20
]);
Также используется пульсация:
let radius = 5;
let direction = 1;
function pulse() {
radius += direction * 0.2;
if (radius > 15 || radius < 5) direction *= -1;
map.setPaintProperty('pulse-layer', 'circle-radius', radius);
requestAnimationFrame(pulse);
}
pulse();
Heatmap-слои обладают специфическими свойствами:
heatmap-weightheatmap-intensityheatmap-radiusПример динамического усиления:
map.setPaintProperty('heat', 'heatmap-intensity', [
'interpolate',
['linear'],
['zoom'],
5, 1,
12, 3
]);
Изменение этих параметров создаёт эффект «разгорания» тепловой карты при приближении.
Хотя filter не является визуальным свойством, он часто
используется для анимации появления объектов.
let step = 0;
function animateFilter() {
step += 0.02;
map.setFilter('places', [
'<=',
['get', 'importance'],
step
]);
if (step < 1) {
requestAnimationFrame(animateFilter);
}
}
animateFilter();
Таким образом происходит постепенное «проявление» объектов по атрибуту данных.
Реальные сценарии часто требуют синхронного изменения нескольких параметров.
Пример анимации маршрута:
function animateRoute(t) {
map.setPaintProperty('route', 'line-width', 2 + t * 6);
map.setPaintProperty('route', 'line-opacity', t);
map.setPaintProperty('route', 'line-blur', (1 - t) * 5);
}
Такая комбинация создаёт эффект «рисования линии».
Анимация в MapLibre GL JS работает в рамках WebGL pipeline, поэтому существуют важные ограничения:
setPaintProperty могут вызывать лагиОптимизационные практики:
Встроенные expressions позволяют переносить логику анимации в декларативную модель:
['interpolate',
['linear'],
['zoom'],
0, 0,
10, 1
]
Преимущества:
Многие анимации зависят от состояния камеры:
Пример:
map.setPaintProperty('buildings', 'fill-extrusion-height', [
'interpolate',
['linear'],
['zoom'],
15, 0,
16, ['get', 'height']
]);
Это создаёт эффект «вырастания» зданий при приближении.
Для сложных визуализаций используется обновление source данных:
map.getSource('points').setData({
type: 'FeatureCollection',
features: updatedFeatures
});
Если данные содержат временные параметры, можно реализовать анимацию движения объектов (например, транспорта).
В реальных приложениях применяются следующие паттерны:
Каждый из них может комбинироваться с другими, образуя сложные визуальные системы.
Поведение анимации в MapLibre GL JS можно формализовать как:
Эта модель обеспечивает высокую производительность при условии корректного выбора механизма анимации и минимизации лишних перерисовок.