Форматирование заголовка и тела подсказки

Подсказка (tooltip) — интерактивный элемент, отображающий дополнительную информацию при наведении курсора на точку, сектор, столбец или другой графический объект диаграммы. В Chart.js система подсказок обладает гибкой архитектурой и поддерживает:

  • изменение текста;
  • настройку заголовка;
  • форматирование значений;
  • кастомизацию цветов;
  • изменение шрифтов;
  • добавление пользовательских строк;
  • полное переопределение HTML-разметки.

Все параметры подсказок располагаются внутри секции:

options: {
    plugins: {
        tooltip: {
            // настройки
        }
    }
}

Структура подсказки

Стандартная подсказка состоит из нескольких частей:

  1. Заголовок (title)
  2. Тело (body)
  3. Подвал (footer)
  4. Цветовые индикаторы
  5. Маркеры датасетов

Например:

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 Справа

Callback-функции тела подсказки

Основной callback label

Наиболее используемый механизм кастомизации.

tooltip: {
    callbacks: {
        label: function(context) {
            return 'Продажи: ' + context.raw;
        }
    }
}

Форматирование чисел

Добавление валюты

tooltip: {
    callbacks: {
        label: function(context) {
            return '$ ' + context.raw;
        }
    }
}

Форматирование через Intl.NumberFormat

tooltip: {
    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
            ];
        }
    }
}

Форматирование отдельных частей тела

Callback beforeLabel

Добавляет текст перед основной строкой.

tooltip: {
    callbacks: {
        beforeLabel: function(context) {
            return 'Информация';
        },

        label: function(context) {
            return 'Значение: ' + context.raw;
        }
    }
}

Callback afterLabel

tooltip: {
    callbacks: {
        afterLabel: function(context) {
            return 'Обновлено сегодня';
        }
    }
}

Callback beforeBody

Выполняется перед всем содержимым тела.

tooltip: {
    callbacks: {
        beforeBody: function() {
            return 'Статистика';
        }
    }
}

Callback afterBody

tooltip: {
    callbacks: {
        afterBody: function() {
            return 'Конец данных';
        }
    }
}

Использование HTML-подобного форматирования

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
}

Теперь вместо квадрата будет использоваться стиль точки графика.


Кастомизация Point Style

tooltip: {
    callbacks: {
        labelPointStyle: function() {

            return {
                pointStyle: 'triangle',
                rotation: 0
            };
        }
    }
}

Возможные типы

  • circle
  • triangle
  • rect
  • star
  • cross
  • line
  • dash

Условное форматирование

Изменение текста в зависимости от значения

tooltip: {
    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

tooltip: {
    itemSort: function(a, b) {
        return b.raw - a.raw;
    }
}

Фильтрация элементов tooltip

Исключение нулевых значений

tooltip: {
    filter: function(item) {
        return item.raw !== 0;
    }
}

Полная настройка внешнего вида

Цвет фона

tooltip: {
    backgroundColor: '#1e1e1e'
}

Цвет рамки

tooltip: {
    borderColor: '#ffffff',
    borderWidth: 1
}

Радиус скругления

tooltip: {
    cornerRadius: 10
}

Внутренние отступы

tooltip: {
    padding: 16
}

Полностью кастомный HTML Tooltip

Chart.js позволяет полностью отключить встроенную подсказку и рисовать собственную HTML-структуру.

Отключение стандартной подсказки

tooltip: {
    enabled: false,
    external: externalTooltipHandler
}

Пример HTML Tooltip

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';
}

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

Форматирование подвала подсказки

tooltip: {
    footerColor: '#ffcc00',

    footerFont: {
        size: 14,
        weight: 'bold'
    },

    callbacks: {
        footer: function(items) {

            let total = 0;

            items.forEach(item => {
                total += item.raw;
            });

            return 'Итого: ' + total;
        }
    }
}

Контекст callback-функций

Объект context содержит большое количество полезной информации.

Основные свойства

Свойство Описание
context.label Подпись элемента
context.raw Исходное значение
context.dataset Текущий dataset
context.dataIndex Индекс элемента
context.datasetIndex Индекс dataset
context.parsed Обработанные данные

Работа с parsed

Форматирование scatter-графика

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');
        }
    }
}

Частые ошибки

Использование HTML внутри label

Неверно:

return '<b>Продажи</b>';

Canvas не интерпретирует HTML.


Отсутствие return

Неверно:

label: function(context) {
    'Продажи: ' + context.raw;
}

Правильно:

label: function(context) {
    return 'Продажи: ' + context.raw;
}

Ошибка при работе с context[0]

В callback title массив обязателен:

title: function(context) {
    return context[0].label;
}

В label используется одиночный объект:

label: function(context) {
    return context.label;
}

Комплексный пример форматирования tooltip

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 + ' ₽';
                    }
                }
            }
        }
    }
};