Внутри Kepler.gl визуализация строится поверх движка deck.gl. Сам Kepler.gl не рендерит слои напрямую — он формирует декларативное описание слоёв, которое затем преобразуется в экземпляры deck.gl Layer.
Ключевой принцип: все слои Kepler.gl существуют как часть состояния (Redux store), но фактически исполняются deck.gl. Это создаёт возможность перехвата, модификации и расширения визуализации на уровне низкоуровневых API.
Kepler.gl хранит конфигурацию визуализации в нескольких ключевых сегментах состояния:
visState.layers — декларации слоёвvisState.layerData — данные, привязанные к слоямmapState — параметры камеры и координатной системыinteractionConfig — настройки интерактивностиКаждый слой в visState.layers — это не deck.gl объект, а
описательный JSON, который позже трансформируется в
экземпляр слоя.
Пример структуры слоя:
{
id: "layer_1",
type: "point",
config: {
dataId: "trip_data",
columns: {
lat: "pickup_lat",
lng: "pickup_lng"
},
color: [255, 0, 0],
isVisible: true
},
visualChannels: {
colorField: null,
sizeField: null
}
}
На этапе рендеринга Kepler.gl преобразует это в соответствующий
deck.gl слой (например, ScatterplotLayer,
ArcLayer, HexagonLayer и т.д.).
Преобразование происходит в момент построения экземпляра
KeplerGl компонента. Внутри происходит вызов фабрики
слоёв:
visState.layersdeckLayersЭти слои затем передаются в:
new Deck({
layers: deckLayers
})
Таким образом, доступ к deck.gl слоям возможен только после того, как Kepler.gl завершил сборку сцены.
Прямой доступ к deck.gl instance — ключевой способ взаимодействия.
import KeplerGl from 'kepler.gl';
const mapRef = useRef(null);
<KeplerGl
id="map"
width={800}
height={600}
ref={mapRef}
/>
Однако сам ref не всегда предоставляет deck instance напрямую. Более надёжный путь — через store и middleware.
Kepler.gl построен поверх Redux, поэтому слой deck.gl можно извлекать из состояния приложения.
const state = store.getState();
const layers = state.keplerGl.map.visState.layers;
Но это всё ещё декларативное представление. Для получения deck.gl объектов требуется промежуточный слой — selectors.
Kepler.gl предоставляет селекторы, которые позволяют получить уже трансформированные объекты:
import { visStateSelector } from 'kepler.gl/reducers';
const visState = visStateSelector(store.getState().keplerGl.map);
const deckLayers = visState.layers;
В некоторых конфигурациях visState.layers уже содержит
экземпляры deck.gl Layer, а не только конфигурации.
Расширенный способ доступа — Redux middleware.
const layerInterceptor = store => next => action => {
const result = next(action);
if (action.type === 'LAYER_CONFIG_CHANGE') {
const state = store.getState();
const layers = state.keplerGl.map.visState.layers;
console.log(layers);
}
return result;
};
Это позволяет отслеживать момент пересборки deck.gl слоёв.
Kepler.gl использует набор предопределённых слоёв deck.gl:
ScatterplotLayer — точечные данныеLineLayer / ArcLayer — связи между
точкамиPolygonLayer — полигоны и границыHexagonLayer — агрегация плотностиGridLayer — сеточная агрегацияGeoJsonLayer — произвольная геометрияКаждый из них создаётся динамически на основе
layer.type.
Внутренний процесс можно представить так:
KeplerLayer (config)
-> LayerManager
-> LayerFactory
-> DeckGL Layer instance
Пример трансформации:
new ScatterplotLayer({
id: layer.id,
data: layer.data,
getPosition: d => [d.lng, d.lat],
getRadius: layer.config.radius,
getFillColor: layer.config.color
})
После создания слоя можно извлечь его параметры:
deckLayers.forEach(layer => {
console.log(layer.id);
console.log(layer.props);
});
Особенно важны:
data — входной массивupdateTriggers — механизм обновленияaccessor functions — функции извлечения данныхKepler.gl позволяет подменять стандартные слои.
import { CompositeLayer } from '@deck.gl/core';
class CustomLayer extends CompositeLayer {
renderLayers() {
return [
new ScatterplotLayer({
id: `${this.props.id}-scatter`,
data: this.props.data,
getPosition: d => d.position,
getFillColor: [0, 200, 255]
})
];
}
}
Далее слой регистрируется в Kepler.gl через расширение layerManager.
Если доступен deck instance:
const deck = mapRef.current.deck;
const layers = deck.props.layers;
Это наиболее прямой способ получить фактические render-ready объекты.
Любое изменение слоёв должно проходить через actions:
import { addLayer, updateLayer } from 'kepler.gl/actions';
dispatch(updateLayer({
...layer,
config: {
...layer.config,
color: [0, 255, 0]
}
}));
После dispatch происходит:
Важно различать:
visState.layers — логическая модельdeck.gl layers — вычисленный runtime слойЛюбое прямое вмешательство в deck.gl без синхронизации с visState приводит к рассинхронизации UI и состояния.
Deck.gl слои в Kepler.gl пересоздаются при:
Каждое пересоздание вызывает повторную генерацию массива layers, даже если конфигурация изменилась частично.
При работе с большим количеством слоёв важно учитывать:
store.getState() в рендереОсобенно критично это при работе с потоковыми данными и динамическими обновлениями.
Для диагностики можно использовать логирование deck слоёв:
const inspectLayers = () => {
const state = store.getState();
const layers = state.keplerGl.map.visState.layers;
layers.forEach(l => {
console.log({
id: l.id,
type: l.type,
visible: l.config.isVisible
});
});
};
Это позволяет сопоставить UI состояние с фактической визуализацией.
deck.gl генерирует события, которые могут быть перехвачены:
new Deck({
layers,
onClick: info => {
console.log(info.object);
},
onHover: info => {
console.log(info.x, info.y);
}
});
Kepler.gl проксирует эти события через собственную систему interactionConfig, связывая их с Redux actions.
Прямой доступ к deck.gl слоям даёт возможность:
Однако такие операции требуют ручного контроля синхронизации с visState, иначе визуальная модель перестаёт соответствовать состоянию приложения.