Работа с temporal данными

Работа с временными (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 временная ось не является отдельной сущностью ядра библиотеки, но реализуется через комбинацию источников данных, фильтров и параметров запросов к сервисам.

Временные слои и параметр TIME

Наиболее распространённый подход — использование временного измерения через серверные сервисы, такие как WMS с параметром TIME.

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'
  })
});

Изменение времени приводит к перезапросу тайлов и обновлению визуализации.

Динамическое обновление TIME

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 });
}

Проблема несогласованности временных шагов решается через нормализацию:

  • фиксированный шаг (например, 1 час)
  • дискретизация временной шкалы
  • серверная агрегация

Кэширование временных данных

Временные слои создают нагрузку из-за постоянных перезапросов. Оптимизация включает:

  • HTTP caching с учётом TIME
  • tile cache partitioned by time
  • локальное хранение уже загруженных временных срезов

Пример ключа кэша:

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);
};

Потоковые данные требуют:

  • дедупликации
  • ограниченного окна отображения
  • удаления устаревших объектов

Окно времени (time window)

Для больших потоков данных применяется скользящее окно:

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

При использовании WebGL-рендерера временная логика может переноситься на GPU:

  • фильтрация по uniform времени
  • интерполяция позиций
  • анимация без перерисовки источника

Это критично для больших наборов данных (десятки тысяч объектов).

Интерполяция между временными состояниями

Для плавной анимации используется интерполяция:

function lerp(a, b, t) {
  return a + (b - a) * t;
}

Применение к координатам:

const x = lerp(x1, x2, t);
const y = lerp(y1, y2, t);

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

Временные индексы и предобработка данных

Для ускорения фильтрации создаются индексы:

  • сортированные массивы timestamp
  • B-tree структуры
  • разбиение по временным чанкам

Пример структуры:

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'
}

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