Подсказка (tooltip) — интерактивный элемент, отображающий дополнительную информацию при наведении курсора на точку, сектор, столбец или другой графический объект диаграммы. В Chart.js система подсказок обладает гибкой архитектурой и поддерживает:
Все параметры подсказок располагаются внутри секции:
options: {
plugins: {
tooltip: {
// настройки
}
}
}
Стандартная подсказка состоит из нескольких частей:
title)body)footer)Например:
tooltip: {
enabled: true
}
При наведении пользователь увидит:
Январь
Продажи: 150
Параметр titleColor задаёт цвет текста заголовка.
tooltip: {
titleColor: '#ffffff'
}
Шрифт настраивается через объект titleFont.
tooltip: {
titleFont: {
size: 18,
family: 'Arial',
style: 'bold',
weight: 'bold'
}
}
| Свойство | Описание |
|---|---|
size |
Размер шрифта |
family |
Семейство шрифта |
style |
Стиль текста |
weight |
Толщина шрифта |
lineHeight |
Межстрочный интервал |
tooltip: {
titleMarginBottom: 15
}
Увеличивает расстояние между заголовком и телом подсказки.
tooltip: {
titleAlign: 'center'
}
| Значение | Описание |
|---|---|
left |
Выравнивание слева |
center |
По центру |
right |
Справа |
Для динамического формирования текста используются callback-функции.
tooltip: {
callbacks: {
title: function(context) {
return 'Месяц: ' + context[0].label;
}
}
}
tooltip: {
callbacks: {
title: function() {
return '';
}
}
}
Можно возвращать массив строк.
tooltip: {
callbacks: {
title: function(context) {
return [
'Статистика продаж',
'Период: ' + context[0].label
];
}
}
}
Результат:
Статистика продаж
Период: Январь
tooltip: {
callbacks: {
title: function(context) {
const item = context[0];
return item.dataset.label;
}
}
}
tooltip: {
bodyColor: '#00ffcc'
}
tooltip: {
bodyFont: {
size: 14,
family: 'Verdana',
weight: 'normal'
}
}
tooltip: {
bodySpacing: 10
}
Увеличивает расстояние между строками.
tooltip: {
bodyAlign: 'left'
}
| Значение | Описание |
|---|---|
left |
Слева |
center |
По центру |
right |
Справа |
labelНаиболее используемый механизм кастомизации.
tooltip: {
callbacks: {
label: function(context) {
return 'Продажи: ' + context.raw;
}
}
}
tooltip: {
callbacks: {
label: function(context) {
return '$ ' + context.raw;
}
}
}
Intl.NumberFormattooltip: {
callbacks: {
label: function(context) {
const value = new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB'
}).format(context.raw);
return value;
}
}
}
Результат:
12 500,00 ₽
tooltip: {
callbacks: {
label: function(context) {
const value = context.raw;
return value + '%';
}
}
}
tooltip: {
callbacks: {
label: function(context) {
return [
'Товар: ' + context.label,
'Количество: ' + context.raw,
'Регион: Европа'
];
}
}
}
Если данные представлены объектами:
data: [
{
x: 'Январь',
y: 120,
region: 'Азия'
}
]
Тогда:
tooltip: {
callbacks: {
label: function(context) {
const data = context.raw;
return [
'Продажи: ' + data.y,
'Регион: ' + data.region
];
}
}
}
beforeLabelДобавляет текст перед основной строкой.
tooltip: {
callbacks: {
beforeLabel: function(context) {
return 'Информация';
},
label: function(context) {
return 'Значение: ' + context.raw;
}
}
}
afterLabeltooltip: {
callbacks: {
afterLabel: function(context) {
return 'Обновлено сегодня';
}
}
}
beforeBodyВыполняется перед всем содержимым тела.
tooltip: {
callbacks: {
beforeBody: function() {
return 'Статистика';
}
}
}
afterBodytooltip: {
callbacks: {
afterBody: function() {
return 'Конец данных';
}
}
}
Canvas не поддерживает HTML напрямую внутри tooltip, однако можно имитировать структуру текста.
tooltip: {
callbacks: {
label: function(context) {
const label = context.label.padEnd(10, ' ');
const value = context.raw;
return `${label}: ${value}`;
}
}
}
tooltip: {
callbacks: {
labelColor: function(context) {
return {
borderColor: '#000',
backgroundColor: '#ff0000',
borderWidth: 2,
borderRadius: 4
};
}
}
}
tooltip: {
usePointStyle: true
}
Теперь вместо квадрата будет использоваться стиль точки графика.
tooltip: {
callbacks: {
labelPointStyle: function() {
return {
pointStyle: 'triangle',
rotation: 0
};
}
}
}
circletrianglerectstarcrosslinedashtooltip: {
callbacks: {
label: function(context) {
const value = context.raw;
if (value > 1000) {
return 'Высокие продажи: ' + value;
}
return 'Продажи: ' + value;
}
}
}
tooltip: {
callbacks: {
labelColor: function(context) {
const value = context.raw;
if (value < 0) {
return {
backgroundColor: 'red'
};
}
return {
backgroundColor: 'green'
};
}
}
}
tooltip: {
callbacks: {
label: function(context) {
return [
'Серия: ' + context.dataset.label,
'Значение: ' + context.raw
];
}
}
}
tooltip: {
itemSort: function(a, b) {
return b.raw - a.raw;
}
}
tooltip: {
filter: function(item) {
return item.raw !== 0;
}
}
tooltip: {
backgroundColor: '#1e1e1e'
}
tooltip: {
borderColor: '#ffffff',
borderWidth: 1
}
tooltip: {
cornerRadius: 10
}
tooltip: {
padding: 16
}
Chart.js позволяет полностью отключить встроенную подсказку и рисовать собственную HTML-структуру.
tooltip: {
enabled: false,
external: externalTooltipHandler
}
function externalTooltipHandler(context) {
const tooltip = context.tooltip;
let tooltipEl = document.getElementById('chartjs-tooltip');
if (!tooltipEl) {
tooltipEl = document.createElement('div');
tooltipEl.id = 'chartjs-tooltip';
tooltipEl.innerHTML = '<table></table>';
document.body.appendChild(tooltipEl);
}
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
const titleLines = tooltip.title || [];
const bodyLines = tooltip.body.map(item => item.lines);
let innerHtml = '<thead>';
titleLines.forEach(function(title) {
innerHtml += `<tr><th>${title}</th></tr>`;
});
innerHtml += '</thead><tbody>';
bodyLines.forEach(function(body) {
innerHtml += `<tr><td>${body}</td></tr>`;
});
innerHtml += '</tbody>';
const tableRoot = tooltipEl.querySelector('table');
tableRoot.innerHTML = innerHtml;
const position = context.chart.canvas.getBoundingClientRect();
tooltipEl.style.opacity = 1;
tooltipEl.style.position = 'absolute';
tooltipEl.style.left =
position.left + window.pageXOffset + tooltip.caretX + 'px';
tooltipEl.style.top =
position.top + window.pageYOffset + tooltip.caretY + 'px';
tooltipEl.style.background = '#222';
tooltipEl.style.color = '#fff';
tooltipEl.style.padding = '10px';
}
tooltip: {
footerColor: '#ffcc00',
footerFont: {
size: 14,
weight: 'bold'
},
callbacks: {
footer: function(items) {
let total = 0;
items.forEach(item => {
total += item.raw;
});
return 'Итого: ' + total;
}
}
}
Объект context содержит большое количество полезной
информации.
| Свойство | Описание |
|---|---|
context.label |
Подпись элемента |
context.raw |
Исходное значение |
context.dataset |
Текущий dataset |
context.dataIndex |
Индекс элемента |
context.datasetIndex |
Индекс dataset |
context.parsed |
Обработанные данные |
tooltip: {
callbacks: {
label: function(context) {
return [
'X: ' + context.parsed.x,
'Y: ' + context.parsed.y
];
}
}
}
tooltip: {
callbacks: {
label: function(context) {
return 'Продажи: ' +
context.raw.toLocaleString('ru-RU');
}
}
}
Неверно:
return '<b>Продажи</b>';
Canvas не интерпретирует HTML.
Неверно:
label: function(context) {
'Продажи: ' + context.raw;
}
Правильно:
label: function(context) {
return 'Продажи: ' + context.raw;
}
В callback title массив обязателен:
title: function(context) {
return context[0].label;
}
В label используется одиночный объект:
label: function(context) {
return context.label;
}
const config = {
type: 'bar',
data: {
labels: ['Январь', 'Февраль', 'Март'],
datasets: [{
label: 'Продажи',
data: [120, 190, 300],
backgroundColor: '#4bc0c0'
}]
},
options: {
plugins: {
tooltip: {
backgroundColor: '#1f2937',
borderColor: '#4bc0c0',
borderWidth: 1,
titleColor: '#ffffff',
titleFont: {
size: 18,
weight: 'bold'
},
bodyColor: '#d1d5db',
bodyFont: {
size: 14
},
padding: 12,
callbacks: {
title: function(context) {
return 'Месяц: ' +
context[0].label;
},
label: function(context) {
const value =
context.raw.toLocaleString('ru-RU');
return 'Продажи: ' + value + ' ₽';
},
footer: function(items) {
let total = 0;
items.forEach(item => {
total += item.raw;
});
return 'Всего: ' + total + ' ₽';
}
}
}
}
}
};