Rajat Dabade b339f0509b
Improved graph panel full view (#3039)
* feat: done with prd full view

* refactor: updated some variable and naming convection

* feat: when click on label only select associated graph

* feat: made the table scrollable

* feat: update the table column length

* feat: save notification after saving state

* refactor: removed unwanted code

* refactor: renamed some file

* fix: linter issue

* fix: position of save button

* refactor: seperated widgetGraphComponent from gridGraphComponent

* feat: fetching the localstorage data while initial loading of graph

* fix: dependency of graphVisibilityHandler for other component

* refactor: updated the notification msg on save

* fix: linter error

* refactor: remove the update logic of graph from graph component

* refactor: created utils and move some utility code

* refactor: place the checkbox component in fullview

* refactor: updated the utils function added enun localstorage

* refactor: added enum for table columns data

* refactor: name changes to graphVisibilityStates

* refactor: shifted the type to types.ts

* refactor: sepearated the type from graph componnet

* refactor: seperated graphOptions from graph component

* refactor: updated imports

* refactor: shifted the logic to utils

* refactor: remove unused file and check for full view

* refactor: using PanelType instead of GraphType

* refactor: changed the variable name

* refactor: provided checks of useEffect

* test: added unit test case for utility function

* refactor: one on one maping of props and value

* refactor: panelTypeAndGraphManagerVisibility as a props

* refactor: remove the enforing of type in useChartMutable

* refactor: updated the test case

* refactor: moved types to types.ts files

* refactor: separated types from components

* refactor: one to one mapping and cancel feature

* refactor: remove unwanted useEffect and used eventEmitter

* fix: only open chart visibility will change issue

* refactor: removed unwanted useEffect

* refactor: resolve the hang issue for full view

* refactor: legend to checkbox connection, separated code

* refactor: updated styled component GraphContainer

* chore: removed unwanted consoles

* refactor: ux changes

* fix: eslint and updated test case

* refactor: review comments

* chore: fix types

* refactor: made utils for getIsGraphLegendToggleAvailable

* refactor: removed the ref mutation from graphPanelSwitch

* refactor: resolve the issue of chart state not getting reflect outside fullview

* refactor: common utility for toggle graphs visibility in chart

* refactor: shifted ref to perticular component level

* test: removed extra space

* chore: close on save and NaN infinity check

* refactor: added yAxisUnit to GraphManager table header

* refactor: create a function for appending yAxisUnit to table header

* fix: decimal upto 2 decimal points

---------

Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
Co-authored-by: Pranay Prateek <pranay@signoz.io>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-08-02 20:41:09 +05:30

208 lines
4.3 KiB
TypeScript

import {
BarController,
BarElement,
CategoryScale,
Chart,
ChartType,
Decimation,
Filler,
Legend,
LinearScale,
LineController,
LineElement,
PointElement,
SubTitle,
TimeScale,
TimeSeriesScale,
Title,
Tooltip,
} from 'chart.js';
import annotationPlugin from 'chartjs-plugin-annotation';
import { useIsDarkMode } from 'hooks/useDarkMode';
import isEqual from 'lodash-es/isEqual';
import {
forwardRef,
memo,
useCallback,
useEffect,
useImperativeHandle,
useRef,
} from 'react';
import { hasData } from './hasData';
import { legend } from './Plugin';
import { createDragSelectPlugin } from './Plugin/DragSelect';
import { emptyGraph } from './Plugin/EmptyGraph';
import { createIntersectionCursorPlugin } from './Plugin/IntersectionCursor';
import { TooltipPosition as TooltipPositionHandler } from './Plugin/Tooltip';
import { LegendsContainer } from './styles';
import { CustomChartOptions, GraphProps, ToggleGraphProps } from './types';
import { getGraphOptions, toggleGraph } from './utils';
import { useXAxisTimeUnit } from './xAxisConfig';
Chart.register(
LineElement,
PointElement,
LineController,
CategoryScale,
LinearScale,
TimeScale,
TimeSeriesScale,
Decimation,
Filler,
Legend,
Title,
Tooltip,
SubTitle,
BarController,
BarElement,
annotationPlugin,
);
Tooltip.positioners.custom = TooltipPositionHandler;
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);
},
}),
);
const getGridColor = useCallback(() => {
if (currentTheme === undefined) {
return 'rgba(231,233,237,0.1)';
}
if (currentTheme === 'dark') {
return 'rgba(231,233,237,0.1)';
}
return 'rgba(231,233,237,0.8)';
}, [currentTheme]);
const buildChart = useCallback(() => {
if (lineChartRef.current !== undefined) {
lineChartRef.current.destroy();
}
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);
}
chartPlugins.push(legend(name, data.datasets.length > 3));
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>
);
},
);
declare module 'chart.js' {
interface TooltipPositionerMap {
custom: TooltipPositionerFunction<ChartType>;
}
}
Graph.defaultProps = {
animate: undefined,
title: undefined,
isStacked: undefined,
onClickHandler: undefined,
yAxisUnit: undefined,
forceReRender: undefined,
staticLine: undefined,
containerHeight: '90%',
onDragSelect: undefined,
dragSelectColor: undefined,
};
Graph.displayName = 'Graph';
export default memo(Graph, (prevProps, nextProps) =>
isEqual(prevProps.data, nextProps.data),
);