531 lines
17 KiB
TypeScript
531 lines
17 KiB
TypeScript
import uPlot from "uplot";
|
|
import { seriesToUPlotData, TimeSeries } from "@/lib/timeseries";
|
|
import {
|
|
createEventHandlers,
|
|
attachEventHandlers,
|
|
HandlerCallbacks,
|
|
} from "./handlers";
|
|
import { BigGraphProps, CreateChartParams } from "./types";
|
|
import { normalizeDataSeries } from "./animation";
|
|
|
|
export function createChart({
|
|
containerRef,
|
|
uplotRef,
|
|
newData,
|
|
config,
|
|
colors,
|
|
renderValue,
|
|
viewMode,
|
|
selectedTimeWindow,
|
|
isLiveMode,
|
|
startTimeRef,
|
|
manualScaleRef,
|
|
animationRefs,
|
|
handlerRefs,
|
|
graphId,
|
|
syncGraph,
|
|
getHistoricalEndTimestamp,
|
|
updateYAxisScale,
|
|
setViewMode,
|
|
setIsLiveMode,
|
|
setCursorValue,
|
|
setCursorValues,
|
|
visibleSeries,
|
|
showFromTimestamp,
|
|
}: CreateChartParams): (() => void) | undefined {
|
|
if (!containerRef.current) return;
|
|
|
|
// Get ALL series from original data
|
|
const allOriginalSeries = getAllTimeSeries(newData);
|
|
if (allOriginalSeries.length === 0) return;
|
|
|
|
// Use the first available series for timing calculations (visible or not)
|
|
const primarySeries = allOriginalSeries[0].series;
|
|
const [timestamps, primaryValues] = seriesToUPlotData(primarySeries.long);
|
|
if (timestamps.length === 0) return;
|
|
|
|
if (startTimeRef.current === null && timestamps.length > 0) {
|
|
startTimeRef.current = timestamps[0];
|
|
}
|
|
|
|
// Build uPlot data for ALL series (including hidden ones)
|
|
const uPlotData: uPlot.AlignedData = [timestamps as any];
|
|
|
|
allOriginalSeries.forEach(({ series }) => {
|
|
const [, values] = seriesToUPlotData(series.long);
|
|
uPlotData.push(values as any);
|
|
});
|
|
|
|
// Add config lines data
|
|
config.lines?.forEach((line) => {
|
|
if (line.show !== false) {
|
|
const lineData = new Array(timestamps.length).fill(line.value);
|
|
uPlotData.push(lineData as any);
|
|
}
|
|
});
|
|
|
|
const fullStart = startTimeRef.current ?? timestamps[0] ?? 0;
|
|
|
|
let initialMin: number, initialMax: number;
|
|
if (viewMode === "manual" && manualScaleRef.current) {
|
|
initialMin = manualScaleRef.current.x.min;
|
|
initialMax = manualScaleRef.current.x.max;
|
|
} else if (selectedTimeWindow === "all") {
|
|
initialMin = showFromTimestamp ?? fullStart;
|
|
initialMax = getHistoricalEndTimestamp();
|
|
} else {
|
|
const endTimestamp = getHistoricalEndTimestamp();
|
|
|
|
if (isLiveMode) {
|
|
const defaultViewStart = Math.max(
|
|
endTimestamp - (selectedTimeWindow as number),
|
|
fullStart,
|
|
);
|
|
initialMin = showFromTimestamp ?? defaultViewStart;
|
|
} else {
|
|
initialMin =
|
|
showFromTimestamp ?? endTimestamp - (selectedTimeWindow as number);
|
|
}
|
|
|
|
initialMax = endTimestamp;
|
|
}
|
|
|
|
// Calculate initial Y range from ALL series (not just visible ones)
|
|
// This prevents scale changes when toggling visibility
|
|
const initialAllValues: number[] = [];
|
|
allOriginalSeries.forEach(({ series }) => {
|
|
const [seriesTimestamps, seriesValues] = seriesToUPlotData(series.long);
|
|
for (let i = 0; i < seriesTimestamps.length; i++) {
|
|
if (
|
|
seriesTimestamps[i] >= initialMin &&
|
|
seriesTimestamps[i] <= initialMax
|
|
) {
|
|
initialAllValues.push(seriesValues[i]);
|
|
}
|
|
}
|
|
});
|
|
|
|
config |