Архитектура библиотеки: пакеты, рендереры, провайдеры

Nivo построена как модульная система поверх React и D3-экосистемы, где визуализация декомпозирована на независимые пакеты, единое ядро абстракций и слой провайдеров, отвечающих за контекст, адаптивность и поведение рендеринга. Такая архитектура позволяет поддерживать множество типов графиков при минимальном дублировании логики и высокой согласованности API.

Монорепозиторий и пакетная структура

Архитектура библиотеки основана на монорепозитории, в котором каждый тип визуализации выделен в отдельный пакет. Это обеспечивает:

  • изоляцию зависимостей конкретных графиков;
  • независимое версионирование компонентов внутри общей системы;
  • переиспользование ядра без дублирования логики;
  • единый стиль API при различии внутренних реализаций.

Структура пакетов обычно делится на несколько категорий:

1. Ядро

  • @nivo/core — фундаментальная библиотека абстракций

2. Графики

  • @nivo/bar
  • @nivo/line
  • @nivo/pie
  • @nivo/radar
  • @nivo/heatmap
  • @nivo/geo
  • @nivo/sankey
  • @nivo/treemap
  • @nivo/scatterplot
  • @nivo/stream

Каждый из этих пакетов содержит:

  • компонент верхнего уровня (например, Bar, Line);
  • внутренние примитивы (оси, сетки, слои);
  • адаптер данных;
  • набор вычислительных функций (layout, stacking, scaling).

Ядро @nivo/core

Пакет @nivo/core является центром архитектуры. Он не содержит конкретных графиков, но определяет:

Абстракции масштаба и координат

Используются обёртки над D3-scale:

  • linear scale
  • band scale
  • time scale
  • ordinal scale

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

Система слоёв (layers)

Каждый график в Nivo строится как композиция слоёв:

  • оси (axes)
  • сетка (grid)
  • маркеры данных (bars, dots, arcs)
  • аннотации (markers, annotations)
  • оверлеи (tooltips, crosshair)

Слои описываются декларативно и могут переопределяться пользователем через API компонентов.

Общие утилиты

  • форматирование данных
  • вычисление цветов
  • генерация паттернов
  • обработка событий (hover, click, mouse move)
  • утилиты для анимации

Пакетная специализация графиков

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

Bar chart (@nivo/bar)

  • преобразует категории в band-scale
  • строит прямоугольники через вычисление высоты/ширины
  • поддерживает stacking и grouped layout

Line chart (@nivo/line)

  • использует time/linear scales
  • преобразует точки в SVG-path
  • поддерживает interpolation (linear, monotone, basis)

Pie chart (@nivo/pie)

  • переводит данные в угловые сегменты
  • использует arc generator
  • управляет радиусами через центрированную систему координат

Geo charts (@nivo/geo)

  • интеграция с geo-projection
  • работа с GeoJSON
  • проекции (mercator, natural earth)

Рендереры: SVG, Canvas и гибридная модель

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

SVG-рендеринг

SVG является основным режимом:

  • декларативная модель React идеально совпадает с SVG DOM
  • удобство стилизации через CSS
  • простота взаимодействия (hover, click)

Используется в большинстве стандартных компонентов.

Canvas-рендеринг

Canvas применяется для:

  • больших объёмов данных (тысячи точек)
  • оптимизации перерисовок
  • снижения нагрузки на DOM

Особенности:

  • императивное рисование
  • контроль через requestAnimationFrame
  • отдельные canvas-слои для разных элементов

Гибридный подход

Некоторые графики комбинируют SVG и Canvas:

  • Canvas для геометрии
  • SVG для интерактивных оверлеев

Это позволяет сохранять интерактивность без потери производительности.

Провайдеры и контекстная архитектура

В основе управления состоянием лежит React Context API, через который передаются глобальные настройки визуализации.

ResponsiveProvider

Отвечает за адаптивность:

  • отслеживание размеров контейнера
  • пересчёт графика при resize
  • автоматическое масштабирование

Ключевая идея — график не знает своих размеров заранее.

ThemeProvider

Централизует визуальный стиль:

  • цвета
  • типографика
  • сетки
  • стили осей и подписей

Позволяет переопределять визуальный язык без изменения логики графика.

MotionProvider

Контролирует анимации:

  • включение/выключение motion
  • длительность переходов
  • easing-функции

Анимации реализуются через библиотеку react-motion или аналоги, интегрированные в слой рендера.

Datum и Tooltip контекст

Контексты данных обеспечивают:

  • доступ к текущему элементу графика
  • передачу данных в tooltip
  • синхронизацию hover-состояний

Поток данных в архитектуре Nivo

Внутренний pipeline визуализации можно разложить на последовательные стадии:

1. Входные данные

Исходный массив данных поступает в компонент графика:

  • нормализация структуры
  • проверка ключей
  • маппинг значений

2. Построение шкал

На основе данных формируются scales:

  • domain вычисляется автоматически
  • range зависит от размеров контейнера
  • тип scale выбирается конфигурацией

3. Layout-слой

На этом этапе данные преобразуются в геометрию:

  • bar → прямоугольники
  • line → точки + path
  • pie → arcs
  • treemap → иерархические прямоугольники

4. Generators

Используются генераторы:

  • d3-shape (arc, line, area)
  • кастомные функции для сеток и маркеров

5. Rendering layer

Финальный этап:

  • SVG элементы или Canvas draw calls
  • применение цветов и стилей
  • привязка событий

Компонентная композиция React

Архитектура строится на композиции:

  • верхнеуровневый компонент графика
  • внутренние слои
  • переиспользуемые примитивы

Компоненты разделяются на:

  • presentational (визуальные)
  • container (логика и данные)
  • hooks-based utilities

Это позволяет заменять части графика без изменения ядра.

Хуки и внутренние утилиты

Используются кастомные React hooks:

  • useDimensions — измерение контейнера
  • useScale — работа со шкалами
  • useAnimatedProps — анимации
  • useTheme — доступ к теме
  • useTooltip — управление подсказками

Хуки обеспечивают переносимость логики между разными типами графиков.

Система слоёв как ключевая абстракция

Layer model является одной из центральных концепций:

  • каждый слой — независимая функция рендера
  • слои можно добавлять/удалять
  • порядок слоёв влияет на визуальную композицию

Пример типичного набора:

  • grid
  • axes
  • bars/lines/arcs
  • markers
  • legends
  • annotations

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

Производительность и оптимизации

Архитектура учитывает высокие нагрузки:

  • мемоизация вычислений (React.memo, useMemo)
  • кэширование шкал
  • разделение Canvas слоёв
  • минимизация DOM-операций
  • выборочная перерисовка элементов

Canvas-режим особенно важен для сценариев с десятками тысяч точек, где SVG становится узким местом.

Расширяемость архитектуры

Система спроектирована так, чтобы новые графики могли добавляться без изменения ядра:

  • переиспользование @nivo/core
  • подключение собственных layers
  • кастомные tooltip-реализации
  • альтернативные renderers

Архитектура допускает создание полностью новых типов визуализаций при сохранении стандартного API-компонента React.