По умолчанию библиотека Chart.js выводит числовые значения без дополнительного форматирования. Для небольших значений этого достаточно, однако при работе с финансовыми данными, аналитикой, статистикой или научными вычислениями возникает необходимость:
Основная настройка форматирования выполняется через callback-функции.
Без форматирования значения выглядят тяжело для восприятия:
1500000
25000000
987654321
Гораздо удобнее отображать их так:
1 500 000
25 000 000
987 654 321
или:
1,500,000
25,000,000
987,654,321
toLocaleString()Наиболее удобный способ форматирования — встроенный метод JavaScript
toLocaleString().
const value = 1500000;
console.log(value.toLocaleString());
Результат зависит от локали системы:
1 500 000
Для изменения отображения чисел на шкале используется callback в
ticks.
const config = {
type: 'bar',
data: {
labels: ['Январь', 'Февраль', 'Март'],
datasets: [{
label: 'Продажи',
data: [150000, 275000, 990000]
}]
},
options: {
scales: {
y: {
ticks: {
callback: function(value) {
return value.toLocaleString();
}
}
}
}
}
};
Было:
100000
200000
300000
Стало:
100 000
200 000
300 000
Метод toLocaleString() поддерживает локали.
value.toLocaleString('ru-RU');
Результат:
1 500 000,5
value.toLocaleString('en-US');
Результат:
1,500,000.5
value.toLocaleString('de-DE');
Результат:
1.500.000,5
Tooltip часто требует отдельной настройки, поскольку данные в подсказках отображаются независимо от осей.
const config = {
type: 'line',
data: {
labels: ['Пн', 'Вт', 'Ср'],
datasets: [{
label: 'Доход',
data: [1250000, 980000, 2100000]
}]
},
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context) {
let value = context.parsed.y;
return 'Доход: ' +
value.toLocaleString('ru-RU');
}
}
}
}
}
};
return value.toLocaleString('ru-RU') + ' ₽';
Результат:
1 500 000 ₽
JavaScript поддерживает специальный режим currency.
value.toLocaleString('ru-RU', {
style: 'currency',
currency: 'RUB'
});
Результат:
1 500 000,00 ₽
value.toLocaleString('en-US', {
style: 'currency',
currency: 'USD'
});
Результат:
$1,500,000.00
value.toLocaleString('de-DE', {
style: 'currency',
currency: 'EUR'
});
Результат:
1.500.000,00 €
value.toLocaleString('ru-RU', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
Результат:
1 500,00
value.toLocaleString('ru-RU', {
maximumFractionDigits: 1
});
value.toLocaleString('ru-RU', {
maximumFractionDigits: 0
});
const value = 0.25;
console.log(
value.toLocaleString('ru-RU', {
style: 'percent'
})
);
Результат:
25 %
Для сложных сценариев лучше использовать
Intl.NumberFormat.
const formatter = new Intl.NumberFormat('ru-RU', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
console.log(formatter.format(1234567.89));
Результат:
1 234 567,89
Intl.NumberFormatФорматтер создаётся один раз:
const formatter = new Intl.NumberFormat('ru-RU');
После чего применяется многократно:
formatter.format(value);
Это эффективнее, чем постоянный вызов
toLocaleString().
const formatter = new Intl.NumberFormat('ru-RU', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
const config = {
type: 'line',
data: {
labels: ['Январь', 'Февраль', 'Март'],
datasets: [{
label: 'Прибыль',
data: [1250000.5, 2250000.75, 3100000.9]
}]
},
options: {
scales: {
y: {
ticks: {
callback: function(value) {
return formatter.format(value);
}
}
}
},
plugins: {
tooltip: {
callbacks: {
label: function(context) {
return formatter.format(
context.parsed.y
);
}
}
}
}
}
};
Иногда крупные значения удобнее показывать в сокращённом виде.
function formatNumber(value) {
if (value >= 1000000) {
return (value / 1000000).toFixed(1) + 'M';
}
if (value >= 1000) {
return (value / 1000).toFixed(1) + 'K';
}
return value;
}
ticks: {
callback: function(value) {
return formatNumber(value);
}
}
1500 → 1.5K
2500000 → 2.5M
function formatNumber(value) {
if (value >= 1000000) {
return (value / 1000000).toFixed(1) + ' млн';
}
if (value >= 1000) {
return (value / 1000).toFixed(1) + ' тыс';
}
return value;
}
При использовании плагина chartjs-plugin-datalabels
форматирование выполняется через formatter.
plugins: {
datalabels: {
formatter: function(value) {
return value.toLocaleString('ru-RU');
}
}
}
Для легенд чаще форматируются не числа, а подписи, однако возможно динамическое создание текста.
label: 'Продажи: ' +
total.toLocaleString('ru-RU')
В финансовых графиках удобно комбинировать:
const moneyFormatter =
new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
tooltip: {
callbacks: {
label: function(context) {
return moneyFormatter.format(
context.parsed.y
);
}
}
}
const formatter = new Intl.NumberFormat('ru-RU', {
minimumFractionDigits: 2
});
console.log(formatter.format(-1500000.5));
Результат:
-1 500 000,50
Иногда требуется полностью собственный формат.
function customFormat(value) {
return value
.toFixed(2)
.replace('.', ',')
.replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}
1234567.89
преобразуется в:
1 234 567,89
Ключевая часть форматирования:
/\B(?=(\d{3})+(?!\d))/g
Разбирается следующим образом:
| Выражение | Назначение |
|---|---|
\B |
позиция внутри числа |
(?=...) |
проверка вперёд |
\d{3} |
группа из трёх цифр |
(?!\d) |
отсутствие следующей цифры |
callback: function(value) {
if (value === 0) {
return '0';
}
return value.toLocaleString('ru-RU');
}
null и
undefinedfunction safeFormat(value) {
if (value == null) {
return '-';
}
return value.toLocaleString('ru-RU');
}
function createFormatter(locale = 'ru-RU') {
const formatter =
new Intl.NumberFormat(locale, {
minimumFractionDigits: 0,
maximumFractionDigits: 2
});
return function(value) {
return formatter.format(value);
};
}
const format = createFormatter();
ticks: {
callback: function(value) {
return format(value);
}
}
В Chart.js 4 callback-функции работают аналогично предыдущим версиям.
| Область | Настройка |
|---|---|
| Оси | ticks.callback |
| Tooltip | tooltip.callbacks.label |
| DataLabels | datalabels.formatter |
| Подписи | пользовательские функции |
| Легенда | генерация текста |
Неправильно:
data: ['1000', '2000']
Правильно:
data: [1000, 2000]
nullНеправильно:
value.toLocaleString()
Правильно:
value?.toLocaleString?.()
Неправильно:
callback: function(value) {
const formatter =
new Intl.NumberFormat('ru-RU');
return formatter.format(value);
}
Правильно:
const formatter =
new Intl.NumberFormat('ru-RU');
const formatter =
new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
const config = {
type: 'bar',
data: {
labels: [
'Январь',
'Февраль',
'Март'
],
datasets: [{
label: 'Выручка',
data: [
1250000.25,
2200000.5,
3100000.75
]
}]
},
options: {
scales: {
y: {
ticks: {
callback: function(value) {
return formatter.format(value);
}
}
}
},
plugins: {
tooltip: {
callbacks: {
label: function(context) {
return 'Выручка: ' +
formatter.format(
context.parsed.y
);
}
}
}
}
}
};