158 lines
3.6 KiB
TypeScript
158 lines
3.6 KiB
TypeScript
import React from 'react';
|
|
import {
|
|
Chart as ChartJS,
|
|
CategoryScale,
|
|
LinearScale,
|
|
PointElement,
|
|
LineElement,
|
|
Title,
|
|
Tooltip,
|
|
Filler,
|
|
Legend,
|
|
} from 'chart.js';
|
|
import { Line } from 'react-chartjs-2';
|
|
import { useGetCoinChartQuery } from '../coinApi';
|
|
import { format } from 'date-fns';
|
|
|
|
import Button from '@mui/material/Button';
|
|
import ButtonGroup from '@mui/material/ButtonGroup';
|
|
import Grid from '@mui/material/Grid';
|
|
|
|
import {
|
|
ICoinChartProps,
|
|
IChartDataItem,
|
|
IChartData,
|
|
IChartDataFormatted
|
|
} from './coinDetails-types';
|
|
|
|
ChartJS.register(
|
|
CategoryScale,
|
|
LinearScale,
|
|
PointElement,
|
|
LineElement,
|
|
Title,
|
|
Tooltip,
|
|
Filler,
|
|
Legend
|
|
);
|
|
|
|
export interface IDurationOption {
|
|
label: string;
|
|
value: string;
|
|
}
|
|
|
|
export interface IDurationOptions extends Array<IDurationOption> { }
|
|
|
|
const CoinChart = (props: ICoinChartProps): JSX.Element => {
|
|
|
|
const ref = React.useRef<any>(null);
|
|
const [duration, setDuration] = React.useState('max')
|
|
const [redraw, setRedraw] = React.useState(false);
|
|
|
|
// BUG: responsive and redraw toghether cause double render
|
|
React.useEffect(() => {
|
|
function handleResize() {
|
|
setTimeout(function () { setRedraw(true) }, 1000);
|
|
setTimeout(function () { setRedraw(false) }, 2000);
|
|
}
|
|
window.addEventListener('resize', handleResize)
|
|
}, []);
|
|
|
|
|
|
const chartRequest = {
|
|
coin: props.coin,
|
|
days: duration
|
|
}
|
|
|
|
const { data, isSuccess, refetch } = useGetCoinChartQuery(chartRequest);
|
|
|
|
|
|
const durationOptions: IDurationOptions = [
|
|
{ label: "1D", value: '1' },
|
|
{ label: "2W", value: '14' },
|
|
{ label: "1M", value: '30' },
|
|
{ label: "3M", value: '90' },
|
|
{ label: "1Y", value: '365' },
|
|
{ label: "MAX", value: 'max' }
|
|
];
|
|
|
|
function formatChartData(data: IChartData): IChartDataFormatted {
|
|
return data['prices'].map(function (value: IChartDataItem) {
|
|
return {
|
|
x: new Date(value[0]),
|
|
y: value[1],
|
|
};
|
|
});
|
|
}
|
|
|
|
function formatChartLabels(data: IChartData): string[] {
|
|
return data['prices'].map((value: IChartDataItem) =>
|
|
format(new Date(value[0]), 'MM/dd/yyyy')
|
|
);
|
|
}
|
|
|
|
function durationHandler(value: string): void {
|
|
setDuration(value)
|
|
refetch()
|
|
}
|
|
|
|
const chartOptions = {
|
|
elements: {
|
|
point: {
|
|
radius: 0
|
|
}
|
|
},
|
|
color: '#444444',
|
|
borderColor: '#444444',
|
|
backgroundColor: '#444444',
|
|
responsive: true,
|
|
maintainAspectRatio: true,
|
|
aspectRatio: 2,
|
|
pointRadius: 0,
|
|
plugins: {
|
|
legend: {
|
|
display: false
|
|
},
|
|
},
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className="chart"
|
|
>
|
|
{
|
|
data && <>
|
|
<Grid container justifyContent="flex-start" style={{ marginBottom: 20 }}>
|
|
<ButtonGroup variant="contained" aria-label="outlined primary button group">
|
|
{
|
|
durationOptions.map(item => <Button
|
|
key={item.value}
|
|
variant={item.value === duration ? 'outlined' : 'contained'}
|
|
onClick={() => { durationHandler(item.value) }}>{item.label}
|
|
</Button>
|
|
)
|
|
}
|
|
</ButtonGroup>
|
|
</Grid>
|
|
<div id="chart" className="chart-container" style={{ position: "relative", height: "auto" }}> <Line
|
|
options={chartOptions}
|
|
redraw={redraw}
|
|
updateMode="resize"
|
|
data={{
|
|
labels: formatChartLabels(data),
|
|
datasets: [{
|
|
label: 'Dataset',
|
|
data: formatChartData(data)
|
|
}],
|
|
}}
|
|
/>
|
|
</div>
|
|
</>
|
|
}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default CoinChart;
|