Компонент Bar: вертикальные и горизонтальные столбцы

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

Ключевая особенность реализации заключается в декларативной модели конфигурации: разработчик описывает данные и параметры отображения, а библиотека самостоятельно управляет масштабированием, анимацией и отрисовкой через SVG или Canvas.


Структура данных для Bar

Данные для Bar-чарта в Nivo представляют собой массив объектов, где каждый объект соответствует категории (группе), а его свойства — значения подкатегорий.

const data = [
  {
    country: "Kazakhstan",
    sales: 120,
    profit: 80
  },
  {
    country: "Russia",
    sales: 200,
    profit: 130
  }
];

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

keys={["sales", "profit"]}
indexBy="country"
  • indexBy определяет категорию (ось X или Y в зависимости от ориентации)
  • keys определяет набор числовых метрик

Вертикальные столбцы

Вертикальный Bar-чарт является стандартным вариантом отображения, где категории располагаются по оси X, а значения растут по оси Y.

import { ResponsiveBar } from '@nivo/bar'

<ResponsiveBar
  data={data}
  keys={["sales", "profit"]}
  indexBy="country"
  margin={{ top: 50, right: 130, bottom: 50, left: 60 }}
  padding={0.3}
  axisBottom={{
    tickRotation: -45
  }}
/>

Особенности вертикальной ориентации

  • Категории размещаются горизонтально
  • Значения отображаются вертикальными столбцами
  • Хорошо подходит для сравнений небольшого числа категорий
  • Удобен при длинных числовых диапазонах

Масштабирование

Nivo автоматически применяет линейный масштаб для оси значений. При этом диапазон вычисляется динамически на основе максимального значения всех series.

Важный аспект — контроль padding между столбцами:

  • padding: 0 — плотная упаковка
  • padding: 0.3 — сбалансированный вариант
  • padding > 0.5 — визуально разреженные данные

Горизонтальные столбцы

Горизонтальная ориентация меняет оси местами: категории становятся по вертикали, а значения вытягиваются по горизонтали.

<ResponsiveBar
  data={data}
  keys={["sales", "profit"]}
  indexBy="country"
  layout="horizontal"
  margin={{ top: 50, right: 130, bottom: 50, left: 80 }}
  padding={0.3}
/>

Когда использовать горизонтальные бары

Горизонтальный формат особенно эффективен в следующих случаях:

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

Отличия от вертикального режима

  • Ось категорий переносится в вертикальную плоскость
  • Значения растягиваются вправо
  • axisBottom заменяется на axisLeft как основная категориальная ось
  • требуется увеличенный левый margin для текста

Ключевые параметры Bar-компонента

Bar в Nivo обладает большим количеством настроек, влияющих на поведение и внешний вид.

data, keys и indexBy

data={data}
keys={["sales", "profit"]}
indexBy="country"
  • data — исходный массив
  • keys — набор метрик
  • indexBy — поле группировки

Ошибки конфигурации здесь приводят к пустому графику или NaN-значениям, так как Nivo строго сопоставляет ключи.


margin и padding

margin={{ top: 40, right: 80, bottom: 60, left: 60 }}
padding={0.25}
  • margin отвечает за пространство для осей и подписей
  • padding управляет расстоянием между столбцами внутри категории

valueScale и indexScale

valueScale={{ type: "linear" }}
indexScale={{ type: "band", round: true }}
  • valueScale определяет числовую шкалу (обычно linear)
  • indexScale управляет категорией (band — дискретные группы)

Настройка осей

Оси в Bar-чартах Nivo — это независимые конфигурационные блоки.

Нижняя и левая оси

axisBottom={{
  tickSize: 5,
  tickPadding: 5,
  tickRotation: 0,
  legend: "Страны",
  legendPosition: "middle",
  legendOffset: 40
}}
axisLeft={{
  tickSize: 5,
  tickPadding: 5,
  legend: "Значения",
  legendPosition: "middle",
  legendOffset: -50
}}

Особенности работы осей

  • tickRotation помогает избежать наложения текста
  • legendOffset критичен для читаемости
  • автоматическое вычисление делений происходит через d3-scale внутри Nivo

Цветовые схемы и кастомизация

Цвета можно задавать несколькими способами.

Встроенные схемы

colors={{ scheme: "nivo" }}

Другие схемы:

  • category10
  • accent
  • dark2
  • paired

Функциональная кастомизация

colors={(bar) => {
  if (bar.id === "sales") return "#4caf50";
  return "#2196f3";
}}

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


Подписи значений и метки

Bar-компонент поддерживает отображение значений прямо на столбцах.

labelSkipWidth={12}
labelSkipHeight={12}
labelTextColor="#ffffff"

Логика отображения label

  • если ширина столбца меньше labelSkipWidth, текст скрывается
  • аналогично для высоты
  • автоматически предотвращает визуальный шум

Группировка и стековая модель

Bar может работать в двух режимах: grouped и stacked.

Grouped Bars

groupMode="grouped"
  • столбцы располагаются рядом
  • удобно для сравнения метрик

Stacked Bars

groupMode="stacked"
  • значения складываются друг над другом
  • подходит для анализа структуры общего значения

Пример интерпретации:

  • grouped → сравнение компонентов
  • stacked → вклад в общий результат

Анимации

Nivo использует плавные переходы на основе интерполяции значений.

animate={true}
motionConfig="gentle"

Параметры анимации

  • motionConfig: "wobbly" — более выраженные эффекты
  • gentle — стандартный баланс
  • stiff — минимальная инерция

Анимации применяются к:

  • изменению высоты столбцов
  • смене данных
  • переключению режимов grouped/stacked

Tooltip и интерактивность

Tooltip позволяет отображать детализированную информацию при наведении.

tooltip={({ id, value, color }) => (
  <div style={{ padding: 12 }}>
    <strong style={{ color }}>{id}</strong>: {value}
  </div>
)}

Поведение tooltip

  • привязан к конкретному bar-segment
  • обновляется в реальном времени при hover
  • поддерживает кастомные компоненты React

Canvas и SVG режимы

Bar может отрисовываться двумя способами:

  • SVG (по умолчанию)
  • Canvas (для больших данных)
<ResponsiveBar
  data={data}
  renderWrapper={false}
/>

Canvas режим предпочтителен при:

  • тысячах элементов
  • ограниченной производительности браузера
  • мобильных устройствах

SVG предпочтителен при:

  • необходимости стилизации через CSS
  • небольшом количестве данных
  • высокой точности взаимодействия

Сравнение вертикального и горизонтального Bar

Вертикальный вариант

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

Горизонтальный вариант

  • улучшенная читаемость длинных подписей
  • масштабируемость по количеству категорий
  • удобство при аналитических списках

Практика компоновки интерфейса

Bar-чарты часто используются внутри dashboard-систем и аналитических панелей. В таких случаях важны:

  • ограничение высоты контейнера через Responsive wrapper
  • контроль перерисовки при изменении данных
  • согласование цветов с общей дизайн-системой
<div style={{ height: 400 }}>
  <ResponsiveBar {...props} />
</div>

Без фиксированной высоты компонент не сможет корректно вычислить размеры SVG-контейнера.


Поведение при пустых или некорректных данных

Bar-компонент ожидает корректный числовой ввод. При нарушении структуры возможны:

  • отсутствие рендера
  • NaN в шкале значений
  • пропуск серий

Типичная защита:

const safeData = data.filter(d => typeof d.sales === "number")

Управление порядком серий

Порядок отображения определяется массивом keys:

keys={["profit", "sales"]}

Это влияет на:

  • порядок stack
  • порядок grouped bars
  • легенду

Legend и описание серий

legends={[
  {
    dataFrom: "keys",
    anchor: "bottom-right",
    direction: "column",
    translateX: 120,
    itemWidth: 100,
    itemHeight: 20
  }
]}

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


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

При работе с большими наборами данных критичны:

  • использование Canvas-рендера
  • минимизация кастомных tooltip
  • отключение лишних анимаций
animate={false}
motionConfig="none"

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


Поведение при ресайзе

ResponsiveBar автоматически пересчитывает:

  • ширину столбцов
  • масштаб осей
  • положение легенд

Важное ограничение: контейнер должен иметь ненулевые размеры при первом рендере, иначе график не инициализируется корректно.