Добавил возможность выбора множества тегов для отображения.

This commit is contained in:
Первов Артем
2026-06-22 21:49:52 +03:00
parent 6ab9cd1c75
commit 9fc66624dc
10 changed files with 229 additions and 109 deletions

View File

@@ -1,92 +1,70 @@
import { LineChart, ScatterChart } from 'echarts/charts';
import {
DataZoomComponent,
GridComponent,
LegendComponent,
TooltipComponent,
} from 'echarts/components';
import * as echarts from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import ReactEChartsCore from 'echarts-for-react/esm/core.js';
import { useMemo, useRef } from 'react';
import type { HistoryResponse } from '../../entities/history/types';
import { useCallback, useMemo, useRef } from 'react';
import type { HistoryAxisLabelFormat } from '../../utils/historyGranularity';
import type { DataZoomEventBatch, DataZoomState } from './chartTypes';
import { HistoryChartArea } from './HistoryChartArea';
import { createHistoryChartOptions } from './historyChartOptions';
echarts.use([
LineChart,
ScatterChart,
GridComponent,
LegendComponent,
TooltipComponent,
DataZoomComponent,
CanvasRenderer,
]);
import { useHistoryChartQueries } from './useHistoryChartQueries';
import { useHistoryChartSeries } from './useHistoryChartSeries';
type HistoryChartProps = {
data?: HistoryResponse;
loading: boolean;
from?: string;
to?: string;
tickIntervalMs?: number;
edge: string;
from: string;
granulate: string;
labelFormat?: HistoryAxisLabelFormat;
tag?: string;
tags: string[];
tickIntervalMs?: number;
to: string;
tagLabels?: Record<string, string>;
};
/** Рисует avg-линию, min/max-точки и вертикальный диапазон для агрегированной истории. */
/** Контейнер истории: загружает выбранные теги и передает готовые серии в область ECharts. */
export function HistoryChart({
data,
loading,
edge,
from,
to,
tickIntervalMs,
granulate,
labelFormat,
tag,
tags,
tickIntervalMs,
to,
tagLabels = {},
}: HistoryChartProps) {
const dataZoomRef = useRef<DataZoomState | null>(null);
const seriesLabel = tag ? tagLabels[tag] ?? tag : '';
const legendData = useMemo(() => (data?.rows.length && seriesLabel ? [seriesLabel] : []), [data?.rows.length, seriesLabel]);
const lines = useHistoryChartQueries({ edge, from, granulate, tags, to, tagLabels });
const series = useHistoryChartSeries(lines);
const legendData = useMemo(() => lines.map((line) => line.label), [lines]);
const loading = lines.some((line) => line.loading);
const option = useMemo(
() =>
createHistoryChartOptions({
data,
dataZoomState: dataZoomRef.current ?? {},
from,
to,
labelFormat,
legendData,
seriesLabel,
series,
tickIntervalMs,
}),
[data, from, labelFormat, legendData, seriesLabel, tickIntervalMs, to],
[from, labelFormat, legendData, series, tickIntervalMs, to],
);
const onChartEvents = useMemo(
() => ({
datazoom: (event: DataZoomEventBatch) => {
const state = event.batch?.[0] ?? event;
dataZoomRef.current = {
start: state.start,
end: state.end,
startValue: state.startValue,
endValue: state.endValue,
};
},
}),
[],
const handleDataZoom = useCallback((event: DataZoomEventBatch) => {
const state = event.batch?.[0] ?? event;
dataZoomRef.current = {
start: state.start,
end: state.end,
startValue: state.startValue,
endValue: state.endValue,
};
}, []);
return (
<HistoryChartArea
hasData={series.length > 0}
hasSelection={tags.length > 0}
loading={loading}
option={option}
onDataZoom={handleDataZoom}
/>
);
if (loading) {
return <div className="chart-placeholder">Загрузка графика...</div>;
}
if (!data?.rows.length) {
return <div className="chart-placeholder">Нет данных для выбранного диапазона</div>;
}
return <ReactEChartsCore echarts={echarts} option={option} className="history-chart" onEvents={onChartEvents} lazyUpdate />;
}