Текстовые метки и выноски

В библиотеке Nivo текстовые метки (labels) выступают ключевым инструментом повышения читаемости графиков, позволяя напрямую связывать визуальные элементы с их значениями. Метки используются практически во всех типах визуализаций: столбчатых диаграммах, линейных графиках, круговых диаграммах, диаграммах рассеяния.

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


Базовая модель отображения меток в Nivo

В большинстве компонентов Nivo текстовые метки управляются через параметры label и labelFormat. Эти свойства могут быть строками, функциями или отключаться полностью.

Пример стандартной конфигурации:

<Bar
    data={data}
    keys={['value']}
    indexBy="label"
    label="value"
/>

В этом случае каждая колонка получает подпись, соответствующую значению поля value.

Гибкость Nivo заключается в том, что label может быть функцией:

label={(d) => `${d.value}%`}

Такой подход позволяет формировать динамические подписи, адаптированные под контекст данных.


Форматирование текстовых меток

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

Используются следующие подходы:

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

Пример форматирования:

label={(d) => `${Math.round(d.value / 1000)}k`}

Для более сложных сценариев применяются функции форматирования из d3-format:

import { format } from 'd3-format';

const fmt = format('.2f');

label={(d) => fmt(d.value)}

Управление расположением меток

Расположение меток напрямую влияет на читаемость визуализации. В Nivo для разных типов графиков используются разные стратегии позиционирования.

Внутренние метки

Используются в столбчатых и круговых диаграммах, когда подпись размещается внутри графического элемента.

<Bar
    labelSkipWidth={12}
    labelSkipHeight={12}
/>

Параметры labelSkipWidth и labelSkipHeight позволяют скрывать метки при недостатке пространства.


Внешние метки

Применяются в случаях, когда внутреннее размещение приводит к наложению текста на графические элементы.

В pie chart:

<Pie
    radialLabelsSkipAngle={10}
    radialLabelsTextXOffset={6}
/>

Здесь текст выносится за пределы сектора и соединяется с ним линией-указателем.


Условное отображение меток

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

Пример скрытия малых значений:

label={(d) => d.value > 10 ? d.value : null}

Если функция возвращает null, метка не отображается.

Другой подход — фильтрация по размеру визуального элемента:

labelSkipWidth={20}

Это автоматически отключает подписи для слишком узких столбцов.


Цвет и контраст текстовых меток

Контраст текста с фоном является критическим фактором восприятия. Nivo предоставляет возможность управлять цветом меток через labelTextColor.

Пример динамического выбора цвета:

labelTextColor={(d) =>
    d.color === '#ffffff' ? '#000000' : '#ffffff'
}

Часто используется фиксированная логика:

  • светлый текст на тёмных элементах;
  • тёмный текст на светлых элементах.

В некоторых случаях применяется автоматическое вычисление контраста на основе яркости цвета.


Анимация появления меток

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

animate={true}
motionConfig="stiff"

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

При высокой плотности данных анимацию часто отключают:

animate={false}

Перенос и усечение текста

Длинные подписи могут выходить за пределы доступного пространства. В Nivo отсутствует автоматический перенос строк, поэтому применяется ручное управление.

Подходы:

Усечение строки

label={(d) =>
    d.label.length > 10
        ? d.label.slice(0, 10) + '...'
        : d.label
}

Сокращение через словарь значений

const map = {
    "New York City": "NYC",
    "San Francisco": "SF"
};

label={(d) => map[d.label] || d.label}

Выноски (callouts) как расширение текстовых меток

Выноски используются для выделения отдельных значений, требующих дополнительного контекста. В Nivo они реализуются либо через кастомные слои, либо через annotations в компонентах.

Аннотации как базовый механизм

annotations={[
    {
        type: 'circle',
        match: { index: 3 },
        note: 'Пиковое значение',
        noteX: 30,
        noteY: -30
    }
]}

Выноска включает:

  • точку привязки (match);
  • текст пояснения (note);
  • смещение текста (noteX, noteY);
  • тип соединительной линии.

Линейные выноски для временных рядов

В линейных графиках выноски часто применяются для выделения аномалий или ключевых событий.

annotations={[
    {
        type: 'x',
        value: '2023-01-01',
        note: 'Изменение политики',
        noteX: 0,
        noteY: -40
    }
]}

Такая конструкция создаёт вертикальную линию с текстовым пояснением.


Кастомные выноски через слои

Более сложные сценарии требуют создания собственного слоя (layers), где выноски отрисовываются вручную.

const CustomLayer = ({ nodes }) => (
    <g>
        {nodes.map(node => (
            node.value > 100 && (
                <text
                    x={node.x}
                    y={node.y - 10}
                >
                    {node.value}
                </text>
            )
        ))}
    </g>
);

Подключение слоя:

<Bar
    layers={['grid', 'axes', CustomLayer]}
/>

Поведение выносок при масштабировании

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

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

Пример адаптивного отключения:

annotations={width < 600 ? [] : annotations}

Взаимодействие меток и легенд

Текстовые метки и легенды в Nivo выполняют пересекающиеся функции, однако их использование различается по контексту.

  • метки принадлежат конкретным элементам графика;
  • легенды описывают группы данных;
  • выноски добавляют дополнительный смысл.

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


Производительность при большом количестве меток

При работе с тысячами точек метки становятся фактором, влияющим на производительность. Основные оптимизации:

  • отключение меток для части элементов;
  • использование labelSkip* параметров;
  • рендер только видимых элементов;
  • замена текста на tooltip-подсказки.
enableLabel={false}

В этом режиме текст переносится в интерактивные элементы, снижая нагрузку на DOM.


Связь текстовых меток с доступностью

Текстовые метки выполняют роль не только визуального элемента, но и основы доступности. При правильной настройке они могут использоваться:

  • экранными читалками;
  • экспортируемыми SVG-данными;
  • вспомогательными интерфейсами анализа.

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