Тултип
Включён по умолчанию: при наведении показывается ближайший узел, сам узел подсвечивается, остальные серии приглушаются.
Модульная сборка
В сборке через grafit-charts/core тултип — отдельный модуль: register(tooltipModule).
По умолчанию тултип показывает значение xField заголовком и пару «имя серии: значение» с маркером серии. Исключение — точечные серии (scatter, bubble): у них обе оси — измерения, поэтому заголовок обозначает серию (маркер + name), а значения выводятся подписанными строками — xName: x, yName: y, у bubble ещё sizeName: size. Содержимое настраивается через tooltip.renderer на серии:
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';
const rub = new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB', maximumFractionDigits: 0 });
export function createOptions(): ChartOptions {
return {
data: getData(),
title: { text: 'Orders this week' },
series: [
{
type: 'bar',
xField: 'day',
yField: 'orders',
name: 'Orders',
tooltip: {
// renderer returns the tooltip structure; datum gives access to the whole data row
renderer: ({ datum, yValue, color }) => ({
heading: `${datum.day} — ${yValue} orders`,
rows: [{ label: 'Revenue', value: rub.format(datum.revenue as number), color }],
}),
},
},
],
legend: { enabled: false },
};
}export function getData() {
return [
{ day: 'Mon', orders: 142, revenue: 388000 },
{ day: 'Tue', orders: 158, revenue: 412000 },
{ day: 'Wed', orders: 149, revenue: 395500 },
{ day: 'Thu', orders: 173, revenue: 460200 },
{ day: 'Fri', orders: 196, revenue: 540800 },
{ day: 'Sat', orders: 224, revenue: 618400 },
{ day: 'Sun', orders: 201, revenue: 552300 },
];
}Режимы
mode: 'single' (по умолчанию) показывает значение ближайшего узла; mode: 'shared' — значения всех видимых серий категории одним тултипом; подсвечиваются узлы всех серий, приглушение не применяется:
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';
export function createOptions(): ChartOptions {
return {
data: getData(),
title: { text: 'Shared tooltip' },
subtitle: { text: "mode: 'shared' + range: 'nearest' — tooltip from anywhere" },
series: [
{ type: 'line', xField: 'month', yField: 'plan', name: 'Plan' },
{ type: 'line', xField: 'month', yField: 'fact', name: 'Actual' },
{ type: 'line', xField: 'month', yField: 'forecast', name: 'Forecast', lineDash: [4, 3] },
],
tooltip: { mode: 'shared', range: 'nearest' },
crosshair: { enabled: true },
};
}export function getData() {
return [
{ month: 'Jan', plan: 120, fact: 134, forecast: 128 },
{ month: 'Feb', plan: 125, fact: 118, forecast: 124 },
{ month: 'Mar', plan: 130, fact: 142, forecast: 136 },
{ month: 'Apr', plan: 135, fact: 129, forecast: 133 },
{ month: 'May', plan: 140, fact: 151, forecast: 146 },
{ month: 'Jun', plan: 145, fact: 148, forecast: 150 },
];
}Режим означает одно и то же везде, где серии делят категорию: радар несёт по мере на серию так же, как линейный график, поэтому спица под курсором отвечает сразу за все, — и так же ведут себя роза и радиальные столбцы, у которых общая угловая ось.
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';
export function createOptions(): ChartOptions {
return {
data: getData(),
title: { text: 'Shared tooltip on a radar' },
subtitle: { text: "mode: 'shared' — every measure of the spoke under the cursor" },
series: [
{ type: 'radar-line', angleField: 'metric', radiusField: 'alpha', name: 'Alpha' },
{ type: 'radar-line', angleField: 'metric', radiusField: 'beta', name: 'Beta' },
{ type: 'radar-line', angleField: 'metric', radiusField: 'gamma', name: 'Gamma' },
],
tooltip: { mode: 'shared' },
};
}export function getData() {
return [
{ metric: 'Speed', alpha: 8.1, beta: 6.4, gamma: 4.9 },
{ metric: 'Quality', alpha: 7.4, beta: 8.6, gamma: 6.1 },
{ metric: 'Coverage', alpha: 5.2, beta: 7.1, gamma: 8.4 },
{ metric: 'Uptime', alpha: 9.0, beta: 8.2, gamma: 7.6 },
{ metric: 'Cost', alpha: 4.5, beta: 6.8, gamma: 8.9 },
{ metric: 'Support', alpha: 6.3, beta: 5.4, gamma: 7.2 },
];
}Опции (chart-level)
| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
enabled | boolean | true | показывать тултип |
mode | 'single' | 'shared' | 'single' | один узел или вся категория |
position.anchorTo | 'node' | 'center' | 'pointer' | 'node' | край узла, центр узла или курсор |
position.xOffset | Pixels | 0 | смещение тултипа |
yOffset | Pixels | 0 | смещение тултипа |
range | Pixels | 'exact' | 'nearest' | 30 | число — радиус в px; 'exact' — только попадание в узел; 'nearest' — ближайший узел из любого места области построения |
container | 'chart' | 'body' | HTMLElement | 'chart' | где живёт элемент тултипа — см. Вне графика |
zIndex | number | 10; вне графика — 1000 | CSS z-index элемента тултипа |
Вне графика
Тултип — DOM-элемент внутри контейнера графика, прижатый к его границам. В плитке дашборда с overflow: hidden или на графике высотой в несколько десятков пикселей места ему не хватает: тултип обрезается или закрывает сам график. container: 'body' переносит его в document.body с position: fixed — он ставится у узла в координатах окна и прижимается к границам окна, поэтому обрезающие предки его больше не режут:
Charts.create({
container,
tooltip: { container: 'body' },
series: [{ type: 'area', xField: 'day', yField: 'visits', marker: { showOn: 'hover' } }],
});Полоса KPI высотой 48 пикселей в рамке, которая обрезает содержимое, как карточка дашборда. Наведите на неё курсор, а потом кнопкой ниже переключите тултип внутрь графика и сравните:
import { getData } from './data';
import type { ChartInstance, ChartOptions } from 'grafit-charts';
const bareAxis = { label: { enabled: false }, line: { enabled: false }, tick: { enabled: false }, gridLine: { enabled: false } };
// A KPI strip in a tile that clips its content, as a dashboard card does. Inside
// the chart the tooltip is held within a strip shorter than itself and cut by the
// tile; in the body it sits by the node whole, reaching past the tile's edges.
export function createOptions(): ChartOptions {
return {
data: getData(),
series: [
{
type: 'line',
xField: 'month',
yField: 'revenue',
name: 'Revenue',
marker: { showOn: 'hover' },
tooltip: {
renderer: ({ datum, color }) => ({
heading: String(datum.month),
rows: [{ label: 'Revenue', value: `${Number(datum.revenue).toFixed(2)} M`, color }],
}),
},
},
],
axes: [
{ type: 'category', position: 'bottom', paddingOuter: 0, ...bareAxis },
{ type: 'number', position: 'left', nice: false, ...bareAxis },
],
legend: { enabled: false },
// no floor under the measured size: the strip is exactly as short as its card
minHeight: 0,
padding: { top: 6, right: 8, bottom: 6, left: 8 },
tooltip: { container: 'body', range: 'nearest' },
};
}
// Buttons under the demo: the same strip with the tooltip in either home.
export const actions = [
{
label: 'Tooltip in the body',
run: (chart: ChartInstance) => void chart.updateDelta({ tooltip: { container: 'body' } }),
},
{
label: 'Tooltip inside the chart',
run: (chart: ChartInstance) => void chart.updateDelta({ tooltip: { container: 'chart' } }),
},
];export function getData() {
return [
{ month: 'Jan', revenue: 41.2 },
{ month: 'Feb', revenue: 43.8 },
{ month: 'Mar', revenue: 42.5 },
{ month: 'Apr', revenue: 47.1 },
{ month: 'May', revenue: 49.6 },
{ month: 'Jun', revenue: 48.3 },
{ month: 'Jul', revenue: 51.9 },
{ month: 'Aug', revenue: 53.4 },
{ month: 'Sep', revenue: 52.2 },
{ month: 'Oct', revenue: 55.7 },
{ month: 'Nov', revenue: 57.1 },
{ month: 'Dec', revenue: 58.65 },
];
}Элемент вместо 'body' кладёт тултип в этот элемент — для приложений, которые держат оверлеи в своём слое; позиционируется он так же. Вне графика:
- тултип ставится у точки так же, как внутри графика — справа и выше, с переносом там, где кончается окно, — только края графика его больше не ограничивают;
- прокрутка страницы или любого прокручиваемого предка и изменение размера окна прячут тултип — следующее движение курсора покажет его снова на нужном месте;
destroy()убирает элемент вместе с графиком;- шрифт, размер, насыщенность и цвета темы задаются на самом элементе: от контейнера графика он ничего не наследует;
position: fixedотсчитывается от окна, если у предков элемента нетtransform,filterилиcontain— не ставьте их на переданный слой.
Внешний вид
Контейнер тултипа настраивается там же, в tooltip:
| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
background | ColorValue | фон темы | фон |
borderColor | ColorValue | приглушённый цвет темы | цвет рамки |
borderWidth | Pixels | 1 | толщина рамки; 0 убирает рамку |
borderRadius | Pixels | 6 | скругление углов |
shadow | string | false | 0 2px 8px rgba(0,0,0,.25) | CSS box-shadow; false — без тени |
padding | PaddingValue | string | 7px 10px | внутренние поля: 8, [8, 12], [8, 12, 4, 0], { top, right, bottom, left } или CSS-строка |
fontSize | Pixels | 12 | размер шрифта |
fontFamily | string | system-ui, sans-serif | гарнитура |
color | ColorValue | foreground темы | цвет текста |
tooltip: {
background: '#141821',
color: '#f0f0f0',
borderColor: '#436ff4',
borderRadius: 10,
shadow: false,
},Опции серии
series[].tooltip.renderer(params) возвращает строку (станет заголовком) или структуру:
renderer: ({ datum, xValue, yValue, seriesName, color }) => ({
heading: String(xValue),
rows: [{ label: seriesName, value: String(yValue), color }],
});params.datum — вся строка данных: в тултип можно выводить поля, не участвующие в серии.
heading — строка либо объект { text, color }; с color перед текстом заголовка рисуется такой же маркер, как у строк. Именно так scatter и bubble рисуют тултип по умолчанию — маркер обозначает серию, а не отдельную строку:
renderer: ({ datum, xValue, yValue, seriesName, color }) => ({
heading: { text: String(datum.category), color },
rows: [
{ label: 'X', value: String(xValue) },
{ label: 'Y', value: String(yValue) },
],
});Подсветка управляется блоком highlight:
| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
enabled | boolean | true | подсветка узла и приглушение остальных серий |
dimOpacity | Fraction | 0.8 | прозрачность неподсвеченных серий (1 — не приглушать) |
highlight.enabled | boolean | true | подсветка узла и приглушение |
highlight.dimOpacity | Fraction | 0.8 | прозрачность неподсвеченных серий |