2021-09-23 15:43:43 +05:30
|
|
|
import {
|
|
|
|
|
BarController,
|
|
|
|
|
BarElement,
|
|
|
|
|
CategoryScale,
|
|
|
|
|
Chart,
|
|
|
|
|
ChartType,
|
|
|
|
|
Decimation,
|
|
|
|
|
Filler,
|
|
|
|
|
Legend,
|
|
|
|
|
LinearScale,
|
|
|
|
|
LineController,
|
|
|
|
|
LineElement,
|
|
|
|
|
PointElement,
|
|
|
|
|
SubTitle,
|
|
|
|
|
TimeScale,
|
|
|
|
|
TimeSeriesScale,
|
|
|
|
|
Title,
|
|
|
|
|
Tooltip,
|
|
|
|
|
} from 'chart.js';
|
2022-07-14 13:23:15 +05:30
|
|
|
import annotationPlugin from 'chartjs-plugin-annotation';
|
2023-01-11 14:39:06 +05:30
|
|
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
2023-02-10 18:02:37 +05:30
|
|
|
import isEqual from 'lodash-es/isEqual';
|
2023-08-02 20:41:09 +05:30
|
|
|
import {
|
|
|
|
|
forwardRef,
|
|
|
|
|
memo,
|
|
|
|
|
useCallback,
|
|
|
|
|
useEffect,
|
|
|
|
|
useImperativeHandle,
|
|
|
|
|
useRef,
|
|
|
|
|
} from 'react';
|
2021-09-23 15:43:43 +05:30
|
|
|
|
2022-03-29 16:05:08 +05:30
|
|
|
import { hasData } from './hasData';
|
2022-03-22 12:10:31 +05:30
|
|
|
import { legend } from './Plugin';
|
2023-08-02 20:41:09 +05:30
|
|
|
import { createDragSelectPlugin } from './Plugin/DragSelect';
|
2022-03-29 16:05:08 +05:30
|
|
|
import { emptyGraph } from './Plugin/EmptyGraph';
|
2023-08-02 20:41:09 +05:30
|
|
|
import { createIntersectionCursorPlugin } from './Plugin/IntersectionCursor';
|
2023-02-28 08:46:31 +00:00
|
|
|
import { TooltipPosition as TooltipPositionHandler } from './Plugin/Tooltip';
|
2022-03-22 12:10:31 +05:30
|
|
|
import { LegendsContainer } from './styles';
|
2023-08-02 20:41:09 +05:30
|
|
|
import { CustomChartOptions, GraphProps, ToggleGraphProps } from './types';
|
|
|
|
|
import { getGraphOptions, toggleGraph } from './utils';
|
2022-03-11 13:39:04 +05:30
|
|
|
import { useXAxisTimeUnit } from './xAxisConfig';
|
2022-03-15 15:18:33 +05:30
|
|
|
|
2021-09-28 18:20:14 +05:30
|
|
|
Chart.register(
|
|
|
|
|
LineElement,
|
|
|
|
|
PointElement,
|
|
|
|
|
LineController,
|
|
|
|
|
CategoryScale,
|
|
|
|
|
LinearScale,
|
|
|
|
|
TimeScale,
|
|
|
|
|
TimeSeriesScale,
|
|
|
|
|
Decimation,
|
|
|
|
|
Filler,
|
|
|
|
|
Legend,
|
|
|
|
|
Title,
|
|
|
|
|
Tooltip,
|
|
|
|
|
SubTitle,
|
|
|
|
|
BarController,
|
|
|
|
|
BarElement,
|
2022-07-14 13:23:15 +05:30
|
|
|
annotationPlugin,
|
2021-09-28 18:20:14 +05:30
|
|
|
);
|
2021-09-23 15:43:43 +05:30
|
|
|
|
2023-02-28 08:46:31 +00:00
|
|
|
Tooltip.positioners.custom = TooltipPositionHandler;
|
|
|
|
|
|
2023-08-02 20:41:09 +05:30
|
|
|
const Graph = forwardRef<ToggleGraphProps | undefined, GraphProps>(
|
|
|
|
|
(
|
|
|
|
|
{
|
|
|
|
|
animate = true,
|
|
|
|
|
data,
|
|
|
|
|
type,
|
|
|
|
|
title,
|
|
|
|
|
isStacked,
|
|
|
|
|
onClickHandler,
|
|
|
|
|
name,
|
|
|
|
|
yAxisUnit = 'short',
|
|
|
|
|
forceReRender,
|
|
|
|
|
staticLine,
|
|
|
|
|
containerHeight,
|
|
|
|
|
onDragSelect,
|
|
|
|
|
dragSelectColor,
|
|
|
|
|
},
|
|
|
|
|
ref,
|
|
|
|
|
): JSX.Element => {
|
|
|
|
|
const nearestDatasetIndex = useRef<null | number>(null);
|
|
|
|
|
const chartRef = useRef<HTMLCanvasElement>(null);
|
|
|
|
|
const isDarkMode = useIsDarkMode();
|
|
|
|
|
|
|
|
|
|
const currentTheme = isDarkMode ? 'dark' : 'light';
|
|
|
|
|
const xAxisTimeUnit = useXAxisTimeUnit(data); // Computes the relevant time unit for x axis by analyzing the time stamp data
|
|
|
|
|
|
|
|
|
|
const lineChartRef = useRef<Chart>();
|
|
|
|
|
|
|
|
|
|
useImperativeHandle(
|
|
|
|
|
ref,
|
|
|
|
|
(): ToggleGraphProps => ({
|
|
|
|
|
toggleGraph(graphIndex: number, isVisible: boolean): void {
|
|
|
|
|
toggleGraph(graphIndex, isVisible, lineChartRef);
|
2022-03-22 16:22:02 +05:30
|
|
|
},
|
2023-08-02 20:41:09 +05:30
|
|
|
}),
|
|
|
|
|
);
|
2023-02-07 13:25:33 +02:00
|
|
|
|
2023-08-02 20:41:09 +05:30
|
|
|
const getGridColor = useCallback(() => {
|
|
|
|
|
if (currentTheme === undefined) {
|
|
|
|
|
return 'rgba(231,233,237,0.1)';
|
|
|
|
|
}
|
2023-02-07 13:25:33 +02:00
|
|
|
|
2023-08-02 20:41:09 +05:30
|
|
|
if (currentTheme === 'dark') {
|
|
|
|
|
return 'rgba(231,233,237,0.1)';
|
|
|
|
|
}
|
2022-07-14 13:23:15 +05:30
|
|
|
|
2023-08-02 20:41:09 +05:30
|
|
|
return 'rgba(231,233,237,0.8)';
|
|
|
|
|
}, [currentTheme]);
|
2022-06-24 15:00:21 +05:30
|
|
|
|
2023-08-02 20:41:09 +05:30
|
|
|
const buildChart = useCallback(() => {
|
|
|
|
|
if (lineChartRef.current !== undefined) {
|
|
|
|
|
lineChartRef.current.destroy();
|
2023-01-17 13:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-02 20:41:09 +05:30
|
|
|
if (chartRef.current !== null) {
|
|
|
|
|
const options: CustomChartOptions = getGraphOptions(
|
|
|
|
|
animate,
|
|
|
|
|
staticLine,
|
|
|
|
|
title,
|
|
|
|
|
nearestDatasetIndex,
|
|
|
|
|
yAxisUnit,
|
|
|
|
|
onDragSelect,
|
|
|
|
|
dragSelectColor,
|
|
|
|
|
currentTheme,
|
|
|
|
|
getGridColor,
|
|
|
|
|
xAxisTimeUnit,
|
|
|
|
|
isStacked,
|
|
|
|
|
onClickHandler,
|
|
|
|
|
data,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const chartHasData = hasData(data);
|
|
|
|
|
const chartPlugins = [];
|
|
|
|
|
|
|
|
|
|
if (chartHasData) {
|
|
|
|
|
chartPlugins.push(createIntersectionCursorPlugin());
|
|
|
|
|
chartPlugins.push(createDragSelectPlugin());
|
|
|
|
|
} else {
|
|
|
|
|
chartPlugins.push(emptyGraph);
|
|
|
|
|
}
|
2021-09-23 15:43:43 +05:30
|
|
|
|
2023-08-02 20:41:09 +05:30
|
|
|
chartPlugins.push(legend(name, data.datasets.length > 3));
|
2021-09-23 15:43:43 +05:30
|
|
|
|
2023-08-02 20:41:09 +05:30
|
|
|
lineChartRef.current = new Chart(chartRef.current, {
|
|
|
|
|
type,
|
|
|
|
|
data,
|
|
|
|
|
options,
|
|
|
|
|
plugins: chartPlugins,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}, [
|
|
|
|
|
animate,
|
|
|
|
|
staticLine,
|
|
|
|
|
title,
|
|
|
|
|
yAxisUnit,
|
|
|
|
|
onDragSelect,
|
|
|
|
|
dragSelectColor,
|
|
|
|
|
currentTheme,
|
|
|
|
|
getGridColor,
|
|
|
|
|
xAxisTimeUnit,
|
|
|
|
|
isStacked,
|
|
|
|
|
onClickHandler,
|
|
|
|
|
data,
|
|
|
|
|
name,
|
|
|
|
|
type,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
buildChart();
|
|
|
|
|
}, [buildChart, forceReRender]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div style={{ height: containerHeight }}>
|
|
|
|
|
<canvas ref={chartRef} />
|
|
|
|
|
<LegendsContainer id={name} />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
2021-09-23 15:43:43 +05:30
|
|
|
|
2023-02-28 08:46:31 +00:00
|
|
|
declare module 'chart.js' {
|
|
|
|
|
interface TooltipPositionerMap {
|
|
|
|
|
custom: TooltipPositionerFunction<ChartType>;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-24 12:06:57 +05:30
|
|
|
Graph.defaultProps = {
|
|
|
|
|
animate: undefined,
|
|
|
|
|
title: undefined,
|
|
|
|
|
isStacked: undefined,
|
|
|
|
|
onClickHandler: undefined,
|
|
|
|
|
yAxisUnit: undefined,
|
|
|
|
|
forceReRender: undefined,
|
2022-07-14 13:23:15 +05:30
|
|
|
staticLine: undefined,
|
2023-01-18 19:53:45 +05:30
|
|
|
containerHeight: '90%',
|
2023-01-17 13:30:34 +02:00
|
|
|
onDragSelect: undefined,
|
|
|
|
|
dragSelectColor: undefined,
|
2022-03-24 12:06:57 +05:30
|
|
|
};
|
2023-02-10 18:02:37 +05:30
|
|
|
|
2023-08-02 20:41:09 +05:30
|
|
|
Graph.displayName = 'Graph';
|
|
|
|
|
|
2023-02-10 18:02:37 +05:30
|
|
|
export default memo(Graph, (prevProps, nextProps) =>
|
|
|
|
|
isEqual(prevProps.data, nextProps.data),
|
|
|
|
|
);
|