Визуализации временных рядов в Nivo опираются на корректную работу с датами на уровне шкал, осей, подсказок и легенд. Основная сложность заключается не в отображении чисел, а в согласованном преобразовании дат между данными, масштабами D3 и форматированием UI-слоёв.
Nivo ожидает, что временные значения будут приведены к одному из двух форматов:
Date-объект JavaScriptНа практике предпочтительным вариантом считается нормализация данных заранее:
const data = [
{
id: "Температура",
data: [
{ x: new Date("2024-01-01"), y: 12 },
{ x: new Date("2024-01-02"), y: 15 },
{ x: new Date("2024-01-03"), y: 9 }
]
}
];
При использовании строкового представления дат ответственность за корректное преобразование ложится на шкалу:
xScale={{
type: "time",
format: "%Y-%m-%d",
precision: "day"
}}
Здесь формат задаётся в стиле d3-time-format, что важно
для согласованного парсинга.
Внутри Nivo используется экосистема D3, поэтому форматирование дат
опирается на d3-time-format.
Основные символы:
%Y — год (2024)%m — месяц (01–12)%d — день месяца%H — часы%M — минуты%S — секундыПример функции форматирования:
import { format } from "d3-time-format";
const formatDate = format("%d.%m.%Y");
Эта функция используется в нескольких слоях: оси, подсказки, легенды.
Ось X в временных графиках — основной потребитель форматирования дат.
В Nivo это задаётся через axisBottom или
axisTop.
axisBottom={{
format: value => {
const date = new Date(value);
return `${date.getDate()}.${date.getMonth() + 1}`;
}
}}
Более строгий подход — использование d3-time-format:
import { format } from "d3-time-format";
const axisFormat = format("%d.%m");
axisBottom={{
format: axisFormat
}}
При работе с большими диапазонами времени важно учитывать масштаб:
%d.%m%b %Y%YЭто снижает визуальный шум и улучшает читаемость.
Шкала времени в Nivo опирается на D3 scaleTime:
xScale={{
type: "time",
precision: "day",
useUTC: false
}}
Параметр precision влияет на:
Частая ошибка — смешивание временных зон. При работе с глобальными
данными используется useUTC: true, чтобы избежать сдвигов
дат.
Tooltip в Nivo позволяет полностью контролировать представление даты:
tooltip={({ point }) => {
const date = new Date(point.data.x);
return (
<div>
<div>{date.toLocaleDateString()}</div>
<div>{point.data.y}</div>
</div>
);
}}
Для строгого форматирования предпочтительно использовать единый формат:
const formatFullDate = format("%d.%m.%Y %H:%M");
tooltip={({ point }) => (
<div>
<div>{formatFullDate(new Date(point.data.x))}</div>
<div>{point.data.y}</div>
</div>
)}
Tooltip часто становится местом, где проявляется несогласованность форматов, если оси и легенды используют разные правила отображения.
Легенды в Nivo обычно отражают идентификаторы серий, но в временных визуализациях часто возникает задача включения дат в подписи.
Базовая конфигурация:
legends={[
{
anchor: "top-left",
direction: "column",
itemWidth: 120,
itemHeight: 20,
symbolSize: 12
}
]}
По умолчанию легенда отображает id серии, но
форматирование возможно через dataFrom и трансформацию
данных.
Если серии представляют периоды времени, подписи можно формировать вручную:
legends={[
{
anchor: "bottom",
direction: "row",
dataFrom: "keys",
itemWidth: 100,
itemHeight: 20,
translateY: 50,
format: value => {
const date = new Date(value);
return format("%d.%m")(date);
}
}
]}
Такой подход применяется, когда id серии хранит дату или
временной диапазон.
В реальных сценариях данные часто агрегируются:
Пример структуры:
const data = [
{
id: "2024-01",
data: [
{ x: "2024-01-01", y: 100 },
{ x: "2024-01-02", y: 120 }
]
}
];
Легенда в этом случае должна отражать период:
legends={[
{
anchor: "top",
direction: "row",
itemWidth: 90,
format: value => {
const [year, month] = value.split("-");
return `${month}.${year}`;
}
}
]}
При отображении данных для разных регионов важно учитывать локаль:
const formatLocalized = new Intl.DateTimeFormat("ru-RU", {
day: "2-digit",
month: "short",
year: "numeric"
});
axisBottom={{
format: value => formatLocalized.format(new Date(value))
}}
Локализация влияет не только на формат, но и на порядок элементов даты, что особенно заметно в длинных временных диапазонах.
Критически важный аспект — единообразие формата:
Несогласованность приводит к когнитивной нагрузке: пользователь видит одну дату в разных представлениях.
Пример согласованного подхода:
const formatDate = format("%d.%m.%Y");
const commonDateFormatter = d => formatDate(new Date(d));
Использование одной функции во всех слоях:
axisBottom={{ format: commonDateFormatter }}
tooltip={({ point }) => (
<div>{commonDateFormatter(point.data.x)}</div>
)}
Каждая из этих ошибок приводит к визуальным смещениям или некорректной группировке точек.
При увеличении диапазона данных формат легенды и осей должен становиться более абстрактным:
Пример адаптивного форматирования:
const adaptiveFormat = value => {
const date = new Date(value);
const diff = Date.now() - date.getTime();
if (diff < 1000 * 60 * 60 * 24) {
return format("%H:%M")(date);
}
if (diff < 1000 * 60 * 60 * 24 * 30) {
return format("%d.%m")(date);
}
return format("%m.%Y")(date);
};
Этот подход особенно полезен в интерактивных графиках с масштабированием.
При работе с диапазонами дат (например, недельные серии) легенды могут представлять интервалы:
legends={[
{
anchor: "bottom",
direction: "row",
itemWidth: 140,
format: value => {
const start = new Date(value.start);
const end = new Date(value.end);
return `${format("%d.%m")(start)} - ${format("%d.%m")(end)}`;
}
}
]}
Такой формат делает легенду частью временной шкалы, а не просто идентификатором серии.
Корректная работа с датами в Nivo формирует связность всей визуализации: шкалы определяют структуру, оси задают читаемость, tooltip раскрывает детали, а легенда связывает серии с временными интервалами.