Initial web
This commit is contained in:
64
web/components/ChartCard/SignalsChart.tsx
Normal file
64
web/components/ChartCard/SignalsChart.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
'use client';
|
||||
|
||||
import 'uplot/dist/uPlot.min.css';
|
||||
import uPlot from 'uplot';
|
||||
import { useApp } from '@/lib/context';
|
||||
import { resolveName } from '@/lib/localization';
|
||||
import { CardShell } from './CardShell';
|
||||
import { makeYScale, makeAnnotationHooks, makeSignalsSeries, makeSignalsAxes, CURSOR_NO_DRAG } from './plotHelpers';
|
||||
import { buildSeriesData } from './seriesData';
|
||||
import { usePlot } from './usePlot';
|
||||
import type { AlertConfig, ChartConfig, SessionBoundary, SignalRow } from '@/lib/types';
|
||||
import type { TimeMode } from '@/lib/types';
|
||||
|
||||
interface Props {
|
||||
config: ChartConfig;
|
||||
rows: SignalRow[];
|
||||
sessions: SessionBoundary[];
|
||||
alerts: AlertConfig[];
|
||||
timeMode: TimeMode;
|
||||
onEdit: () => void;
|
||||
onDelete: () => void;
|
||||
}
|
||||
|
||||
export default function SignalsChart({ config, rows, sessions, alerts, timeMode, onEdit, onDelete }: Props) {
|
||||
const { localeMap } = useApp();
|
||||
|
||||
const { containerRef, legendRef } = usePlot(
|
||||
(el, w, h, lRef) => {
|
||||
const data = buildSeriesData(rows, config.signal_type, timeMode);
|
||||
if (!data) return null;
|
||||
|
||||
const { keys, allXs, data: seriesData } = data;
|
||||
const sessionXs = sessions.map(s => timeMode === 'tick' ? s.game_tick : new Date(s.real_time).getTime() / 1000);
|
||||
const alertThresholds = alerts
|
||||
.filter(a => config.signal_type === 'both' || config.signal_type === a.signal_type)
|
||||
.map(a => a.threshold);
|
||||
|
||||
return new uPlot({
|
||||
width: w,
|
||||
height: h,
|
||||
cursor: CURSOR_NO_DRAG,
|
||||
legend: {
|
||||
mount: (_u, legendEl) => {
|
||||
if (lRef.current) lRef.current.appendChild(legendEl);
|
||||
},
|
||||
},
|
||||
series: makeSignalsSeries(keys, timeMode, key => resolveName(key, localeMap)),
|
||||
axes: makeSignalsAxes(timeMode),
|
||||
scales: {
|
||||
x: { time: false },
|
||||
y: makeYScale(config.y_min ?? null, config.y_max ?? null, config.y_scale),
|
||||
},
|
||||
hooks: makeAnnotationHooks(sessionXs, alertThresholds),
|
||||
}, [allXs, ...seriesData], el);
|
||||
},
|
||||
[rows, sessions, alerts, config, timeMode, localeMap],
|
||||
);
|
||||
|
||||
return (
|
||||
<CardShell title={config.title} onEdit={onEdit} onDelete={onDelete} empty={rows.length === 0} legendContainerRef={legendRef}>
|
||||
<div ref={containerRef as React.RefObject<HTMLDivElement>} className="w-full h-full" />
|
||||
</CardShell>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user