Files
qitech-control/electron/src/components/graph/createChart.ts
T

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