Система слоёв строится поверх deck.gl и наследует его модель декларативного описания визуальных примитивов. Каждый слой представляет собой независимую визуализацию геоданных, описанную через набор параметров: данные, стилизация, фильтры и поведение интерактивности.
Внутри Kepler.gl слой не является изолированным классом — он
интегрирован в состояние visState, где хранится список
активных слоёв и их конфигурации. Добавление новых типов слоёв требует
расширения двух ключевых уровней:
Каждый слой в системе описывается структурой:
{
id: 'custom-layer',
type: 'customType',
config: {
dataId: 'dataset_1',
columns: {
lat: 'latitude',
lng: 'longitude'
},
isVisible: true
},
visualChannels: {
colorField: null,
sizeField: null
}
}
Ключевое поле type определяет, какой класс или фабрика
будет использоваться для построения визуализации.
Регистрация нового типа слоя осуществляется через создание layer factory, совместимого с интерфейсом Kepler.gl:
export const CustomLayerFactory = {
layerName: 'CustomLayer',
// идентификатор типа слоя
type: 'custom',
// создание deck.gl слоя
buildLayer: (layer, { data, config }) => {
return new CustomDeckLayer({
id: layer.id,
data,
getPosition: d => [d.lng, d.lat],
getColor: config.color || [255, 0, 0],
pickable: true
});
},
// преобразование данных слоя
formatLayerData: (data, layer) => {
return data;
},
// дефолтная конфигурация
defaultProps: {
color: [0, 128, 255]
}
};
Фабрика становится связующим звеном между состоянием Kepler.gl и конкретной реализацией слоя на уровне deck.gl.
Чтобы Kepler.gl распознал новый тип слоя, требуется расширение списка доступных фабрик:
import KeplerGl from 'kepler.gl';
import { addDataToMap } from 'kepler.gl/actions';
const customLayers = {
custom: CustomLayerFactory
};
const mapConfig = {
visState: {
layers: [
{
id: 'custom-layer-1',
type: 'custom',
config: {
dataId: 'points',
columns: {
lat: 'lat',
lng: 'lng'
}
}
}
]
}
};
Далее расширение передаётся в store через middleware или enhancer:
const store = createStore(
rootReducer,
applyMiddleware(
keplerGlReducer.initialState({
customLayers
})
)
);
Основная логика регистрации типов слоёв может быть встроена в
visStateReducer:
const enhancedVisStateReducer = (state, action) => {
switch (action.type) {
case 'REGISTER_CUSTOM_LAYER':
return {
...state,
layerClasses: {
...state.layerClasses,
[action.payload.type]: action.payload.factory
}
};
default:
return keplerGlVisStateReducer(state, action);
}
};
Таким образом, система становится расширяемой без модификации ядра.
Kepler.gl не ограничивает типы визуализации стандартным набором слоёв. Любой слой deck.gl может быть встроен при условии соответствия интерфейсу:
import { Layer } from '@deck.gl/core';
class CustomDeckLayer extends Layer {
initializeState() {}
draw({ uniforms }) {
const { data } = this.props;
data.forEach(d => {
// WebGL отрисовка
});
}
}
Фабрика Kepler.gl просто оборачивает этот слой и управляет его жизненным циклом.
Для полноценной интеграции нового слоя требуется расширение UI-конфигурации:
const customLayerUI = {
color: {
type: 'color',
label: 'Цвет слоя',
defaultValue: [255, 0, 0]
},
intensity: {
type: 'number',
label: 'Интенсивность',
min: 0,
max: 1
}
};
Эта схема связывается с layer.config и передаётся в
фабрику через props.
Kepler.gl выполняет предварительную нормализацию данных перед передачей в слой:
function prepareLayerData(data, layer) {
const { columns } = layer.config;
return data.map(row => ({
position: [row[columns.lng], row[columns.lat]],
raw: row
}));
}
Эта стадия позволяет унифицировать входной формат независимо от источника данных.
Любой новый тип слоя обязан поддерживать сериализацию в
mapState:
function serializeCustomLayer(layer) {
return {
id: layer.id,
type: layer.type,
config: layer.config
};
}
При восстановлении состояния слой должен корректно реконструироваться через фабрику.
Слои Kepler.gl взаимодействуют с глобальными фильтрами
visState.filters. Для поддержки фильтрации в кастомных
слоях требуется явная обработка:
function applyFilters(data, filters) {
return data.filter(d => {
return filters.every(f => {
if (f.name === 'time') {
return d.time >= f.value[0] && d.time <= f.value[1];
}
return true;
});
});
}
Система визуальных каналов определяет, какие параметры слоя могут управляться через UI:
Добавление нового канала требует расширения маппинга:
const visualChannels = {
colorField: {
type: 'color',
accessor: 'getColor'
},
radiusField: {
type: 'size',
accessor: 'getRadius'
}
};
В runtime возможно добавление новых типов без пересборки приложения:
store.dispatch({
type: 'REGISTER_CUSTOM_LAYER',
payload: {
type: 'custom',
factory: CustomLayerFactory
}
});
После регистрации новый слой становится доступным через интерфейс добавления слоёв.
Слои наследуют глобальные стили карты: освещение, базовая подложка, цветовая схема. Для отключения наследования используется явная конфигурация:
const layerConfig = {
enableLighting: false,
mapStyle: 'dark'
};
Модель расширения слоёв накладывает ряд структурных ограничений:
Эти ограничения обеспечивают предсказуемость рендеринга и совместимость между версиями слоёв и движка визуализации.