Регистрация новых типов слоёв

Система слоёв строится поверх deck.gl и наследует его модель декларативного описания визуальных примитивов. Каждый слой представляет собой независимую визуализацию геоданных, описанную через набор параметров: данные, стилизация, фильтры и поведение интерактивности.

Внутри Kepler.gl слой не является изолированным классом — он интегрирован в состояние visState, где хранится список активных слоёв и их конфигурации. Добавление новых типов слоёв требует расширения двух ключевых уровней:

  • регистрация фабрики слоя (layer factory)
  • интеграция в менеджер визуального состояния (visState reducer)

Базовая модель слоя

Каждый слой в системе описывается структурой:

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

Интеграция через reducer visState

Основная логика регистрации типов слоёв может быть встроена в 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);
  }
};

Таким образом, система становится расширяемой без модификации ядра.


Использование deck.gl кастомных слоёв

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:

  • цвет (color)
  • размер (size)
  • высота (height)
  • прозрачность (opacity)

Добавление нового канала требует расширения маппинга:

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

Ограничения архитектуры слоёв

Модель расширения слоёв накладывает ряд структурных ограничений:

  • строгая декларативность конфигурации
  • отсутствие прямого DOM-доступа
  • обязательная сериализация состояния
  • зависимость от deck.gl rendering pipeline

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