В библиотеке Nivo система подсказок построена как слой визуальной интерактивности, отделённый от базовой отрисовки графика. Каждый график, будь то столбчатый, линейный или круговой, предоставляет стандартный механизм активации hover-состояния, на основе которого вычисляется контекст подсказки: серия данных, индекс элемента, координаты и метаданные визуального слоя.
Подсказки в Nivo реализуются через декларативные свойства компонентов, где поведение tooltip задаётся через пропсы уровня графика, а не через императивное управление DOM. Это обеспечивает единообразие интерфейса между различными типами визуализаций.
Ключевым принципом является разделение ответственности:
Во всех компонентах семейства Nivo (ResponsiveBar, ResponsiveLine, ResponsivePie и других) подсказка активируется при наведении на элемент данных. В момент hover библиотека формирует объект данных, содержащий:
Этот объект передаётся в tooltip renderer.
Типовая конфигурация:
<ResponsiveBar
data={data}
keys={['sales']}
indexBy="month"
tooltip={({ id, value, color }) => (
<div style={{ padding: 8, background: 'white' }}>
<strong style={{ color }}>{id}</strong>: {value}
</div>
)}
/>
В данном случае tooltip заменяет стандартный рендерер и получает полный доступ к данным активного элемента.
Внутренне tooltip в Nivo работает как функция:
tooltip: (node: TooltipProps) => ReactNode
Где TooltipProps может включать:
Это позволяет строить tooltip не только как текстовую подсказку, но как полноценный UI-компонент с логикой.
В ResponsiveBar tooltip связан с отдельным баром. При
наведении библиотека определяет активный прямоугольник и передаёт его
контекст.
Расширенная настройка:
<ResponsiveBar
data={data}
keys={['sales', 'profit']}
indexBy="month"
tooltip={({ id, value, color, indexValue }) => (
<div>
<div>{indexValue}</div>
<div style={{ color }}>{id}</div>
<div>{value}</div>
</div>
)}
/>
Особенность bar tooltip заключается в наличии
indexValue, который отражает категорию оси X (например,
месяц). Это делает подсказку многомерной: одновременно отображается
категория и серия.
В stacked bar charts tooltip получает дополнительные данные о сегменте стека, что позволяет различать вклад каждого слоя.
В ResponsiveLine система подсказок работает на уровне
точек (points). Каждая точка представляет собой вычисленное значение
линии.
<ResponsiveLine
data={data}
tooltip={({ point }) => (
<div>
<div>{point.data.xFormatted}</div>
<div>{point.serieId}</div>
<div>{point.data.yFormatted}</div>
</div>
)}
/>
В отличие от bar charts, здесь tooltip оперирует:
Nivo заранее вычисляет форматированные версии, чтобы избежать повторного форматирования при каждом рендере tooltip.
Отдельный механизм — slice tooltips, активируемый через
useMesh или enableSlices.
Slice представляет вертикальный или горизонтальный срез всех линий в конкретной координате X.
<ResponsiveLine
data={data}
useMesh={true}
sliceTooltip={({ slice }) => (
<div>
<strong>{slice.points[0].data.xFormatted}</strong>
{slice.points.map(point => (
<div key={point.id}>
{point.serieId}: {point.data.yFormatted}
</div>
))}
</div>
)}
/>
В этом режиме tooltip агрегирует несколько серий одновременно. Это критически важно для сравнительных графиков, где требуется видеть значения всех линий в одной точке.
Система slice-tooltip формирует массив slice.points,
каждый элемент которого содержит точку из соответствующей серии.
В ResponsivePie tooltip привязан к сегменту дуги. Каждый
сектор передаёт данные:
<ResponsivePie
data={data}
tooltip={({ datum }) => (
<div>
<div style={{ color: datum.color }}>{datum.label}</div>
<div>{datum.value}</div>
<div>{datum.formattedValue}</div>
</div>
)}
/>
Дополнительно Pie charts часто используют центрированные
tooltip-эффекты через arcLinkLabels или внешние
overlay-компоненты, но базовая система остаётся той же: активный сегмент
→ datum → tooltip renderer.
Nivo допускает передачу полноценного React-компонента вместо функции:
const CustomTooltip = ({ id, value, color }) => {
return (
<div style={{
padding: 10,
border: `1px solid ${color}`,
background: '#fff'
}}>
<div>{id}</div>
<div>{value}</div>
</div>
);
};
<ResponsiveBar
data={data}
keys={['value']}
indexBy="label"
tooltip={CustomTooltip}
/>
Такой подход позволяет:
Tooltip становится полноценной частью React tree, а не просто функцией отображения.
Nivo предоставляет несколько уровней форматирования:
valueFormat)axisLeft.format)<ResponsiveBar
data={data}
keys={['value']}
valueFormat={value => `${value.toFixed(2)} ₽`}
tooltip={({ value }) => (
<div>{value.toLocaleString()}</div>
)}
/>
Часто используется разделение:
value — сырое значениеformattedValue — подготовленное значениеЭто позволяет избежать дублирования логики форматирования между осью и tooltip.
Встроенная система темы Nivo позволяет управлять стилем tooltip глобально:
theme={{
tooltip: {
container: {
background: '#1e1e1e',
color: '#fff',
fontSize: 12,
borderRadius: 4
}
}
}}
Tooltip получает стили из темы, если не переопределён вручную.
Приоритет применения стилей:
Таким образом обеспечивается предсказуемая иерархия визуального оформления.
Tooltip в Nivo оптимизирован под минимальные перерисовки. Основные механизмы:
В сложных графиках (тысячи точек) используется spatial indexing, чтобы быстро определять ближайший элемент.
Особенно это заметно в:
Tooltip можно отключать или ограничивать:
<ResponsiveBar
data={data}
keys={['value']}
enableLabel={false}
tooltip={() => null}
/>
Также можно использовать условное отображение:
tooltip={({ value }) => value > 100 ? <div>{value}</div> : null}
Это позволяет строить контекстные подсказки, зависящие от бизнес-логики.
Nivo использует систему layers, где tooltip фактически является отдельным overlay-слоем. Это означает:
В bar charts это прямоугольники, в line charts — точки или mesh, в pie charts — arcs.
useMesh hover зависит от точности
попадания в точкуЭти особенности связаны с тем, что tooltip не является самостоятельной сущностью, а отражает состояние интерактивного слоя графика.
Несмотря на различия визуализаций, Nivo поддерживает унифицированный подход:
Это делает возможным перенос логики tooltip между графиками без переписывания структуры, изменяется только контекст данных, но не принцип их обработки.