Легенда в Chart.js отображает наборы данных, присутствующие на
графике, и предоставляет механизм взаимодействия с ними. По умолчанию
легенда автоматически формируется на основе массива
datasets, однако библиотека позволяет полностью управлять
процессом генерации элементов, включая:
Настройка выполняется через объект:
options: {
plugins: {
legend: {
// параметры
}
}
}
Фильтрация и сортировка особенно важны при работе:
Управление элементами легенды выполняется через объект:
options.plugins.legend.labels
Основные свойства:
| Свойство | Назначение |
|---|---|
generateLabels |
Полная генерация элементов легенды |
filter |
Фильтрация элементов |
sort |
Сортировка элементов |
usePointStyle |
Использование маркеров точек |
pointStyle |
Тип маркера |
color |
Цвет текста |
font |
Настройки шрифта |
Наиболее важными для управления отображением являются:
labels: {
filter: function(item, data) {},
sort: function(a, b, data) {}
}
Метод filter вызывается для каждого элемента
легенды.
Если функция возвращает:
true — элемент отображается;false — элемент скрывается.Сигнатура:
filter(legendItem, chartData)
Параметры:
| Параметр | Описание |
|---|---|
legendItem |
Объект текущего элемента легенды |
chartData |
Данные графика |
Скрытие определённого набора данных:
const config = {
type: 'bar',
data: {
labels: ['Январь', 'Февраль', 'Март'],
datasets: [
{
label: 'Продажи',
data: [10, 20, 30]
},
{
label: 'Расходы',
data: [5, 15, 25]
}
]
},
options: {
plugins: {
legend: {
labels: {
filter: function(item) {
return item.text !== 'Расходы';
}
}
}
}
}
};
В легенде будет отображаться только элемент
"Продажи".
Объект legendItem содержит информацию об элементе
легенды.
Пример структуры:
{
text: 'Продажи',
fillStyle: 'blue',
strokeStyle: 'black',
hidden: false,
datasetIndex: 0,
lineCap: 'butt',
lineDash: [],
lineJoin: 'miter',
lineWidth: 1
}
Наиболее полезные свойства:
| Свойство | Назначение |
|---|---|
text |
Текст элемента |
datasetIndex |
Индекс набора данных |
hidden |
Состояние скрытия |
fillStyle |
Цвет маркера |
strokeStyle |
Цвет границы |
Иногда требуется скрыть технические или служебные datasets.
labels: {
filter: function(item) {
return item.datasetIndex !== 0;
}
}
Первый набор данных не попадёт в легенду.
Datasets могут содержать дополнительные поля.
datasets: [
{
label: 'Доход',
data: [10, 20, 30],
visibleInLegend: true
},
{
label: 'Служебные данные',
data: [5, 10, 15],
visibleInLegend: false
}
]
Фильтр:
labels: {
filter: function(item, data) {
const dataset =
data.datasets[item.datasetIndex];
return dataset.visibleInLegend;
}
}
Такой подход особенно удобен в крупных приложениях.
Фильтрация может зависеть от состояния интерфейса.
let showExpenses = false;
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Пн', 'Вт', 'Ср'],
datasets: [
{
label: 'Доход',
data: [100, 200, 150]
},
{
label: 'Расход',
data: [50, 70, 90]
}
]
},
options: {
plugins: {
legend: {
labels: {
filter: function(item) {
if (
item.text === 'Расход' &&
!showExpenses
) {
return false;
}
return true;
}
}
}
}
}
});
После изменения переменной:
showExpenses = true;
chart.update();
легенда будет перестроена.
Chart.js позволяет скрывать наборы данных программно:
chart.hide(1);
Однако скрытый dataset всё равно остаётся в легенде. Для удаления из списка:
labels: {
filter: function(item, data) {
const dataset =
data.datasets[item.datasetIndex];
return !dataset.hidden;
}
}
Свойство sort определяет порядок отображения
элементов.
Сигнатура:
sort(a, b, data)
Возвращаемые значения:
| Значение | Результат |
|---|---|
< 0 |
a раньше b |
> 0 |
b раньше a |
0 |
порядок не меняется |
labels: {
sort: function(a, b) {
return a.text.localeCompare(b.text);
}
}
Результат:
Доход
Продажи
Расходы
labels: {
sort: function(a, b) {
return b.text.localeCompare(a.text);
}
}
labels: {
sort: function(a, b) {
return a.datasetIndex - b.datasetIndex;
}
}
Такой подход позволяет явно контролировать порядок.
Создание приоритетов:
const order = {
'Доход': 1,
'Расход': 2,
'Налоги': 3
};
Сортировка:
labels: {
sort: function(a, b) {
return order[a.text] - order[b.text];
}
}
Можно сортировать легенду по данным графика.
Например, по сумме значений:
labels: {
sort: function(a, b, data) {
const datasetA =
data.datasets[a.datasetIndex];
const datasetB =
data.datasets[b.datasetIndex];
const sumA =
datasetA.data.reduce(
(acc, value) => acc + value,
0
);
const sumB =
datasetB.data.reduce(
(acc, value) => acc + value,
0
);
return sumB - sumA;
}
}
Элементы с наибольшими значениями будут сверху.
labels: {
sort: function(a, b, data) {
function average(arr) {
return arr.reduce(
(acc, val) => acc + val,
0
) / arr.length;
}
const avgA = average(
data.datasets[a.datasetIndex].data
);
const avgB = average(
data.datasets[b.datasetIndex].data
);
return avgB - avgA;
}
}
Обе функции могут использоваться одновременно.
labels: {
filter: function(item) {
return item.text !== 'Технические';
},
sort: function(a, b) {
return a.text.localeCompare(b.text);
}
}
Порядок работы:
Для полного контроля применяется метод:
generateLabels(chart)
Он позволяет:
labels: {
generateLabels: function(chart) {
return chart.data.datasets.map(
(dataset, index) => {
return {
text:
dataset.label +
' (' +
dataset.data.length +
')',
fillStyle:
dataset.backgroundColor,
hidden: false,
datasetIndex: index
};
}
);
}
}
Результат:
Продажи (12)
Расходы (12)
labels: {
generateLabels: function(chart) {
return chart.data.datasets
.filter(dataset => {
return dataset.showLegend;
})
.map((dataset, index) => {
return {
text: dataset.label,
fillStyle:
dataset.backgroundColor,
datasetIndex: index
};
});
}
}
Иногда несколько datasets должны отображаться как один элемент.
generateLabels: function(chart) {
return [
{
text: 'Финансовые показатели',
fillStyle: 'green',
datasetIndex: 0
}
];
}
generateLabels: function(chart) {
return chart.data.datasets
.sort((a, b) => {
return b.priority - a.priority;
})
.map((dataset, index) => {
return {
text: dataset.label,
fillStyle:
dataset.backgroundColor,
datasetIndex: index
};
});
}
В pie и doughnut легенда создаётся иначе:
элементы соответствуют не datasets, а сегментам.
Пример:
data: {
labels: ['Chrome', 'Firefox', 'Safari'],
datasets: [{
data: [65, 20, 15]
}]
}
Каждый label становится отдельным элементом легенды.
labels: {
filter: function(item) {
return item.text !== 'Safari';
}
}
labels: {
sort: function(a, b) {
return a.text.localeCompare(b.text);
}
}
const config = {
type: 'line',
data: {
labels: [
'Янв',
'Фев',
'Мар'
],
datasets: [
{
label: 'Доход',
data: [100, 200, 300],
priority: 1
},
{
label: 'Расход',
data: [50, 70, 90],
priority: 2
},
{
label: 'Служебные',
data: [1, 2, 3],
hiddenInLegend: true,
priority: 999
}
]
},
options: {
plugins: {
legend: {
labels: {
filter: function(item, data) {
const dataset =
data.datasets[
item.datasetIndex
];
return !dataset.hiddenInLegend;
},
sort: function(a, b, data) {
const datasetA =
data.datasets[
a.datasetIndex
];
const datasetB =
data.datasets[
b.datasetIndex
];
return (
datasetA.priority -
datasetB.priority
);
}
}
}
}
}
};
При работе с десятками и сотнями datasets необходимо учитывать:
filter вызывается для каждого элемента;sort может выполняться многократно;Неэффективный код:
sort: function(a, b, data) {
// сложные вычисления
}
Предпочтительно заранее вычислять значения:
dataset.total = calculateTotal(dataset);
Оптимизированный вариант:
datasets.forEach(dataset => {
dataset.cachedTotal =
dataset.data.reduce(
(a, b) => a + b,
0
);
});
Использование:
sort: function(a, b, data) {
return (
data.datasets[b.datasetIndex]
.cachedTotal -
data.datasets[a.datasetIndex]
.cachedTotal
);
}
Неверно:
filter: function(item) {
return item.label !== 'Расход';
}
Правильно:
filter: function(item) {
return item.text !== 'Расход';
}
Неверно:
filter: function(item) {
item.text !== 'Расход';
}
Правильно:
filter: function(item) {
return item.text !== 'Расход';
}
Нежелательно:
sort: function(a, b, data) {
data.datasets.reverse();
return 0;
}
Функция сортировки должна быть чистой.
Удобный подход:
{
label: 'Доход',
data: [1, 2, 3],
meta: {
visibleInLegend: true,
priority: 1,
category: 'finance'
}
}
Полезно выносить обработчики:
function legendFilter(item, data) {
const dataset =
data.datasets[item.datasetIndex];
return dataset.meta.visibleInLegend;
}
Даже если datasets уже расположены правильно, лучше явно задавать сортировку:
sort: function(a, b) {
return a.datasetIndex - b.datasetIndex;
}
Это предотвращает ошибки при динамическом обновлении данных.
Фильтрация легенды часто связана:
Пример:
let currentCategory = 'finance';
filter: function(item, data) {
const dataset =
data.datasets[item.datasetIndex];
return (
dataset.category === currentCategory
);
}
После смены категории:
chart.update();
легенда обновится автоматически.
В сложных приложениях легенда может формироваться полностью вручную:
generateLabels: function(chart) {
return customLegendItems;
}
Такой подход используется:
Он позволяет превращать легенду из вспомогательного элемента в полноценный интерфейс управления визуализацией.