Версионирование конфигурации в Kepler.gl становится критически важным элементом при построении масштабируемых аналитических систем, где карты, слои, фильтры и взаимодействия пользователей должны сохраняться, воспроизводиться и эволюционировать без потери совместимости между версиями приложения.
Конфигурация Kepler.gl представляет собой сериализуемый JSON-объект,
включающий состояние визуализации (visState), параметры
карты (mapState) и наборы данных (datasets).
Именно эта структура определяет поведение карты и является основным
кандидатом для версионирования.
Ключевые области конфигурации:
Любое изменение структуры этих блоков между версиями приложения может привести к несовместимости сохранённых конфигураций.
Наиболее распространённый подход — добавление поля версии в корень конфигурации:
{
"version": "1.0.0",
"config": {
"visState": { },
"mapState": { },
"datasets": []
}
}
Поле версии позволяет однозначно определить, какие правила миграции необходимо применить при загрузке конфигурации.
Использование схемы SemVer (MAJOR.MINOR.PATCH) особенно эффективно:
Такой подход облегчает поддержку миграций при обновлении интерфейса визуализации.
Альтернативный метод — вычисление хеша от нормализованного JSON:
import stableStringify from 'fast-json-stable-stringify';
import crypto from 'crypto';
function getConfigHash(config) {
const normalized = stableStringify(config);
return crypto.createHash('sha256').update(normalized).digest('hex');
}
Этот подход позволяет отслеживать любые изменения состояния, включая неявные модификации порядка полей.
Каждая версия конфигурации должна иметь функцию преобразования в следующую:
const migrations = {
"1.0.0": (config) => {
return {
...config,
visState: {
...config.visState,
filters: config.visState.filters || []
}
};
},
"1.1.0": (config) => {
return {
...config,
mapState: {
...config.mapState,
pitch: config.mapState.pitch ?? 0
}
};
}
};
Миграции применяются последовательно до достижения актуальной версии.
function migrateConfig(config, targetVersion) {
let current = config;
let version = config.version;
while (version !== targetVersion) {
const migrate = migrations[version];
if (!migrate) break;
current = migrate(current);
version = getNextVersion(version);
current.version = version;
}
return current;
}
Простейший вариант хранения:
function saveConfig(config) {
localStorage.setItem('kepler_config', JSON.stringify(config));
}
function loadConfig() {
const raw = localStorage.getItem('kepler_config');
return raw ? JSON.parse(raw) : null;
}
Недостаток — отсутствие централизованного управления версиями и миграциями.
При использовании backend-архитектуры конфигурации часто сохраняются в базе данных как JSONB (PostgreSQL) или документ (MongoDB).
Структура записи:
Это позволяет реализовать откат и историю изменений.
Слои Kepler.gl имеют собственную внутреннюю структуру, которая может меняться:
Пример обработки несовместимого слоя:
function normalizeLayer(layer) {
if (!layer.config) {
layer.config = {};
}
return {
...layer,
config: {
opacity: layer.config.opacity ?? 1,
thickness: layer.config.thickness ?? 2
}
};
}
Фильтры часто являются наиболее изменяемой частью состояния:
Поэтому фильтры требуют отдельной стратегии миграции:
function migrateFilter(filter) {
switch (filter.type) {
case 'range':
return {
...filter,
value: Array.isArray(filter.value)
? filter.value
: [filter.value.min, filter.value.max]
};
default:
return filter;
}
}
Отдельно от конфигурации визуализации необходимо версионировать структуру входных данных:
Пример метаданных:
{
"datasetVersion": "2.3.0",
"fields": [
{ "name": "lat", "type": "float" },
{ "name": "lng", "type": "float" }
]
}
При изменении схемы данных конфигурация визуализации может стать некорректной без соответствующей миграции.
Изменения внутри Kepler.gl могут включать:
visStateПоэтому конфигурация должна быть защищена слоем адаптации:
function adaptKeplerConfig(config) {
return {
...config,
visState: adaptVisState(config.visState),
mapState: adaptMapState(config.mapState)
};
}
Для корректного версионирования важно обеспечить детерминированный порядок:
Это позволяет избежать ложных различий между версиями конфигураций.
function normalizeConfig(config) {
return {
...config,
visState: {
...config.visState,
layers: [...config.visState.layers].sort((a, b) => a.id - b.id),
filters: [...config.visState.filters].sort((a, b) => a.id - b.id)
}
};
}
При загрузке устаревшей конфигурации возможны конфликты:
Стратегии обработки:
Развитие системы конфигураций требует строгого контроля изменений:
Применение схемы валидации:
import Ajv from 'ajv';
const ajv = new Ajv();
const validate = ajv.compile(keplerConfigSchema);
function validateConfig(config) {
const valid = validate(config);
if (!valid) {
throw new Error('Invalid configuration');
}
}
Версионирование конфигурации в Kepler.gl становится не вспомогательной задачей, а центральным механизмом стабильности системы визуализации, определяющим возможность долгосрочного развития интерфейса, сохранения пользовательских сценариев и предсказуемого поведения картографических приложений.