Создание собственных панелей

В библиотеке Kepler.gl интерфейс построен вокруг набора управляемых панелей, каждая из которых отвечает за отдельный аспект конфигурации карты: слои, фильтры, стили, взаимодействия и экспорт. Панели реализованы как React-компоненты и тесно связаны с состоянием Redux, где хранится вся логика визуализации.

Ключевая особенность системы панелей заключается в том, что она не является жёстко зафиксированной. Интерфейс допускает расширение и переопределение стандартных компонентов, включая добавление собственных панелей, модификацию существующих и полную замену UI-структуры.

Основные контейнеры, влияющие на панели:

  • uiState — отвечает за состояние интерфейса (открытие/закрытие панелей, режимы отображения)
  • visState — хранит слои, фильтры, взаимодействия
  • mapState — параметры камеры и позиционирования карты
  • mapStyle — визуальное оформление карты

Панели в Kepler.gl представляют собой визуальные проекции этих слоёв состояния.


Механизм расширения интерфейса через injectComponents

Основной способ создания собственных панелей основан на механизме внедрения компонентов через injectComponents. Эта функция позволяет переопределять внутренние части интерфейса без изменения исходного кода библиотеки.

Структура переопределения выглядит следующим образом:

import KeplerGl from 'kepler.gl';
import {injectComponents} from 'kepler.gl/components';

const CustomPanel = () => {
  return (
    <div className="custom-panel">
      <h3>Дополнительная панель</h3>
    </div>
  );
};

const myInjectedComponents = injectComponents([
  [KeplerGl.Panels.LayerPanel, CustomPanel]
]);

При такой конфигурации стандартная панель слоёв заменяется на пользовательскую реализацию.


Переопределение стандартных панелей

Внутренняя структура Kepler.gl разделяет панели на несколько ключевых типов:

  • PanelHeader
  • LayerPanel
  • FilterPanel
  • MapControlPanel
  • SidePanel

Каждый из этих компонентов может быть заменён или расширен.

Пример замены заголовка панели:

import {injectComponents} from 'kepler.gl/components';
import KeplerGl from 'kepler.gl';

const CustomHeader = ({title}) => {
  return (
    <div className="custom-header">
      <span>{title}</span>
      <button>Действие</button>
    </div>
  );
};

export default injectComponents([
  [KeplerGl.PanelHeaderFactory, CustomHeader]
]);

Переопределение фабрик компонентов обеспечивает сохранение внутренней логики Kepler.gl при изменении визуального слоя.


Добавление полностью новых панелей

Добавление новой панели требует не только визуального компонента, но и интеграции с состоянием Redux и системой UI-стейта.

Основной подход включает три шага:

  1. Создание React-компонента панели
  2. Подключение к Redux-состоянию
  3. Регистрация панели в uiState

Пример структуры новой панели

import React from 'react';
import {connect} from 'react-redux';

const AnalysisPanel = ({datasets}) => {
  return (
    <div className="analysis-panel">
      <h4>Аналитика данных</h4>
      <div>Количество наборов: {datasets.length}</div>
    </div>
  );
};

const mapStateToProps = state => ({
  datasets: state.keplerGl.map.datasets
});

export default connect(mapStateToProps)(AnalysisPanel);

Интеграция панели в UI state

Для отображения новой панели требуется зарегистрировать её в uiState:

dispatch({
  type: 'ADD_CUSTOM_PANEL',
  payload: {
    panelId: 'analysis',
    title: 'Аналитика',
    component: 'AnalysisPanel'
  }
});

Далее UI должен быть расширен так, чтобы учитывать новый panelId при рендеринге боковой панели.


Работа с SidePanel и управление вкладками

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

Ключевые аспекты:

  • управление активной вкладкой через uiState.activeSidePanel
  • динамическое формирование списка вкладок
  • синхронизация с Redux actions

Пример логики выбора вкладки:

const mapStateToProps = state => ({
  activePanel: state.keplerGl.uiState.activeSidePanel
});

Расширение списка вкладок требует модификации конфигурации интерфейса:

const panels = [
  {id: 'layers', label: 'Слои'},
  {id: 'filters', label: 'Фильтры'},
  {id: 'analysis', label: 'Аналитика'}
];

Интеграция с состоянием визуализации (visState)

Панели часто взаимодействуют с visState, поскольку именно он содержит ключевую информацию о слоях и фильтрах.

Пример доступа к слоям внутри кастомной панели:

const mapStateToProps = state => ({
  layers: state.keplerGl.map.visState.layers
});

Типичные операции, выполняемые через панели:

  • добавление слоёв
  • изменение параметров визуализации
  • управление фильтрами
  • настройка интерактивности

Создание панели управления слоями

Расширение стандартной панели слоёв позволяет добавлять дополнительные настройки, например бизнес-логику поверх геоданных.

const ExtendedLayerPanel = ({layers}) => {
  return (
    <div>
      {layers.map(layer => (
        <div key={layer.id}>
          <strong>{layer.config.label}</strong>
          <div>Тип: {layer.type}</div>
        </div>
      ))}
    </div>
  );
};

Такой подход используется для построения специализированных аналитических интерфейсов поверх базовой геовизуализации.


Управление стилями панелей

Панели Kepler.gl используют CSS-in-JS и классовую систему. Для кастомных панелей обычно применяется изолированная стилизация, чтобы избежать конфликтов с базовой темой.

Ключевые подходы:

  • использование namespace классов
  • переопределение theme через mapStyle
  • изоляция контейнеров панели

Пример:

.custom-panel {
  padding: 12px;
  background: #1a1a1a;
  color: #ffffff;
}

Встраивание интерактивных элементов в панели

Панели могут содержать сложные UI-элементы: формы, графики, переключатели режимов визуализации.

Пример интерактивного элемента:

const ControlPanel = ({setFilter}) => {
  return (
    <div>
      <button onCl ick={() => setFilter('date')}>
        Фильтр по дате
      </button>
    </div>
  );
};

Связь с Redux action:

dispatch({
  type: 'ADD_FILTER',
  payload: {
    dataId,
    filter: {
      name: 'date'
    }
  }
});

Переиспользование внутренних компонентов Kepler.gl

Для ускорения разработки часто используются внутренние компоненты библиотеки:

  • UI элементы кнопок и селекторов
  • базовые контейнеры панелей
  • системные хелперы для действий

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


Расширение логики через middleware Redux

В сложных случаях панели не ограничиваются UI и напрямую взаимодействуют с middleware:

  • перехват действий добавления слоёв
  • трансформация данных перед визуализацией
  • синхронизация с внешними API

Пример middleware:

const customMiddleware = store => next => action => {
  if (action.type === 'ADD_LAYER') {
    console.log('Добавление слоя:', action.payload);
  }
  return next(action);
};

Синхронизация кастомных панелей с состоянием карты

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

  • актуальность данных слоёв
  • изменения фильтров в реальном времени
  • переключение режимов отображения
  • обновление UI при изменении visState

Без синхронизации интерфейс быстро теряет согласованность с визуализацией, особенно при работе с большими геоданными и динамическими источниками данных.