Работа с временными (temporal) данными в OpenLayers строится вокруг
идеи изменяющегося состояния геоданных во времени, где
каждый слой или объект может иметь привязку к моменту времени или
интервалу. Временная ось в веб-картах обычно выражается через стандарты
ISO 8601, Unix timestamp или объекты Date, а сама логика
отображения сводится к фильтрации, стилевым изменениям и управлению
источниками данных в зависимости от текущего времени.
Ключевая особенность временных данных в картографии — необходимость синхронизации трёх уровней:
В JavaScript экосистеме временные значения обычно приводятся к единому виду:
Date — базовый объект для операций с датойnumber — Unix timestamp (миллисекунды)string — ISO 8601
(2026-06-06T12:00:00Z)При работе с временными слоями важно избегать смешения локального времени и UTC. Большинство серверных картографических сервисов ожидают именно UTC.
Пример нормализации времени:
const time = new Date("2026-06-06T12:00:00Z");
const timestamp = time.getTime();
const iso = time.toISOString();
В рамках OpenLayers временная ось не является отдельной сущностью ядра библиотеки, но реализуется через комбинацию источников данных, фильтров и параметров запросов к сервисам.
Наиболее распространённый подход — использование временного измерения
через серверные сервисы, такие как WMS с параметром
TIME.
Серверы GeoServer, MapServer и аналогичные реализуют временные слои
через стандарт OGC. В OpenLayers это выражается через передачу параметра
TIME в запросах:
import TileLayer from 'ol/layer/Tile.js';
import TileWMS from 'ol/source/TileWMS.js';
const layer = new TileLayer({
source: new TileWMS({
url: 'https://example.com/geoserver/wms',
params: {
'LAYERS': 'weather:temperature',
'TIME': '2026-06-06T00:00:00Z'
},
serverType: 'geoserver'
})
});
Изменение времени приводит к перезапросу тайлов и обновлению визуализации.
function setTime(layer, isoTime) {
const source = layer.getSource();
source.updateParams({
TIME: isoTime
});
}
Этот механизм лежит в основе временных слайдеров и анимаций.
Векторные данные часто содержат временные атрибуты внутри
Feature. Это наиболее гибкий способ реализации temporal
логики.
Пример структуры GeoJSON:
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [71.4304, 51.1284]
},
"properties": {
"timestamp": "2026-06-06T10:00:00Z",
"value": 42
}
}
import VectorSource from 'ol/source/Vector.js';
const source = new VectorSource({
url: 'data.geojson',
format: new GeoJSON()
});
function filterByTime(features, time) {
return features.filter(f => {
const t = new Date(f.get('timestamp')).getTime();
return t <= time;
});
}
Более эффективный подход — использование loader
функции:
const source = new VectorSource({
loader: function(extent, resolution, projection) {
fetch('data.geojson')
.then(r => r.json())
.then(data => {
const format = new GeoJSON();
const features = format.readFeatures(data);
const filtered = features.filter(f => {
const t = new Date(f.get('timestamp')).getTime();
return t <= Date.now();
});
source.addFeatures(filtered);
});
}
});
Временная ось часто отражается не только в видимости объектов, но и в их визуальном представлении.
import Style from 'ol/style/Style.js';
import CircleStyle from 'ol/style/Circle.js';
import Fill from 'ol/style/Fill.js';
const styleFunction = (feature) => {
const timestamp = new Date(feature.get('timestamp')).getTime();
const now = Date.now();
const age = now - timestamp;
const opacity = Math.max(1 - age / 10000000, 0);
return new Style({
image: new CircleStyle({
radius: 6,
fill: new Fill({
color: `rgba(255, 0, 0, ${opacity})`
})
})
});
};
Подобный подход используется для визуализации потоков событий, перемещения объектов и исторических данных.
Анимация временной оси реализуется через изменение глобального состояния времени и обновление слоёв.
let currentTime = new Date("2026-06-06T00:00:00Z").getTime();
function step() {
currentTime += 60000;
wmsLayer.getSource().updateParams({
TIME: new Date(currentTime).toISOString()
});
requestAnimationFrame(step);
}
step();
Для векторных данных:
function animateVector(source, time) {
const features = source.getFeatures();
features.forEach(f => {
const t = new Date(f.get('timestamp')).getTime();
f.setStyle(t <= time ? visibleStyle : hiddenStyle);
});
}
Часто данные имеют не точечное время, а интервал активности:
{
"start": "2026-06-06T00:00:00Z",
"end": "2026-06-06T06:00:00Z"
}
function inInterval(feature, time) {
const start = new Date(feature.get('start')).getTime();
const end = new Date(feature.get('end')).getTime();
return time >= start && time <= end;
}
Интервальная модель особенно важна для:
При работе с несколькими источниками критично поддерживать единый временной контекст.
function updateAllLayers(time) {
const iso = new Date(time).toISOString();
temperatureLayer.getSource().updateParams({ TIME: iso });
precipitationLayer.getSource().updateParams({ TIME: iso });
windLayer.getSource().updateParams({ TIME: iso });
}
Проблема несогласованности временных шагов решается через нормализацию:
Временные слои создают нагрузку из-за постоянных перезапросов. Оптимизация включает:
Пример ключа кэша:
layer:temperature:2026-06-06T10:00:00Z:z10:x512:y384
Особую сложность создают:
Рекомендуемая практика — хранение всех временных данных в UTC и преобразование только на уровне UI.
const utc = new Date(localTime).toISOString();
При работе с live-данными (IoT, трекинг, телеметрия) используется потоковая модель:
const socket = new WebSocket('wss://example.com/stream');
socket.onmess age = (event) => {
const data = JSON.parse(event.data);
const feature = new Feature({
geometry: new Point(data.coordinates),
timestamp: data.time
});
vectorSource.addFeature(feature);
};
Потоковые данные требуют:
Для больших потоков данных применяется скользящее окно:
const WINDOW_MS = 3600000; // 1 час
function pruneFeatures(source) {
const now = Date.now();
source.getFeatures().forEach(f => {
const t = new Date(f.get('timestamp')).getTime();
if (now - t > WINDOW_MS) {
source.removeFeature(f);
}
});
}
При использовании WebGL-рендерера временная логика может переноситься на GPU:
Это критично для больших наборов данных (десятки тысяч объектов).
Для плавной анимации используется интерполяция:
function lerp(a, b, t) {
return a + (b - a) * t;
}
Применение к координатам:
const x = lerp(x1, x2, t);
const y = lerp(y1, y2, t);
Такой подход используется в трекинге объектов между дискретными измерениями.
Для ускорения фильтрации создаются индексы:
Пример структуры:
2026-06-06/
00.geojson
01.geojson
02.geojson
Это снижает стоимость клиентской фильтрации.
OGC-совместимые серверы поддерживают:
TIME (точка)START/END (интервал)ELEVATION как дополнительное измерениеOpenLayers взаимодействует с ними через параметры источника, не реализуя временную модель самостоятельно, а делегируя её серверу.
Типичный комбинированный запрос:
params: {
LAYERS: 'satellite:clouds',
TIME: '2026-06-06T12:00:00Z',
CQL_FILTER: 'cloud_cover < 50'
}
Такой подход позволяет выполнять предварительную фильтрацию на сервере и уменьшать объём данных на клиенте.