101 lines
2.5 KiB
TypeScript
101 lines
2.5 KiB
TypeScript
import {
|
|
LineChart,
|
|
Line,
|
|
XAxis,
|
|
YAxis,
|
|
CartesianGrid,
|
|
Tooltip,
|
|
ResponsiveContainer
|
|
} from 'recharts';
|
|
import type { ChartDataPoint } from '@/lib/types';
|
|
import { getChartColors } from '../utils/chart-colors';
|
|
import { ChartTooltip } from '../primitives/chart-tooltip';
|
|
import { isPriceData, isOHLCVData } from '../utils/chart-data-transformers';
|
|
|
|
type LineChartViewProps = {
|
|
data: ChartDataPoint[];
|
|
formatters?: {
|
|
price?: (value: number) => string;
|
|
date?: (value: string) => string;
|
|
volume?: (value: number) => string;
|
|
};
|
|
};
|
|
|
|
export function LineChartView({
|
|
data,
|
|
formatters
|
|
}: LineChartViewProps) {
|
|
const colors = getChartColors();
|
|
|
|
const chartData = data.map(point => {
|
|
if (isOHLCVData(point)) {
|
|
return {
|
|
date: point.date,
|
|
price: point.close,
|
|
open: point.open,
|
|
high: point.high,
|
|
low: point.low,
|
|
close: point.close,
|
|
volume: point.volume
|
|
};
|
|
} else if (isPriceData(point)) {
|
|
return {
|
|
date: point.date,
|
|
price: point.price
|
|
};
|
|
}
|
|
return point;
|
|
});
|
|
|
|
return (
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<LineChart data={chartData} margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
|
|
<CartesianGrid
|
|
strokeDasharray="3 3"
|
|
stroke={colors.grid}
|
|
vertical={false}
|
|
/>
|
|
<XAxis
|
|
dataKey="date"
|
|
stroke={colors.muted}
|
|
fontSize={11}
|
|
tickFormatter={formatters?.date}
|
|
minTickGap={50}
|
|
axisLine={{ stroke: colors.grid }}
|
|
tickLine={false}
|
|
/>
|
|
<YAxis
|
|
stroke={colors.muted}
|
|
fontSize={11}
|
|
tickFormatter={formatters?.price}
|
|
width={65}
|
|
domain={['auto', 'auto']}
|
|
axisLine={false}
|
|
tickLine={false}
|
|
orientation="right"
|
|
/>
|
|
<Tooltip
|
|
content={(tooltipProps) => <ChartTooltip {...tooltipProps} formatters={formatters} />}
|
|
cursor={{ stroke: colors.muted, strokeWidth: 1, strokeDasharray: '5 5' }}
|
|
isAnimationActive={false}
|
|
/>
|
|
<Line
|
|
type="linear"
|
|
dataKey="price"
|
|
stroke={colors.primary}
|
|
strokeWidth={2}
|
|
dot={false}
|
|
activeDot={{
|
|
r: 4,
|
|
stroke: colors.primary,
|
|
strokeWidth: 2,
|
|
fill: colors.tooltipBg
|
|
}}
|
|
isAnimationActive={false}
|
|
connectNulls={true}
|
|
/>
|
|
</LineChart>
|
|
</ResponsiveContainer>
|
|
);
|
|
}
|