Режим split map

Режим split map представляет собой механизм одновременного отображения нескольких картографических сцен в одном интерфейсе с синхронизацией состояния или независимым управлением. Он используется для сравнительного анализа пространственных данных, оценки изменений во времени, сопоставления слоёв или визуализации альтернативных сценариев на одной географической области.

В основе режима лежит идея разделения визуального пространства на несколько независимых вьюпортов, каждый из которых может содержать собственный набор слоёв, фильтров и настроек камеры. При этом Kepler.gl поддерживает как полную синхронизацию взаимодействий (панорамирование, зум, вращение), так и частичную или полную независимость карт.


Архитектурная модель split map

Внутренне Kepler.gl оперирует единым состоянием приложения, однако при активации split map состояние логически разделяется на несколько view states:

  • viewState A
  • viewState B
  • (в расширенных конфигурациях — viewState N)

Каждый viewState включает:

  • координаты центра карты (latitude, longitude)
  • уровень масштаба (zoom)
  • угол вращения (bearing)
  • наклон (pitch)

Параллельно каждому viewState могут быть привязаны:

  • наборы слоёв (layers)
  • фильтры (filters)
  • временные диапазоны (animationConfig)

Базовая конфигурация split map

Активация режима осуществляется через конфигурацию интерфейса:

const mapConfig = {
  mapState: {
    latitude: 55.751244,
    longitude: 37.618423,
    zoom: 10
  },
  splitMaps: {
    enabled: true,
    views: [
      {
        id: 'left-map',
        mapState: {
          latitude: 55.751244,
          longitude: 37.618423,
          zoom: 10
        }
      },
      {
        id: 'right-map',
        mapState: {
          latitude: 55.751244,
          longitude: 37.618423,
          zoom: 12
        }
      }
    ]
  }
};

Ключевой параметр splitMaps.enabled включает механизм разбиения интерфейса. Массив views определяет количество отображаемых карт.


Синхронизация состояний карт

Одним из центральных механизмов split map является синхронизация состояний. Она может быть реализована в нескольких режимах:

Полная синхронизация

Все изменения в одной карте отражаются на другой:

  • перемещение карты
  • изменение масштаба
  • вращение
  • наклон

Такой режим полезен при сравнении различных слоёв на одной и той же области.

Частичная синхронизация

Синхронизируются только отдельные параметры:

  • только координаты центра
  • только zoom
  • без вращения

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

Каждая карта управляется отдельно, используется для анализа разных регионов или временных срезов.


Пример синхронизации через состояние

function syncViewStates(sourceViewState, targetViewState) {
  return {
    ...targetViewState,
    latitude: sourceViewState.latitude,
    longitude: sourceViewState.longitude,
    zoom: sourceViewState.zoom,
    bearing: sourceViewState.bearing,
    pitch: sourceViewState.pitch
  };
}

В реальной архитектуре Kepler.gl это реализуется через Redux-стор, где обновление одного viewState может триггерить обновление другого через middleware.


Использование split map для сравнения слоёв

Одним из наиболее частых сценариев является сравнение двух наборов данных:

  • слева: данные за 2020 год
  • справа: данные за 2025 год

Каждая карта содержит собственный набор слоёв:

const layersLeft = [
  {
    id: 'population-2020',
    type: 'hexagon',
    data: data2020,
    config: {
      colorRange: [255, 200, 0]
    }
  }
];

const layersRight = [
  {
    id: 'population-2025',
    type: 'hexagon',
    data: data2025,
    config: {
      colorRange: [0, 150, 255]
    }
  }
];

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


Управление фильтрами в split map

Фильтры в Kepler.gl могут быть:

  • глобальными (общими для всех карт)
  • локальными (привязанными к конкретному view)

Пример локальных фильтров:

const filters = {
  left: [
    {
      id: 'year-filter',
      dataId: 'dataset-left',
      field: 'year',
      value: [2020, 2020]
    }
  ],
  right: [
    {
      id: 'year-filter',
      dataId: 'dataset-right',
      field: 'year',
      value: [2025, 2025]
    }
  ]
};

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


Работа с камерой и ограничениями viewport

Каждый split view имеет собственную камеру WebGL сцены. Это означает, что:

  • WebGL context может быть разделён логически
  • отрисовка происходит в отдельных контейнерах
  • ресурсы GPU распределяются между сценами

Важно учитывать производительность при использовании:

  • большого количества слоёв
  • сложных heatmap и hexagon слоёв
  • 3D extrusion

Координация событий между картами

Kepler.gl позволяет перехватывать события взаимодействия пользователя:

  • onMapMove
  • onZoom
  • onClick
  • onHover

Пример обработки синхронизации движения:

function handleMapMove(sourceId, viewState) {
  if (sourceId === 'left-map') {
    updateViewState('right-map', {
      latitude: viewState.latitude,
      longitude: viewState.longitude,
      zoom: viewState.zoom
    });
  }
}

Такой механизм часто реализуется через единый event bus или Redux action middleware.


Разделение слоёв и производительности

При использовании split map важно учитывать дублирование рендеринга:

  • каждый слой может существовать в двух экземплярах
  • геометрические вычисления повторяются
  • увеличивается нагрузка на GPU

Оптимизация включает:

  • использование shared data sources
  • мемоизацию вычислений
  • отключение анимаций на одной из карт
  • упрощение стилей для вторичного viewport

Интерактивное сравнение данных

Split map часто используется для аналитических задач:

  • сравнение трафика
  • анализ плотности населения
  • визуализация климатических изменений
  • мониторинг логистики

Пример сценария:

  • левая карта: базовая линия
  • правая карта: текущие данные
  • синхронизированный zoom и pan
  • независимые фильтры времени

Управление состоянием через Redux

Внутренняя архитектура Kepler.gl основана на Redux, где split map представляется как расширение state tree:

const initialState = {
  mapState: {
    splitMaps: {
      left: {},
      right: {}
    }
  }
};

Reducer обновляет конкретный view:

function mapStateReducer(state, action) {
  switch (action.type) {
    case 'UPDATE_SPLIT_VIEW':
      return {
        ...state,
        splitMaps: {
          ...state.splitMaps,
          [action.viewId]: {
            ...state.splitMaps[action.viewId],
            ...action.payload
          }
        }
      };
    default:
      return state;
  }
}

Проблемы и ограничения split map

Несмотря на гибкость, режим имеет ряд технических ограничений:

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

Особенно критично при работе с:

  • миллионами точек
  • 3D слоями
  • частыми обновлениями данных в реальном времени

Поведение при взаимодействии с таймлайнами

Если используется временная анимация, каждая карта может:

  • иметь собственный playback state
  • синхронизировать временную шкалу
  • работать в режиме сравнения разных периодов

Пример независимых таймлайнов:

splitMaps: {
  left: {
    animationConfig: {
      currentTime: 1609459200
    }
  },
  right: {
    animationConfig: {
      currentTime: 1672444800
    }
  }
}

Использование в аналитических интерфейсах

Split map часто становится основой BI-интерфейсов:

  • сравнение KPI по регионам
  • визуализация A/B сценариев
  • анализ аномалий
  • геопространственная валидация данных

Особенность подхода заключается в том, что визуальное сравнение заменяет необходимость сложных таблиц и отчётов.