forked from snehilvj/dash-mantine-components
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLineChart.tsx
173 lines (151 loc) · 5.81 KB
/
LineChart.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import { LineChart as MantineLineChart } from "@mantine/charts";
import {
LineChartCurveType,
LineChartSeries,
LineChartGradientStop,
LineChartType,
} from "@mantine/charts/lib/LineChart/LineChart";
import { BoxProps } from "props/box";
import { GridChartBaseProps } from "props/charts";
import { DashBaseProps } from "props/dash";
import { StylesApiProps } from "props/styles";
import React, { useState, useRef } from "react";
import { getClickData, isEventValid } from "../../utils/charts";
interface Props
extends BoxProps,
GridChartBaseProps,
StylesApiProps,
DashBaseProps {
/** Data used to display chart */
data: Record<string, any>[];
/** An array of objects with `name` and `color` keys. Determines which data should be consumed from the `data` array. */
series: LineChartSeries[];
/** Type of the curve, `'monotone'` by default */
curveType?: LineChartCurveType;
/** Controls fill opacity of all lines, `1` by default */
fillOpacity?: number;
/** Determines whether dots should be displayed, `true` by default */
withDots?: boolean;
/** Props passed down to all dots. Ignored if `withDots={false}` is set. */
dotProps?: any;
/** Props passed down to all active dots. Ignored if `withDots={false}` is set. */
activeDotProps?: any;
/** Stroke width for the chart lines, `2` by default */
strokeWidth?: number;
/** Props passed down to recharts `LineChart` component */
lineChartProps?: any;
/** Props passed down to recharts `Line` component */
lineProps?: any;
/** Determines whether points with `null` values should be connected, `true` by default */
connectNulls?: boolean;
/** Additional components that are rendered inside recharts `AreaChart` component */
children?: React.ReactNode;
/** Click data */
clickData?: Record<string, any>;
/** Hover data */
hoverData?: Record<string, any>;
/** Name of the series that was clicked */
clickSeriesName?: Record<string, any>;
/** Name of the series that is hovered*/
hoverSeriesName?: Record<string, any>;
/**Determines whether a hovered series is highlighted. False by default. Mirrors the behaviour when hovering about chart legend items*/
highlightHover?: boolean
/** Determines whether each point should have associated label, False by default */
withPointLabels?: boolean;
/** Data used to generate gradient stops, [{ offset: 0, color: 'red' }, { offset: 100, color: 'blue' }] by default */
gradientStops?: LineChartGradientStop[];
/** Controls styles of the line 'default' | 'gradient'. 'default' by default */
type?: LineChartType;
}
/** Mantine-themed line chart built on top of the Recharts library, */
const LineChart = (props: Props) => {
const { setProps, loading_state, clickData, hoverData, clickSeriesName, hoverSeriesName, series, highlightHover, lineChartProps, activeDotProps, lineProps, ...others } = props;
const [highlightedArea, setHighlightedArea] = useState(null);
const shouldHighlight = highlightHover && highlightedArea !== null;
const seriesName = useRef(null);
const onClick = (ev) => {
if (isEventValid(ev)) {
setProps({
clickSeriesName: seriesName.current,
clickData: getClickData(ev)
});
}
seriesName.current = null;
};
const onMouseOver = (ev) => {
if (isEventValid(ev)) {
setProps({
hoverSeriesName: seriesName.current,
hoverData: getClickData(ev)
});
}
seriesName.current = null;
};
const handleSeriesClick= (ev) => {
if (isEventValid(ev)) {
seriesName.current = ev["name"];
}
};
const handleSeriesHover = (ev) => {
if (isEventValid(ev)) {
const hoveredSeriesName = ev["name"];
seriesName.current = hoveredSeriesName;
setHighlightedArea(hoveredSeriesName);
}
};
const handleDotClick = (ev, payload) => {
if (isEventValid(ev)) {
seriesName.current = payload["dataKey"];
}
}
const handleDotHover = (ev, payload) => {
if (isEventValid(ev)) {
const hoveredSeriesName = payload["dataKey"];
seriesName.current = hoveredSeriesName;
setHighlightedArea(hoveredSeriesName);
}
};
const handleHoverEnd = () => {
setHighlightedArea(null); // Reset highlighted area
};
const linePropsFunction = (item) => {
const dimmed = shouldHighlight && highlightedArea !== item.name;
const returnProps : any = {
...lineProps,
onClick: handleSeriesClick,
onMouseOver: handleSeriesHover,
onMouseOut: handleHoverEnd,
};
/**if not dimmed, default behavior of Opacity will be triggered, including Hover over chart legend (BarChart.mjs)
fillOpacity: dimmed ? 0.1 : fillOpacity,
strokeOpacity: dimmed ? 0.2 : 0,
*/
if (dimmed) {
returnProps.fillOpacity = 0.1;
returnProps.strokeOpacity = 0.2;
}
return returnProps;
};
const newProps = { ...lineChartProps, onClick, onMouseOver };
return (
<MantineLineChart
data-dash-is-loading={
(loading_state && loading_state.is_loading) || undefined
}
lineChartProps={newProps}
series={series}
activeDotProps={{
...activeDotProps,
onClick: handleDotClick,
onMouseOver: handleDotHover,
onMouseOut: handleHoverEnd,
}}
lineProps={linePropsFunction}
{...others}
/>
);
};
LineChart.defaultProps = {
highlightHover: false,
};
export default LineChart;