@react-magma/charts 0.0.0-9de073 → 0.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -40
- package/dist/charts.js +1 -1
- package/dist/charts.js.map +1 -1
- package/dist/charts.modern.js +63 -25
- package/dist/charts.modern.js.map +1 -1
- package/dist/charts.modern.module.js +1 -1
- package/dist/charts.modern.module.js.map +1 -1
- package/dist/charts.umd.js +1 -1
- package/dist/charts.umd.js.map +1 -1
- package/dist/components/LineChart/Chart.d.ts +11 -2
- package/dist/components/LineChart/ChartDataTable.d.ts +2 -1
- package/dist/components/LineChart/CustomAxisComponent.d.ts +3 -0
- package/dist/components/LineChart/CustomPointComponent.d.ts +17 -1
- package/dist/components/LineChart/DataTable.d.ts +1 -0
- package/dist/components/LineChart/GraphTooltip.d.ts +2 -1
- package/dist/components/LineChart/LegendButton.d.ts +1 -1
- package/dist/components/LineChart/LineChart.d.ts +29 -1
- package/dist/components/LineChart/LineChart.stories.d.ts +6 -7
- package/dist/components/LineChart/magma-charts.d.ts +1 -457
- package/dist/index.d.ts +0 -1
- package/package.json +8 -6
- package/src/components/LineChart/Chart.tsx +180 -20
- package/src/components/LineChart/ChartDataTable.test.js +1 -1
- package/src/components/LineChart/ChartDataTable.tsx +38 -32
- package/src/components/LineChart/CustomAxisComponent.tsx +29 -0
- package/src/components/LineChart/CustomPointComponent.tsx +81 -8
- package/src/components/LineChart/DataTable.tsx +3 -1
- package/src/components/LineChart/GraphTooltip.tsx +58 -26
- package/src/components/LineChart/LegendButton.tsx +32 -32
- package/src/components/LineChart/LineChart.stories.tsx +9 -9
- package/src/components/LineChart/LineChart.test.js +105 -11
- package/src/components/LineChart/LineChart.tsx +277 -113
- package/src/components/LineChart/magma-charts.ts +279 -0
- package/src/index.ts +0 -1
- package/dist/components/DataViz/DataVizTabs.d.ts +0 -8
- package/dist/components/DataViz/index.d.ts +0 -1
- package/src/components/DataViz/DataVizTabs.tsx +0 -48
- package/src/components/DataViz/index.ts +0 -1
- package/src/components/LineChart/magma-charts.js +0 -309
|
@@ -1,21 +1,43 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
I18nContext,
|
|
4
|
+
styled,
|
|
5
|
+
ThemeContext,
|
|
6
|
+
useDescendants,
|
|
7
|
+
} from 'react-magma-dom';
|
|
8
|
+
import { css } from '@emotion/core';
|
|
9
|
+
import { KeyboardIcon } from 'react-magma-icons';
|
|
2
10
|
|
|
3
11
|
import { LineChart, LineChartProps } from './LineChart';
|
|
4
12
|
import { ChartDataTable } from './ChartDataTable';
|
|
5
13
|
import {
|
|
6
|
-
|
|
14
|
+
Announce,
|
|
15
|
+
ButtonVariant,
|
|
16
|
+
Card,
|
|
17
|
+
IconButton,
|
|
7
18
|
Paragraph,
|
|
8
19
|
TabsContainer,
|
|
9
20
|
Tabs,
|
|
10
21
|
Tab,
|
|
11
22
|
TabPanelsContainer,
|
|
12
23
|
TabPanel,
|
|
24
|
+
Tooltip,
|
|
25
|
+
TypographyVisualStyle,
|
|
13
26
|
} from 'react-magma-dom';
|
|
14
27
|
|
|
15
28
|
interface BaseChartProps {
|
|
29
|
+
/**
|
|
30
|
+
* Description of what the line chart data represents placed above the chart
|
|
31
|
+
*/
|
|
16
32
|
description?: string;
|
|
17
33
|
testId?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Title of the line chart
|
|
36
|
+
*/
|
|
18
37
|
title: string;
|
|
38
|
+
/**
|
|
39
|
+
* Type of chart - for now just 'line' is accepted
|
|
40
|
+
*/
|
|
19
41
|
type: string;
|
|
20
42
|
}
|
|
21
43
|
export interface ChartProps<T extends any>
|
|
@@ -23,33 +45,171 @@ export interface ChartProps<T extends any>
|
|
|
23
45
|
Omit<React.HTMLAttributes<HTMLDivElement>, 'title'>,
|
|
24
46
|
LineChartProps<T> {}
|
|
25
47
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
48
|
+
const StyledTitle = styled.span`
|
|
49
|
+
color: ${props => props.theme.colors.neutral};
|
|
50
|
+
font-size: ${props => props.theme.typeScale.size04.fontSize};
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
line-height: ${props => props.theme.typeScale.size04.lineHeight};
|
|
53
|
+
margin: 0 0 12px 0;
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
const StyledParagraph = styled(Paragraph)`
|
|
57
|
+
font-size: ${props => props.theme.typeScale.size02.fontSize};
|
|
58
|
+
margin: 0 0 18px 0;
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
const StyledTabsContainer = styled(TabsContainer)`
|
|
62
|
+
width: 800px;
|
|
63
|
+
ul {
|
|
64
|
+
box-shadow: inset 0 -1px 0 ${props => props.theme.colors.neutral06};
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const StyledTabPanel = styled(TabPanel)`
|
|
69
|
+
padding: 22px 0;
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const KeyboardInstructionsCard = styled(Card)<{
|
|
73
|
+
isOpen?: boolean;
|
|
74
|
+
maxHeight?: string;
|
|
75
|
+
width?: string;
|
|
76
|
+
}>`
|
|
77
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
|
|
78
|
+
display: ${props => (props.isOpen ? 'block' : 'none')};
|
|
79
|
+
right: ${props => props.theme.spaceScale.spacing02};
|
|
80
|
+
max-height: ${props =>
|
|
81
|
+
props.maxHeight ? props.maxHeight : props.theme.dropdown.content.maxHeight};
|
|
82
|
+
opacity: ${props => (props.isOpen ? '1' : '0')};
|
|
83
|
+
outline: 0;
|
|
84
|
+
overflow-y: auto;
|
|
85
|
+
padding: ${props => props.theme.spaceScale.spacing05}
|
|
86
|
+
${props => props.theme.spaceScale.spacing05};
|
|
87
|
+
position: absolute;
|
|
88
|
+
transition: opacity 0.3s;
|
|
89
|
+
white-space: nowrap;
|
|
90
|
+
z-index: 2;
|
|
91
|
+
|
|
92
|
+
${props =>
|
|
93
|
+
props.width &&
|
|
94
|
+
css`
|
|
95
|
+
white-space: normal;
|
|
96
|
+
width: ${props.width};
|
|
97
|
+
`}
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
function BaseChart<T>(props: ChartProps<T>, ref: React.Ref<HTMLDivElement>) {
|
|
30
101
|
const { description, title, testId, type, ...other } = props;
|
|
31
|
-
const
|
|
102
|
+
const keyboardInstructionsRef = React.useRef<HTMLButtonElement>(null);
|
|
103
|
+
const lastFocusedScatterPoint = React.useRef<SVGPathElement>(null);
|
|
104
|
+
const theme = React.useContext(ThemeContext);
|
|
105
|
+
const i18n = React.useContext(I18nContext);
|
|
106
|
+
|
|
107
|
+
const [pointRefArray, registerPoint, unregisterPoint] = useDescendants();
|
|
108
|
+
|
|
109
|
+
const [isKeyboardInstructionsOpen, setIsKeyboardInstructionsOpen] =
|
|
110
|
+
React.useState<boolean>(false);
|
|
111
|
+
|
|
112
|
+
function handleKeyboardInstructionsButtonBlur() {
|
|
113
|
+
setIsKeyboardInstructionsOpen(false);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function handleKeyboardInstructionsButtonClick() {
|
|
117
|
+
setIsKeyboardInstructionsOpen(prevOpen => !prevOpen);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function handleKeyboardInstructionsButtonKeydown(event: React.KeyboardEvent) {
|
|
121
|
+
const { key, shiftKey } = event;
|
|
122
|
+
|
|
123
|
+
switch (key) {
|
|
124
|
+
case 'Escape': {
|
|
125
|
+
setIsKeyboardInstructionsOpen(false);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case 'Tab': {
|
|
129
|
+
if (
|
|
130
|
+
!shiftKey &&
|
|
131
|
+
lastFocusedScatterPoint &&
|
|
132
|
+
lastFocusedScatterPoint.current &&
|
|
133
|
+
pointRefArray.current.find(
|
|
134
|
+
point => point.current === lastFocusedScatterPoint.current
|
|
135
|
+
)
|
|
136
|
+
) {
|
|
137
|
+
event.preventDefault();
|
|
138
|
+
lastFocusedScatterPoint.current.focus();
|
|
139
|
+
}
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
32
144
|
|
|
33
145
|
return (
|
|
34
146
|
<div ref={ref}>
|
|
35
|
-
<
|
|
147
|
+
<StyledTitle theme={theme}>{title}</StyledTitle>
|
|
36
148
|
{description && (
|
|
37
|
-
<
|
|
149
|
+
<StyledParagraph
|
|
150
|
+
theme={theme}
|
|
151
|
+
visualStyle={TypographyVisualStyle.bodySmall}
|
|
152
|
+
>
|
|
153
|
+
{description}
|
|
154
|
+
</StyledParagraph>
|
|
38
155
|
)}
|
|
39
|
-
<
|
|
40
|
-
<Tabs
|
|
41
|
-
<Tab
|
|
42
|
-
<Tab>
|
|
156
|
+
<StyledTabsContainer theme={theme}>
|
|
157
|
+
<Tabs>
|
|
158
|
+
<Tab>{i18n.charts.line.chartTabLabel}</Tab>
|
|
159
|
+
<Tab>{i18n.charts.line.dataTabLabel}</Tab>
|
|
160
|
+
<div
|
|
161
|
+
onBlur={handleKeyboardInstructionsButtonBlur}
|
|
162
|
+
style={{
|
|
163
|
+
display: 'inline-block',
|
|
164
|
+
marginLeft: 'auto',
|
|
165
|
+
}}
|
|
166
|
+
>
|
|
167
|
+
<Tooltip
|
|
168
|
+
content={i18n.charts.line.keyboardInstructionsTooltip}
|
|
169
|
+
ref={keyboardInstructionsRef}
|
|
170
|
+
>
|
|
171
|
+
<IconButton
|
|
172
|
+
aria-controls="keyboardInstructions"
|
|
173
|
+
aria-label={i18n.charts.line.keyboardInstructionsTooltip}
|
|
174
|
+
aria-expanded={Boolean(isKeyboardInstructionsOpen)}
|
|
175
|
+
icon={<KeyboardIcon />}
|
|
176
|
+
onClick={handleKeyboardInstructionsButtonClick}
|
|
177
|
+
onKeyDown={handleKeyboardInstructionsButtonKeydown}
|
|
178
|
+
variant={ButtonVariant.link}
|
|
179
|
+
/>
|
|
180
|
+
</Tooltip>
|
|
181
|
+
<Announce>
|
|
182
|
+
<KeyboardInstructionsCard
|
|
183
|
+
id="keyboardInstructions"
|
|
184
|
+
isOpen={isKeyboardInstructionsOpen}
|
|
185
|
+
theme={theme}
|
|
186
|
+
width="350px"
|
|
187
|
+
>
|
|
188
|
+
<Paragraph
|
|
189
|
+
visualStyle={TypographyVisualStyle.headingXSmall}
|
|
190
|
+
style={{ margin: '0 0 16px' }}
|
|
191
|
+
>
|
|
192
|
+
{i18n.charts.line.keyboardInstructionsHeader}
|
|
193
|
+
</Paragraph>
|
|
194
|
+
{i18n.charts.line.keyboardInstructions}
|
|
195
|
+
</KeyboardInstructionsCard>
|
|
196
|
+
</Announce>
|
|
197
|
+
</div>
|
|
43
198
|
</Tabs>
|
|
44
199
|
<TabPanelsContainer>
|
|
45
|
-
<
|
|
200
|
+
<StyledTabPanel theme={theme}>
|
|
46
201
|
{type === 'line' && (
|
|
47
|
-
<LineChart<T>
|
|
202
|
+
<LineChart<T>
|
|
203
|
+
{...other}
|
|
204
|
+
lastFocusedScatterPoint={lastFocusedScatterPoint}
|
|
205
|
+
pointRefArray={pointRefArray}
|
|
206
|
+
registerPoint={registerPoint}
|
|
207
|
+
tabRef={keyboardInstructionsRef}
|
|
208
|
+
unregisterPoint={unregisterPoint}
|
|
209
|
+
/>
|
|
48
210
|
)}
|
|
49
|
-
</
|
|
50
|
-
<
|
|
51
|
-
<Heading level={4}>{title}</Heading>
|
|
52
|
-
{description && <Paragraph>{description}</Paragraph>}
|
|
211
|
+
</StyledTabPanel>
|
|
212
|
+
<StyledTabPanel theme={theme}>
|
|
53
213
|
<ChartDataTable
|
|
54
214
|
data={other.data}
|
|
55
215
|
xData={{
|
|
@@ -62,9 +222,9 @@ function BaseChart<T>(
|
|
|
62
222
|
tickFormat: other.componentProps?.yAxis?.tickFormat,
|
|
63
223
|
}}
|
|
64
224
|
/>
|
|
65
|
-
</
|
|
225
|
+
</StyledTabPanel>
|
|
66
226
|
</TabPanelsContainer>
|
|
67
|
-
</
|
|
227
|
+
</StyledTabsContainer>
|
|
68
228
|
</div>
|
|
69
229
|
);
|
|
70
230
|
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { VictoryAxisProps } from 'victory';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
Card,
|
|
6
|
-
Datagrid,
|
|
7
|
-
Spinner,
|
|
8
|
-
} from 'react-magma-dom';
|
|
4
|
+
import { Card, Datagrid, Spinner } from 'react-magma-dom';
|
|
9
5
|
|
|
10
|
-
export function toCamelCase(str) {
|
|
6
|
+
export function toCamelCase(str: string) {
|
|
11
7
|
return str
|
|
12
8
|
.toLowerCase()
|
|
13
9
|
.replace(/[^a-z 0-9]/gi, '')
|
|
@@ -33,7 +29,7 @@ export interface DataTableProps {
|
|
|
33
29
|
|
|
34
30
|
export const ChartDataTable = (props: DataTableProps) => {
|
|
35
31
|
const {
|
|
36
|
-
data,
|
|
32
|
+
data = [],
|
|
37
33
|
xData: {
|
|
38
34
|
keyValue: xKeyValue,
|
|
39
35
|
label: xAxisLabel,
|
|
@@ -52,10 +48,10 @@ export const ChartDataTable = (props: DataTableProps) => {
|
|
|
52
48
|
}, [data]);
|
|
53
49
|
|
|
54
50
|
function convertData() {
|
|
55
|
-
const xField = toCamelCase(xKeyValue || xAxisLabel || 'x');
|
|
51
|
+
const xField = toCamelCase((xKeyValue || xAxisLabel || 'x') as string);
|
|
56
52
|
const xTickValuesArray = data.reduce((valuesArray, { data: dataset }) => {
|
|
57
|
-
dataset.forEach(datum => {
|
|
58
|
-
const value = datum.x || datum[xKeyValue];
|
|
53
|
+
dataset.forEach((datum: any) => {
|
|
54
|
+
const value = datum.x || (xKeyValue && datum[xKeyValue]);
|
|
59
55
|
!valuesArray.includes(value) && valuesArray.push(value);
|
|
60
56
|
});
|
|
61
57
|
|
|
@@ -65,28 +61,37 @@ export const ChartDataTable = (props: DataTableProps) => {
|
|
|
65
61
|
let baseTableData = {
|
|
66
62
|
columns:
|
|
67
63
|
xTickValuesArray.length > 0
|
|
68
|
-
? [
|
|
64
|
+
? [
|
|
65
|
+
{
|
|
66
|
+
field: xField,
|
|
67
|
+
header: xAxisLabel || xKeyValue || 'X',
|
|
68
|
+
isRowHeader: true,
|
|
69
|
+
},
|
|
70
|
+
]
|
|
69
71
|
: [],
|
|
70
|
-
rows: xTickValuesArray.reduce(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
? xTickFormat
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
72
|
+
rows: xTickValuesArray.reduce(
|
|
73
|
+
(agg: any[], tick: number, index: number) => {
|
|
74
|
+
const tickValue =
|
|
75
|
+
xTickValues &&
|
|
76
|
+
typeof tick === 'number' &&
|
|
77
|
+
xTickValues.length === xTickValuesArray.length
|
|
78
|
+
? xTickFormat && typeof xTickFormat === 'function'
|
|
79
|
+
? xTickFormat(xTickValues[tick - 1])
|
|
80
|
+
: xTickValues[tick - 1]
|
|
81
|
+
: xTickFormat && Array.isArray(xTickFormat)
|
|
82
|
+
? xTickFormat[tick - 1]
|
|
83
|
+
: xTickFormat && typeof xTickFormat === 'function'
|
|
84
|
+
? xTickFormat(tick)
|
|
85
|
+
: tick;
|
|
86
|
+
agg.push({
|
|
87
|
+
[xField]: tickValue,
|
|
88
|
+
id: index,
|
|
89
|
+
});
|
|
87
90
|
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
return agg;
|
|
92
|
+
},
|
|
93
|
+
[]
|
|
94
|
+
),
|
|
90
95
|
};
|
|
91
96
|
|
|
92
97
|
return data.reduce((tableData, datum) => {
|
|
@@ -98,8 +103,9 @@ export const ChartDataTable = (props: DataTableProps) => {
|
|
|
98
103
|
header,
|
|
99
104
|
});
|
|
100
105
|
|
|
101
|
-
dataset.forEach((d, i) => {
|
|
102
|
-
const yValue =
|
|
106
|
+
dataset.forEach((d: any, i: number) => {
|
|
107
|
+
const yValue =
|
|
108
|
+
d.y || d.y === 0 ? d.y : undefined || (yKeyValue && d[yKeyValue]);
|
|
103
109
|
tableData.rows[i] = {
|
|
104
110
|
...tableData.rows[i],
|
|
105
111
|
id: baseTableData.rows.length > 0 ? i + 1 : i,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { LineSegment, LineSegmentProps } from 'victory';
|
|
3
|
+
|
|
4
|
+
export const CustomAxisComponent: React.FunctionComponent<LineSegmentProps> = ({
|
|
5
|
+
events,
|
|
6
|
+
...props
|
|
7
|
+
}: any) => {
|
|
8
|
+
return (
|
|
9
|
+
<g>
|
|
10
|
+
<LineSegment
|
|
11
|
+
{...props}
|
|
12
|
+
events={events}
|
|
13
|
+
style={{
|
|
14
|
+
strokeWidth: '50px',
|
|
15
|
+
stroke: 'transparent',
|
|
16
|
+
}}
|
|
17
|
+
/>
|
|
18
|
+
<LineSegment
|
|
19
|
+
{...props}
|
|
20
|
+
events={events}
|
|
21
|
+
style={{
|
|
22
|
+
strokeWidth: '1px',
|
|
23
|
+
stroke: 'black',
|
|
24
|
+
strokeOpacity: '0.2',
|
|
25
|
+
}}
|
|
26
|
+
/>
|
|
27
|
+
</g>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
@@ -1,19 +1,92 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Point, PointProps } from 'victory';
|
|
2
3
|
import { useForceUpdate } from 'react-magma-dom';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export interface CustomScatterDataComponentInterface extends PointProps {
|
|
6
|
+
lineIndex: number;
|
|
7
|
+
pointRefArray: React.MutableRefObject<React.MutableRefObject<Element>[]>;
|
|
8
|
+
registerPoint: (
|
|
9
|
+
refArray: React.MutableRefObject<React.MutableRefObject<Element>[]>,
|
|
10
|
+
ref: React.MutableRefObject<Element>
|
|
11
|
+
) => void;
|
|
12
|
+
unregisterPoint: (
|
|
13
|
+
refArray: React.MutableRefObject<React.MutableRefObject<Element>[]>,
|
|
14
|
+
ref: React.MutableRefObject<Element>
|
|
15
|
+
) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CustomPointComponentInterface {
|
|
19
|
+
lineIndex: number;
|
|
20
|
+
pointIndex: PointProps['index'];
|
|
21
|
+
pointRefArray: React.MutableRefObject<React.MutableRefObject<Element>[]>;
|
|
22
|
+
registerPoint: (
|
|
23
|
+
refArray: React.MutableRefObject<React.MutableRefObject<Element>[]>,
|
|
24
|
+
ref: React.MutableRefObject<Element>
|
|
25
|
+
) => void;
|
|
26
|
+
unregisterPoint: (
|
|
27
|
+
refArray: React.MutableRefObject<React.MutableRefObject<Element>[]>,
|
|
28
|
+
ref: React.MutableRefObject<Element>
|
|
29
|
+
) => void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const CustomScatterDataComponent = (
|
|
33
|
+
props: CustomScatterDataComponentInterface
|
|
34
|
+
) => {
|
|
35
|
+
const {
|
|
36
|
+
datum,
|
|
37
|
+
index: pointIndex,
|
|
38
|
+
lineIndex,
|
|
39
|
+
pointRefArray,
|
|
40
|
+
registerPoint,
|
|
41
|
+
unregisterPoint,
|
|
42
|
+
...other
|
|
43
|
+
} = props;
|
|
44
|
+
return (
|
|
45
|
+
<Point
|
|
46
|
+
{...other}
|
|
47
|
+
ariaLabel={datum.label}
|
|
48
|
+
pathComponent={
|
|
49
|
+
<CustomPointComponent
|
|
50
|
+
lineIndex={lineIndex}
|
|
51
|
+
pointIndex={pointIndex}
|
|
52
|
+
pointRefArray={pointRefArray}
|
|
53
|
+
registerPoint={registerPoint}
|
|
54
|
+
unregisterPoint={unregisterPoint}
|
|
55
|
+
/>
|
|
56
|
+
}
|
|
57
|
+
role="button"
|
|
58
|
+
tabIndex={0}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const CustomPointComponent = (props: CustomPointComponentInterface) => {
|
|
64
|
+
const {
|
|
65
|
+
lineIndex,
|
|
66
|
+
pointRefArray,
|
|
67
|
+
pointIndex,
|
|
68
|
+
registerPoint,
|
|
69
|
+
unregisterPoint,
|
|
70
|
+
...other
|
|
71
|
+
} = props;
|
|
7
72
|
const forceUpdate = useForceUpdate();
|
|
8
|
-
const ref = React.useRef<SVGPathElement>();
|
|
73
|
+
const ref = React.useRef<SVGPathElement | null>(null);
|
|
9
74
|
|
|
10
75
|
React.useEffect(() => {
|
|
11
|
-
registerPoint(pointRefArray, ref);
|
|
76
|
+
registerPoint(pointRefArray, ref as React.MutableRefObject<Element>);
|
|
12
77
|
|
|
13
78
|
forceUpdate();
|
|
14
79
|
|
|
15
|
-
return () =>
|
|
80
|
+
return () =>
|
|
81
|
+
unregisterPoint(pointRefArray, ref as React.MutableRefObject<Element>);
|
|
16
82
|
}, []);
|
|
17
83
|
|
|
18
|
-
return
|
|
84
|
+
return (
|
|
85
|
+
<path
|
|
86
|
+
ref={ref}
|
|
87
|
+
data-line-index={lineIndex}
|
|
88
|
+
data-point-index={pointIndex}
|
|
89
|
+
{...other}
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
19
92
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
Card,
|
|
3
5
|
Table,
|
|
@@ -35,7 +37,7 @@ export const DataTable = props => {
|
|
|
35
37
|
<TableHeaderCell
|
|
36
38
|
scope={TableHeaderCellScope.row}
|
|
37
39
|
style={{
|
|
38
|
-
borderRight: '
|
|
40
|
+
borderRight: '1px solid #dfdfdf',
|
|
39
41
|
borderBottom: 0,
|
|
40
42
|
}}
|
|
41
43
|
>
|
|
@@ -1,66 +1,98 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
import {
|
|
3
3
|
StyledTooltip,
|
|
4
4
|
ThemeContext,
|
|
5
5
|
TooltipArrow,
|
|
6
6
|
TooltipPosition,
|
|
7
|
+
ThemeInterface,
|
|
8
|
+
styled,
|
|
7
9
|
} from 'react-magma-dom';
|
|
8
|
-
|
|
10
|
+
|
|
11
|
+
const StyledGraphTooltip = styled(StyledTooltip)`
|
|
12
|
+
background: ${(props: any) => props.theme.colors.neutral08};
|
|
13
|
+
border: 1px solid ${(props: any) => props.theme.colors.neutral06};
|
|
14
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
color: ${(props: any) => props.theme.colors.neutral};
|
|
17
|
+
font-size: ${(props: any) => props.theme.typeScale.size02.fontSize};
|
|
18
|
+
font-weight: normal;
|
|
19
|
+
line-height: ${(props: any) => props.theme.typeScale.size02.lineHeight};
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 8px;
|
|
22
|
+
width: fit-content;
|
|
23
|
+
div {
|
|
24
|
+
margin-bottom: 8px;
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: flex-start;
|
|
27
|
+
&:last-of-type {
|
|
28
|
+
margin-bottom: 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
9
32
|
|
|
10
33
|
const TooltipColorSwatch = styled.span`
|
|
11
|
-
|
|
34
|
+
background: ${(props: any) => props.color};
|
|
35
|
+
border: ${(props: any) => (props.color ? 'none' : '3px solid black')};
|
|
12
36
|
border-radius: 4px;
|
|
13
|
-
|
|
14
|
-
|
|
37
|
+
height: 20px;
|
|
38
|
+
width: 20px;
|
|
15
39
|
margin-right: 8px;
|
|
16
|
-
width: 14px;
|
|
17
|
-
background: ${props => props.color};
|
|
18
40
|
`;
|
|
19
41
|
|
|
20
|
-
export const GraphTooltip = props => {
|
|
21
|
-
const { datum, index, x, y } = props;
|
|
42
|
+
export const GraphTooltip = (props: any) => {
|
|
43
|
+
const { datum, index, showTooltip, x, y } = props;
|
|
22
44
|
|
|
23
|
-
const theme = React.useContext(ThemeContext);
|
|
45
|
+
const theme: ThemeInterface = React.useContext(ThemeContext);
|
|
46
|
+
const linePointIndex = `${index}-${datum.index}`;
|
|
24
47
|
|
|
25
|
-
return (
|
|
48
|
+
return showTooltip === linePointIndex ? (
|
|
26
49
|
<g style={{ pointerEvents: 'none' }}>
|
|
27
|
-
<foreignObject x={x} y={y} width="
|
|
28
|
-
<
|
|
50
|
+
<foreignObject x={x} y={y} width="275" height="100%">
|
|
51
|
+
<StyledGraphTooltip
|
|
29
52
|
position={TooltipPosition.top}
|
|
30
53
|
role="tooltip"
|
|
31
54
|
theme={theme}
|
|
32
55
|
>
|
|
33
|
-
<
|
|
34
|
-
|
|
56
|
+
<div>
|
|
57
|
+
<TooltipColorSwatch color={theme.iterableColors[index]} />
|
|
58
|
+
<span>{datum.label}</span>
|
|
59
|
+
</div>
|
|
35
60
|
<TooltipArrow theme={theme} />
|
|
36
|
-
</
|
|
61
|
+
</StyledGraphTooltip>
|
|
37
62
|
</foreignObject>
|
|
38
63
|
</g>
|
|
39
|
-
);
|
|
64
|
+
) : null;
|
|
40
65
|
};
|
|
41
66
|
|
|
42
|
-
export const AxisTooltip = props => {
|
|
43
|
-
const { x, y, activePoints } = props;
|
|
67
|
+
export const AxisTooltip = (props: any) => {
|
|
68
|
+
const { x, y, activePoints, hiddenData, dataLength } = props;
|
|
69
|
+
|
|
70
|
+
const pointsIndexes = Array.from(
|
|
71
|
+
Array(dataLength - 0),
|
|
72
|
+
(_, i) => i + 0
|
|
73
|
+
).filter(i => !hiddenData.includes(i));
|
|
44
74
|
|
|
45
|
-
const theme = React.useContext(ThemeContext);
|
|
75
|
+
const theme: ThemeInterface = React.useContext(ThemeContext);
|
|
46
76
|
|
|
47
77
|
return (
|
|
48
78
|
<g style={{ pointerEvents: 'none' }}>
|
|
49
|
-
<foreignObject x={x} y={y} width="
|
|
50
|
-
<
|
|
79
|
+
<foreignObject x={x} y={y} width="275" height="100%">
|
|
80
|
+
<StyledGraphTooltip
|
|
51
81
|
data-testid="axis-tooltip"
|
|
52
82
|
position={TooltipPosition.top}
|
|
53
83
|
role="tooltip"
|
|
54
84
|
theme={theme}
|
|
55
85
|
>
|
|
56
|
-
{activePoints.map((point, i) => (
|
|
57
|
-
<div key={i}
|
|
58
|
-
<TooltipColorSwatch
|
|
86
|
+
{activePoints.map((point: any, i: number) => (
|
|
87
|
+
<div key={i}>
|
|
88
|
+
<TooltipColorSwatch
|
|
89
|
+
color={theme.iterableColors[pointsIndexes[i]]}
|
|
90
|
+
/>
|
|
59
91
|
<span>{point.label}</span>
|
|
60
92
|
</div>
|
|
61
93
|
))}
|
|
62
94
|
<TooltipArrow theme={theme} />
|
|
63
|
-
</
|
|
95
|
+
</StyledGraphTooltip>
|
|
64
96
|
</foreignObject>
|
|
65
97
|
</g>
|
|
66
98
|
);
|