Привязка цвета к переменной

Система цветов в библиотеке Nivo поддерживает динамическое управление палитрой через данные, темы, вычисляемые функции и наследование свойств. Один из наиболее важных механизмов — привязка цвета к переменной. Такой подход позволяет визуально связывать категории, состояния, значения или группы данных с определёнными цветами без ручного описания каждого элемента.


Базовая схема работы цветов

Во всех графиках Nivo цвет обычно задаётся через свойство colors. Оно поддерживает несколько форматов:

  • строка;
  • массив цветов;
  • встроенная цветовая схема;
  • функция;
  • объект-конфигурация;
  • наследование от данных.

Простейший пример:

<ResponsiveBar
    data={data}
    keys={['sales']}
    indexBy="month"
    colors="#3b82f6"
/>

В этом случае все столбцы будут окрашены одинаково.


Привязка цвета к полю объекта

Наиболее распространённый способ — использование поля объекта данных как источника цвета.

Структура данных

const data = [
    {
        country: 'Germany',
        population: 83,
        color: '#2563eb'
    },
    {
        country: 'France',
        population: 67,
        color: '#dc2626'
    },
    {
        country: 'Italy',
        population: 59,
        color: '#16a34a'
    }
]

Использование colors

<ResponsiveBar
    data={data}
    keys={['population']}
    indexBy="country"
    colors={({ data }) => data.color}
/>

Что происходит

Каждый элемент получает собственный цвет из свойства color.

Nivo передаёт объект текущей точки данных в callback-функцию:

({ data }) => data.color

Таким образом:

  • Германия → синий;
  • Франция → красный;
  • Италия → зелёный.

Доступные аргументы callback-функции

В большинстве компонентов callback получает объект с подробной информацией:

colors={(bar) => {
    console.log(bar)

    return '#000'
}}

Для Bar доступны:

{
    id,
    value,
    indexValue,
    color,
    data
}

Для Pie:

{
    id,
    label,
    value,
    color,
    data
}

Это позволяет строить сложную цветовую логику.


Привязка цвета к категории

Данные

const data = [
    {
        product: 'Laptop',
        type: 'electronics',
        value: 120
    },
    {
        product: 'Table',
        type: 'furniture',
        value: 80
    },
    {
        product: 'Phone',
        type: 'electronics',
        value: 200
    }
]

Цветовая карта

const categoryColors = {
    electronics: '#2563eb',
    furniture: '#ca8a04'
}

Использование

<ResponsiveBar
    data={data}
    keys={['value']}
    indexBy="product"
    colors={({ data }) => categoryColors[data.type]}
/>

Теперь все элементы категории electronics будут одинакового цвета.


Использование условной логики

Функция позволяет создавать динамическое окрашивание.

Пример: окраска по значению

<ResponsiveBar
    data={data}
    keys={['value']}
    indexBy="name"
    colors={({ value }) => {
        if (value > 100) {
            return '#16a34a'
        }

        if (value > 50) {
            return '#eab308'
        }

        return '#dc2626'
    }}
/>

Результат

  • большие значения → зелёный;
  • средние → жёлтый;
  • маленькие → красный.

Такой подход часто используется:

  • в дашбордах;
  • KPI-графиках;
  • мониторинге;
  • аналитике;
  • heatmap-визуализациях.

Привязка цвета через colorBy

Некоторые компоненты поддерживают свойство colorBy.

Например:

<ResponsivePie
    data={data}
    colorBy="id"
/>

или

<ResponsivePie
    data={data}
    colorBy="label"
/>

Как это работает

Nivo автоматически:

  1. берёт значение поля;
  2. сопоставляет его с палитрой;
  3. назначает цвет.

Цветовые схемы Nivo

Библиотека включает встроенные палитры на основе d3-scale.

Пример

<ResponsivePie
    data={data}
    colors={{ scheme: 'category10' }}
/>

Популярные схемы:

Схема Назначение
category10 категории
accent контрастные цвета
dark2 тёмная палитра
paired парные оттенки
set1 яркие цвета
set2 мягкие цвета
nivo стандартная тема Nivo

Связь схемы с переменной

Пример

<ResponsivePie
    data={data}
    colorBy="id"
    colors={{ scheme: 'set2' }}
/>

Здесь:

  • id становится ключом;
  • каждому уникальному id назначается цвет из set2.

Использование массива цветов

Можно вручную определить палитру.

<ResponsiveBar
    data={data}
    keys={['value']}
    indexBy="name"
    colors={[
        '#2563eb',
        '#dc2626',
        '#16a34a',
        '#eab308'
    ]}
/>

Nivo распределит цвета по порядку.


Динамическая генерация цветов

Пример через HSL

colors={({ index }) => {
    return `hsl(${index * 60}, 70%, 50%)`
}}

Что происходит

Каждый следующий элемент получает новый оттенок:

  • 0°;
  • 60°;
  • 120°;
  • 180°.

Использование данных для вычисления прозрачности

colors={({ value }) => {
    return `rgba(37, 99, 235, ${value / 100})`
}}

Чем больше значение, тем насыщеннее элемент.


Наследование цветов

Nivo поддерживает механизм inherit.

Пример

borderColor={{
    from: 'color',
    modifiers: [
        ['darker', 1.2]
    ]
}}

Что делает from: 'color'

Берётся основной цвет элемента, после чего применяется модификатор.


Модификаторы цвета

Поддерживаются:

Модификатор Описание
darker затемнение
brighter осветление
opacity прозрачность

Пример

labelTextColor={{
    from: 'color',
    modifiers: [
        ['darker', 2]
    ]
}}

Привязка цвета к теме

Создание темы

const theme = {
    axis: {
        ticks: {
            text: {
                fill: '#94a3b8'
            }
        }
    }
}

Использование

<ResponsiveLine
    data={data}
    theme={theme}
/>

Интеграция с CSS-переменными

Nivo хорошо работает с CSS Variables.

CSS

:root {
    --chart-primary: #2563eb;
    --chart-danger: #dc2626;
}

Использование

colors={() => {
    return getComputedStyle(document.documentElement)
        .getPropertyValue('--chart-primary')
}}

Работа с тёмной темой

Обычно используется динамическая палитра.

Пример

const isDark = true

const colors = isDark
    ? ['#60a5fa', '#f87171']
    : ['#2563eb', '#dc2626']
<ResponsivePie
    data={data}
    colors={colors}
/>

Привязка цвета к состоянию элемента

Пример

colors={({ data }) => {
    return data.active
        ? '#16a34a'
        : '#9ca3af'
}}

Используется для:

  • online/offline;
  • success/error;
  • enabled/disabled;
  • selected/unselected.

Цвета в ResponsiveLine

Пример

<ResponsiveLine
    data={data}
    colors={({ id }) => {
        if (id === 'sales') {
            return '#2563eb'
        }

        return '#dc2626'
    }}
/>

Использование defs и fill

Кроме обычных цветов, Nivo поддерживает паттерны и градиенты.

Паттерн

defs={[
    {
        id: 'dots',
        type: 'patternDots',
        background: 'inherit',
        color: 'rgba(255,255,255,0.3)',
        size: 4,
        padding: 1,
        stagger: true
    }
]}

Привязка

fill={[
    {
        match: {
            id: 'france'
        },
        id: 'dots'
    }
]}

Градиенты

Определение

defs={[
    {
        id: 'gradient',
        type: 'linearGradient',
        colors: [
            {
                offset: 0,
                color: '#2563eb'
            },
            {
                offset: 100,
                color: '#60a5fa'
            }
        ]
    }
]}

Использование

fill={[
    {
        match: '*',
        id: 'gradient'
    }
]}

Цвета и легенды

Легенды автоматически наследуют цвет элементов.

legends={[
    {
        anchor: 'bottom',
        direction: 'row'
    }
]}

Если цвет вычисляется динамически, легенда также обновляется автоматически.


Привязка цвета к диапазону значений

Пример

colors={({ value }) => {
    if (value < 20) return '#dc2626'
    if (value < 50) return '#f97316'
    if (value < 80) return '#eab308'

    return '#16a34a'
}}

Такой механизм особенно полезен в:

  • heatmap;
  • gauge;
  • аналитических панелях;
  • системах мониторинга.

Использование d3-scale для цветовых шкал

Nivo построен поверх d3, поэтому можно подключать собственные шкалы.

Пример

import { scaleSequential } from 'd3-scale'
import { interpolateBlues } from 'd3-scale-chromatic'

const colorScale = scaleSequential(interpolateBlues)
    .domain([0, 100])

Использование

colors={({ value }) => colorScale(value)}

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

Функция colors вызывается для каждого элемента.

При больших объёмах данных желательно:

  • избегать тяжёлых вычислений;
  • не создавать объекты внутри callback;
  • кэшировать цветовые карты;
  • использовать useMemo.

Пример

const colorMap = useMemo(() => ({
    sales: '#2563eb',
    profit: '#16a34a'
}), [])

Типичные ошибки

Отсутствие возврата значения

Неверно:

colors={({ data }) => {
    data.color
}}

Верно:

colors={({ data }) => {
    return data.color
}}

Использование несуществующего поля

colors={({ data }) => data.backgroundColor}

Если поле отсутствует, элементы могут стать прозрачными или получить дефолтный цвет.


Несогласованные категории

{
    type: 'Electronics'
}
categoryColors['electronics']

Из-за разного регистра цвет не будет найден.


Архитектурные подходы

Крупные приложения обычно используют централизованную систему цветов.

Пример

export const chartColors = {
    revenue: '#2563eb',
    expenses: '#dc2626',
    profit: '#16a34a'
}

После этого:

colors={({ id }) => chartColors[id]}

Использование вместе с Design System

При интеграции с UI-библиотеками цвета обычно берутся из темы приложения.

Пример с Material UI

const theme = useTheme()

colors={() => theme.palette.primary.main}

Практическая схема организации цветов

Для сложных аналитических интерфейсов часто применяется трёхуровневая структура:

Базовые токены

const palette = {
    blue: '#2563eb',
    red: '#dc2626',
    green: '#16a34a'
}

Семантические цвета

const semantic = {
    success: palette.green,
    danger: palette.red,
    primary: palette.blue
}

Цвета графиков

const charts = {
    sales: semantic.primary,
    errors: semantic.danger
}

Такой подход делает систему визуализации масштабируемой и предсказуемой.