Files
factorio-signal-exporter/web/components/ChartCard/UpsChart.tsx

86 lines
2.4 KiB
TypeScript

'use client';
import 'uplot/dist/uPlot.min.css';
import uPlot from 'uplot';
import { CardShell } from './CardShell';
import { AXIS_BASE, CURSOR_NO_DRAG, makeYScale } from './plotHelpers';
import { usePlot } from './usePlot';
import type { ChartConfig, UpsRow, TimeMode } from '@/lib/types';
import { formatSI } from '@/lib/formatNumber';
interface Props {
config: ChartConfig;
upsRows: UpsRow[];
timeMode: TimeMode;
onEdit: () => void;
onDelete: () => void;
}
export default function UpsChart({ config, upsRows, timeMode, onEdit, onDelete }: Props) {
const { containerRef, legendRef } = usePlot(
(el, w, h, lRef) => {
if (upsRows.length < 2) return null;
const data = timeMode === 'tick'
? [...upsRows].sort((a, b) => a.game_tick - b.game_tick)
: upsRows;
const xs = data.map((r) =>
timeMode === 'tick' ? r.game_tick : new Date(r.real_time).getTime() / 1000,
);
const ys = data.map((r) => r.ups);
const xAxis: uPlot.Axis = {
...AXIS_BASE,
values:
timeMode === 'real'
? (_u, vals) =>
vals.map((v) => (v == null ? '' : new Date(v * 1000).toLocaleTimeString()))
: (_u, vals) => vals.map((v) => (v == null ? '' : formatSI(v))),
};
return new uPlot(
{
width: w,
height: h,
cursor: CURSOR_NO_DRAG,
legend: {
mount: (_u, legendEl) => {
if (lRef.current) lRef.current.appendChild(legendEl);
},
},
series: [
{ label: timeMode === 'tick' ? 'Tick' : 'Time' },
{ label: 'UPS', stroke: '#4ade80', width: 1.5 },
],
axes: [
xAxis,
{ ...AXIS_BASE, values: (_u, vals) => vals.map((v) => (v == null ? '' : formatSI(v))) },
],
scales: {
x: { time: false },
y: makeYScale(config.y_min ?? null, config.y_max ?? null, config.y_scale),
},
},
[xs, ys],
el,
);
},
[upsRows, config.y_min, config.y_max, config.y_scale, timeMode],
);
return (
<CardShell
title={config.title}
onEdit={onEdit}
onDelete={onDelete}
empty={upsRows.length === 0}
legendContainerRef={legendRef}
>
<div ref={containerRef as React.RefObject<HTMLDivElement>} className="w-full h-full" />
</CardShell>
);
}