@takaro/lib-components 0.4.8 → 0.4.10
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/package.json +1 -1
- package/src/components/actions/Button/__snapshots__/Button.test.tsx.snap +1 -1
- package/src/components/actions/IconButton/__snapshots__/IconButton.test.tsx.snap +1 -1
- package/src/components/charts/AreaChart/AreaChart.stories.tsx +11 -7
- package/src/components/charts/AreaChart/index.tsx +114 -63
- package/src/components/charts/BarChart/BarChart.stories.tsx +33 -10
- package/src/components/charts/BarChart/index.tsx +280 -147
- package/src/components/charts/EmptyChart.tsx +45 -0
- package/src/components/charts/GeoMercator/GeoMercator.stories.tsx +15 -9
- package/src/components/charts/GeoMercator/index.tsx +15 -172
- package/src/components/charts/Heatmap/Heatmap.stories.tsx +167 -33
- package/src/components/charts/Heatmap/index.tsx +427 -193
- package/src/components/charts/LineChart/LineChart.stories.tsx +77 -3
- package/src/components/charts/LineChart/index.tsx +200 -79
- package/src/components/charts/PieChart/PieChart.stories.tsx +128 -20
- package/src/components/charts/PieChart/index.tsx +353 -59
- package/src/components/charts/PointHighlight.tsx +2 -2
- package/src/components/charts/RadarChart/RadarChart.stories.tsx +14 -5
- package/src/components/charts/RadarChart/index.tsx +94 -45
- package/src/components/charts/RadialBarChart/RadialBarChart.stories.tsx +26 -1
- package/src/components/charts/RadialBarChart/index.tsx +100 -34
- package/src/components/charts/RadialLineChart/RadialLineChart.stories.tsx +19 -2
- package/src/components/charts/RadialLineChart/index.tsx +116 -26
- package/src/components/charts/index.tsx +0 -26
- package/src/components/charts/util.ts +50 -12
- package/src/components/data/CountryList/index.tsx +146 -0
- package/src/components/data/Stats/Sparkline.tsx +48 -0
- package/src/components/data/Stats/Stat.tsx +15 -4
- package/src/components/data/Stats/context.tsx +1 -1
- package/src/components/data/Stats/index.tsx +8 -3
- package/src/components/data/index.ts +3 -0
- package/src/components/feedback/IconTooltip/index.tsx +9 -6
- package/src/components/feedback/ProgressBar/ProgressBar.stories.tsx +13 -14
- package/src/components/feedback/ProgressBar/index.tsx +1 -1
- package/src/components/inputs/DurationField/__tests__/Generic.test.tsx +12 -0
- package/src/components/visual/Card/CardTitle.tsx +7 -1
- package/src/components/visual/Card/index.tsx +0 -4
- package/src/helpers/formatNumber.ts +6 -0
- package/src/helpers/index.ts +1 -0
- package/src/components/charts/echarts/EChartsArea.stories.tsx +0 -139
- package/src/components/charts/echarts/EChartsArea.tsx +0 -139
- package/src/components/charts/echarts/EChartsBar.stories.tsx +0 -141
- package/src/components/charts/echarts/EChartsBar.tsx +0 -133
- package/src/components/charts/echarts/EChartsBase.tsx +0 -264
- package/src/components/charts/echarts/EChartsFunnel.stories.tsx +0 -164
- package/src/components/charts/echarts/EChartsFunnel.tsx +0 -114
- package/src/components/charts/echarts/EChartsHeatmap.stories.tsx +0 -168
- package/src/components/charts/echarts/EChartsHeatmap.tsx +0 -141
- package/src/components/charts/echarts/EChartsLine.stories.tsx +0 -132
- package/src/components/charts/echarts/EChartsLine.tsx +0 -111
- package/src/components/charts/echarts/EChartsPie.stories.tsx +0 -131
- package/src/components/charts/echarts/EChartsPie.tsx +0 -124
- package/src/components/charts/echarts/EChartsRadialBar.stories.tsx +0 -124
- package/src/components/charts/echarts/EChartsRadialBar.tsx +0 -118
- package/src/components/charts/echarts/EChartsScatter.stories.tsx +0 -166
- package/src/components/charts/echarts/EChartsScatter.tsx +0 -135
- package/src/components/charts/echarts/index.ts +0 -26
|
@@ -2,53 +2,59 @@ import { MouseEvent, useCallback } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { ParentSize } from '@visx/responsive';
|
|
4
4
|
import { Group } from '@visx/group';
|
|
5
|
-
import {
|
|
5
|
+
import { LineRadial } from '@visx/shape';
|
|
6
6
|
import { scaleLinear } from '@visx/scale';
|
|
7
7
|
import { useTooltipInPortal, useTooltip } from '@visx/tooltip';
|
|
8
|
-
import { Point } from '@visx/point';
|
|
9
8
|
import { localPoint } from '@visx/event';
|
|
10
9
|
import { Text } from '@visx/text';
|
|
10
|
+
import { motion } from 'framer-motion';
|
|
11
11
|
|
|
12
|
-
import { getDefaultTooltipStyles, InnerChartProps,
|
|
12
|
+
import { getDefaultTooltipStyles, InnerChartProps, TooltipConfig, ChartProps } from '../util';
|
|
13
13
|
import { genAngles, genPoints, genPolygonPoints } from './generators';
|
|
14
14
|
import { useTheme } from '../../../hooks';
|
|
15
|
+
import { EmptyChart } from '../EmptyChart';
|
|
15
16
|
|
|
16
|
-
export interface RadarChartProps<T> {
|
|
17
|
-
name: string;
|
|
17
|
+
export interface RadarChartProps<T> extends Exclude<ChartProps, 'grid'> {
|
|
18
18
|
data: T[];
|
|
19
|
-
margin?: Margin;
|
|
20
19
|
xAccessor: (d: T) => string;
|
|
21
20
|
yAccessor: (d: T) => number;
|
|
22
|
-
tooltipAccessor: (d: T) => string;
|
|
23
21
|
levels?: number;
|
|
22
|
+
/** Tooltip configuration */
|
|
23
|
+
tooltip?: TooltipConfig<T>;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const defaultMargin = { top:
|
|
26
|
+
const defaultMargin = { top: 40, right: 40, bottom: 40, left: 40 };
|
|
27
27
|
export const RadarChart = <T,>({
|
|
28
28
|
data,
|
|
29
29
|
xAccessor,
|
|
30
30
|
yAccessor,
|
|
31
|
-
tooltipAccessor,
|
|
32
31
|
name,
|
|
33
32
|
levels = 5,
|
|
34
33
|
margin = defaultMargin,
|
|
34
|
+
animate = true,
|
|
35
|
+
tooltip,
|
|
35
36
|
}: RadarChartProps<T>) => {
|
|
37
|
+
const hasData = data && data.length > 0;
|
|
38
|
+
|
|
36
39
|
return (
|
|
37
40
|
<>
|
|
38
41
|
<ParentSize>
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
{hasData
|
|
43
|
+
? (parent) => (
|
|
44
|
+
<Chart<T>
|
|
45
|
+
name={name}
|
|
46
|
+
data={data}
|
|
47
|
+
width={parent.width}
|
|
48
|
+
height={parent.height}
|
|
49
|
+
margin={margin}
|
|
50
|
+
xAccessor={xAccessor}
|
|
51
|
+
yAccessor={yAccessor}
|
|
52
|
+
levels={levels}
|
|
53
|
+
tooltip={tooltip}
|
|
54
|
+
animate={animate}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
: () => <EmptyChart />}
|
|
52
58
|
</ParentSize>
|
|
53
59
|
</>
|
|
54
60
|
);
|
|
@@ -65,7 +71,8 @@ const Chart = <T,>({
|
|
|
65
71
|
xAccessor,
|
|
66
72
|
height,
|
|
67
73
|
margin = defaultMargin,
|
|
68
|
-
|
|
74
|
+
tooltip,
|
|
75
|
+
animate = true,
|
|
69
76
|
}: InnerRadarChartProps<T>) => {
|
|
70
77
|
const theme = useTheme();
|
|
71
78
|
|
|
@@ -79,6 +86,9 @@ const Chart = <T,>({
|
|
|
79
86
|
const innerHeight = height - margin.top - margin.bottom;
|
|
80
87
|
const radius = Math.min(innerWidth, innerHeight) / 2;
|
|
81
88
|
|
|
89
|
+
// Scale dot size based on chart size (5px for ~400px charts, minimum 3px, maximum 8px)
|
|
90
|
+
const dotRadius = Math.max(3, Math.min(8, radius / 40));
|
|
91
|
+
|
|
82
92
|
const radialScale = scaleLinear<number>({
|
|
83
93
|
domain: [360, 0],
|
|
84
94
|
range: [0, Math.PI * 2],
|
|
@@ -96,37 +106,72 @@ const Chart = <T,>({
|
|
|
96
106
|
showTooltip({
|
|
97
107
|
tooltipLeft: coords?.x,
|
|
98
108
|
tooltipTop: coords?.y,
|
|
99
|
-
tooltipData:
|
|
109
|
+
tooltipData: tooltip?.accessor && tooltip.accessor(data),
|
|
100
110
|
});
|
|
101
111
|
},
|
|
102
|
-
[data,
|
|
112
|
+
[data, tooltip?.accessor],
|
|
103
113
|
);
|
|
104
114
|
|
|
105
115
|
const webs = genAngles(data.length);
|
|
106
116
|
const points = genPoints(data.length, radius);
|
|
107
117
|
const polygonPoints = genPolygonPoints(data, (d) => yScale(d) ?? 0, yAccessor);
|
|
108
|
-
const zeroPoint = new Point({ x: 0, y: 0 });
|
|
109
118
|
|
|
110
119
|
return width < 10 ? null : (
|
|
111
120
|
<svg ref={containerRef} width={width} height={height}>
|
|
112
121
|
<rect fill={theme.colors.background} width={width} height={height} rx={14} />
|
|
113
|
-
<Group top={height / 2
|
|
122
|
+
<Group top={height / 2} left={width / 2}>
|
|
114
123
|
{[...new Array(levels)].map((_, i) => (
|
|
115
124
|
<LineRadial
|
|
116
125
|
key={`web-${i}`}
|
|
117
126
|
data={webs}
|
|
118
127
|
angle={(d) => radialScale(d.angle) ?? 0}
|
|
119
128
|
radius={((i + 1) * radius) / levels}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
>
|
|
130
|
+
{({ path }) => {
|
|
131
|
+
const d = path(webs) || '';
|
|
132
|
+
return (
|
|
133
|
+
<motion.path
|
|
134
|
+
d={d}
|
|
135
|
+
fill="none"
|
|
136
|
+
stroke={theme.colors.backgroundAccent}
|
|
137
|
+
strokeWidth={2}
|
|
138
|
+
strokeOpacity={0.8}
|
|
139
|
+
strokeLinecap="round"
|
|
140
|
+
initial={animate ? { pathLength: 0, opacity: 0 } : { pathLength: 1, opacity: 0.8 }}
|
|
141
|
+
animate={{ pathLength: 1, opacity: 0.8 }}
|
|
142
|
+
transition={
|
|
143
|
+
animate
|
|
144
|
+
? {
|
|
145
|
+
duration: 0.6,
|
|
146
|
+
delay: i * 0.1,
|
|
147
|
+
ease: 'easeOut',
|
|
148
|
+
}
|
|
149
|
+
: { duration: 0 }
|
|
150
|
+
}
|
|
151
|
+
/>
|
|
152
|
+
);
|
|
153
|
+
}}
|
|
154
|
+
</LineRadial>
|
|
126
155
|
))}
|
|
127
156
|
{[...new Array(data.length)].map((_, i) => (
|
|
128
157
|
<>
|
|
129
|
-
<
|
|
158
|
+
<motion.line
|
|
159
|
+
key={`radar-line-${i}`}
|
|
160
|
+
x1={0}
|
|
161
|
+
y1={0}
|
|
162
|
+
stroke={theme.colors.backgroundAccent}
|
|
163
|
+
initial={animate ? { x2: 0, y2: 0 } : { x2: points[i].x, y2: points[i].y }}
|
|
164
|
+
animate={{ x2: points[i].x, y2: points[i].y }}
|
|
165
|
+
transition={
|
|
166
|
+
animate
|
|
167
|
+
? {
|
|
168
|
+
duration: 0.5,
|
|
169
|
+
delay: i * 0.05,
|
|
170
|
+
ease: 'easeOut',
|
|
171
|
+
}
|
|
172
|
+
: { duration: 0 }
|
|
173
|
+
}
|
|
174
|
+
/>
|
|
130
175
|
<Text
|
|
131
176
|
textAnchor="middle"
|
|
132
177
|
verticalAnchor="middle"
|
|
@@ -143,21 +188,25 @@ const Chart = <T,>({
|
|
|
143
188
|
<polygon
|
|
144
189
|
points={polygonPoints.pointString}
|
|
145
190
|
fill={theme.colors.primary}
|
|
146
|
-
fillOpacity={0.
|
|
191
|
+
fillOpacity={0.5}
|
|
147
192
|
stroke={theme.colors.primary}
|
|
148
193
|
strokeWidth={2}
|
|
149
194
|
/>
|
|
150
195
|
{polygonPoints.points.map((point, i) => (
|
|
151
|
-
<
|
|
152
|
-
|
|
153
|
-
cx={point.x}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
196
|
+
<g key={`radar-point-${i}`}>
|
|
197
|
+
{/* Visible dot */}
|
|
198
|
+
<circle cx={point.x} cy={point.y} r={dotRadius} fill={theme.colors.primary} />
|
|
199
|
+
{/* Invisible larger hit area for tooltip */}
|
|
200
|
+
<circle
|
|
201
|
+
cx={point.x}
|
|
202
|
+
cy={point.y}
|
|
203
|
+
r={dotRadius * 3}
|
|
204
|
+
fill="transparent"
|
|
205
|
+
style={{ cursor: 'pointer' }}
|
|
206
|
+
onMouseOut={hideTooltip}
|
|
207
|
+
onMouseOver={(e) => handleMouseOver(e, data[i])}
|
|
208
|
+
/>
|
|
209
|
+
</g>
|
|
161
210
|
))}
|
|
162
211
|
</Group>
|
|
163
212
|
{tooltipOpen && tooltipData && (
|
|
@@ -27,7 +27,32 @@ export const Default: StoryFn<RadialBarChartProps<LetterFrequency>> = () => {
|
|
|
27
27
|
xAccessor={getLetter}
|
|
28
28
|
yAccessor={getLetterFrequency}
|
|
29
29
|
data={data}
|
|
30
|
-
|
|
30
|
+
tooltip={{
|
|
31
|
+
accessor: (d) => `Tooltip content for '${d.frequency}'`,
|
|
32
|
+
}}
|
|
33
|
+
animate={true}
|
|
34
|
+
/>
|
|
35
|
+
</Wrapper>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const WithoutAnimation: StoryFn<RadialBarChartProps<LetterFrequency>> = () => {
|
|
40
|
+
const getLetter = (d: LetterFrequency) => d.letter;
|
|
41
|
+
const getLetterFrequency = (d: LetterFrequency) => Number(d.frequency) * 100;
|
|
42
|
+
const alphabeticalSort = (a: LetterFrequency, b: LetterFrequency) => a.letter.localeCompare(b.letter);
|
|
43
|
+
const data = letterFrequency.sort(alphabeticalSort);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Wrapper>
|
|
47
|
+
<RadialBarChart<LetterFrequency>
|
|
48
|
+
name="LetterFrequency"
|
|
49
|
+
xAccessor={getLetter}
|
|
50
|
+
yAccessor={getLetterFrequency}
|
|
51
|
+
data={data}
|
|
52
|
+
tooltip={{
|
|
53
|
+
accessor: (d) => `Tooltip content for '${d.frequency}'`,
|
|
54
|
+
}}
|
|
55
|
+
animate={false}
|
|
31
56
|
/>
|
|
32
57
|
</Wrapper>
|
|
33
58
|
);
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import { MouseEvent, useCallback } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { arc } from '@visx/shape';
|
|
3
3
|
import { Group } from '@visx/group';
|
|
4
4
|
import { scaleBand, scaleRadial } from '@visx/scale';
|
|
5
|
-
import { Text } from '@visx/text';
|
|
6
5
|
import { shade } from 'polished';
|
|
6
|
+
import { motion } from 'framer-motion';
|
|
7
7
|
|
|
8
|
-
import { Margin, InnerChartProps, getDefaultTooltipStyles } from '../util';
|
|
8
|
+
import { Margin, InnerChartProps, getDefaultTooltipStyles, TooltipConfig } from '../util';
|
|
9
9
|
import { useTheme } from '../../../hooks';
|
|
10
10
|
import { ParentSize } from '@visx/responsive';
|
|
11
11
|
import { useTooltip, useTooltipInPortal } from '@visx/tooltip';
|
|
12
12
|
import localPoint from '@visx/event/lib/localPointGeneric';
|
|
13
13
|
import { useGradients } from '../useGradients';
|
|
14
|
+
import { EmptyChart } from '../EmptyChart';
|
|
14
15
|
|
|
15
|
-
const defaultMargin = { top:
|
|
16
|
+
const defaultMargin = { top: 20, right: 20, bottom: 20, left: 20 };
|
|
16
17
|
export interface RadialBarChartProps<T> {
|
|
17
18
|
name: string;
|
|
18
19
|
data: T[];
|
|
19
20
|
margin?: Margin;
|
|
20
21
|
xAccessor: (d: T) => string;
|
|
21
22
|
yAccessor: (d: T) => number;
|
|
22
|
-
|
|
23
|
+
tooltip?: TooltipConfig<T>;
|
|
24
|
+
animate?: boolean;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export const RadialBarChart = <T,>({
|
|
@@ -27,24 +29,30 @@ export const RadialBarChart = <T,>({
|
|
|
27
29
|
data,
|
|
28
30
|
margin,
|
|
29
31
|
yAccessor,
|
|
30
|
-
|
|
32
|
+
tooltip,
|
|
31
33
|
name,
|
|
34
|
+
animate = true,
|
|
32
35
|
}: RadialBarChartProps<T>) => {
|
|
36
|
+
const hasData = data.length > 0;
|
|
37
|
+
|
|
33
38
|
return (
|
|
34
39
|
<>
|
|
35
40
|
<ParentSize>
|
|
36
|
-
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
{hasData
|
|
42
|
+
? (parent) => (
|
|
43
|
+
<Chart<T>
|
|
44
|
+
name={name}
|
|
45
|
+
data={data}
|
|
46
|
+
width={parent.width}
|
|
47
|
+
height={parent.height}
|
|
48
|
+
margin={margin}
|
|
49
|
+
yAccessor={yAccessor}
|
|
50
|
+
xAccessor={xAccessor}
|
|
51
|
+
tooltip={tooltip}
|
|
52
|
+
animate={animate}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
: () => <EmptyChart />}
|
|
48
56
|
</ParentSize>
|
|
49
57
|
</>
|
|
50
58
|
);
|
|
@@ -58,14 +66,18 @@ const Chart = <T,>({
|
|
|
58
66
|
height,
|
|
59
67
|
xAccessor,
|
|
60
68
|
yAccessor,
|
|
61
|
-
|
|
69
|
+
tooltip,
|
|
62
70
|
data,
|
|
63
71
|
margin = defaultMargin,
|
|
72
|
+
animate = true,
|
|
64
73
|
}: InnerRadialBarChartProps<T>) => {
|
|
65
74
|
const toDegrees = (x: number) => (x * 180) / Math.PI;
|
|
66
75
|
const theme = useTheme();
|
|
67
76
|
const gradients = useGradients(name);
|
|
68
77
|
|
|
78
|
+
const tooltipAccessor = tooltip?.accessor;
|
|
79
|
+
const showTooltipEnabled = tooltip?.enabled ?? true;
|
|
80
|
+
|
|
69
81
|
const { tooltipData, tooltipLeft, tooltipTop, tooltipOpen, hideTooltip, showTooltip } = useTooltip<string>();
|
|
70
82
|
const { containerRef, TooltipInPortal } = useTooltipInPortal({
|
|
71
83
|
detectBounds: true,
|
|
@@ -74,6 +86,7 @@ const Chart = <T,>({
|
|
|
74
86
|
|
|
75
87
|
const handleMouseOver = useCallback(
|
|
76
88
|
(event: MouseEvent, data: T) => {
|
|
89
|
+
if (!showTooltipEnabled || !tooltipAccessor) return;
|
|
77
90
|
const target = event.target as SVGElement;
|
|
78
91
|
const coords = localPoint(target.ownerSVGElement!, event);
|
|
79
92
|
showTooltip({
|
|
@@ -82,7 +95,7 @@ const Chart = <T,>({
|
|
|
82
95
|
tooltipData: tooltipAccessor(data),
|
|
83
96
|
});
|
|
84
97
|
},
|
|
85
|
-
[data, tooltipAccessor],
|
|
98
|
+
[data, tooltipAccessor, showTooltipEnabled],
|
|
86
99
|
);
|
|
87
100
|
|
|
88
101
|
// bounds
|
|
@@ -91,6 +104,9 @@ const Chart = <T,>({
|
|
|
91
104
|
const radiusMax = Math.min(xMax, yMax) / 2;
|
|
92
105
|
const innerRadius = radiusMax / 3;
|
|
93
106
|
|
|
107
|
+
const centerX = margin.left + xMax / 2;
|
|
108
|
+
const centerY = margin.top + yMax / 2;
|
|
109
|
+
|
|
94
110
|
const xScale = scaleBand<string>({
|
|
95
111
|
range: [0, 2 * Math.PI],
|
|
96
112
|
domain: data.map(xAccessor),
|
|
@@ -105,36 +121,75 @@ const Chart = <T,>({
|
|
|
105
121
|
<svg ref={containerRef} width={width} height={height}>
|
|
106
122
|
{gradients.background.gradient}
|
|
107
123
|
<rect width={width} height={height} fill="url(#radial-bars-green)" rx={14} />
|
|
108
|
-
<Group top={
|
|
109
|
-
{data.map((d) => {
|
|
124
|
+
<Group top={centerY} left={centerX}>
|
|
125
|
+
{data.map((d, index) => {
|
|
110
126
|
const xVal = xAccessor(d);
|
|
111
127
|
const startAngle = xScale(xVal) ?? 0;
|
|
112
128
|
const midAngle = startAngle + xScale.bandwidth() / 2;
|
|
113
129
|
const endAngle = startAngle + xScale.bandwidth();
|
|
114
130
|
const outerRadius = yScale(yAccessor(d)) ?? 0;
|
|
115
131
|
|
|
132
|
+
const arcGenerator = arc<{
|
|
133
|
+
innerRadius: number;
|
|
134
|
+
outerRadius: number;
|
|
135
|
+
startAngle: number;
|
|
136
|
+
endAngle: number;
|
|
137
|
+
}>({
|
|
138
|
+
cornerRadius: 3,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Generate path data for static path
|
|
142
|
+
const pathData = arcGenerator({
|
|
143
|
+
startAngle,
|
|
144
|
+
endAngle,
|
|
145
|
+
innerRadius,
|
|
146
|
+
outerRadius,
|
|
147
|
+
});
|
|
148
|
+
|
|
116
149
|
// convert polar coordinates to cartesian for drawing labels
|
|
117
150
|
const textRadius = outerRadius + 4;
|
|
118
151
|
const textX = textRadius * Math.cos(midAngle - Math.PI / 2);
|
|
119
152
|
const textY = textRadius * Math.sin(midAngle - Math.PI / 2);
|
|
120
153
|
|
|
121
154
|
return (
|
|
122
|
-
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
cornerRadius={3}
|
|
126
|
-
startAngle={startAngle}
|
|
127
|
-
endAngle={endAngle}
|
|
128
|
-
outerRadius={outerRadius}
|
|
129
|
-
innerRadius={innerRadius}
|
|
155
|
+
<g key={`bar-${xVal}`}>
|
|
156
|
+
<motion.path
|
|
157
|
+
d={pathData ?? undefined}
|
|
130
158
|
fill={shade(0.5, theme.colors.primary)}
|
|
131
159
|
stroke={theme.colors.primary}
|
|
132
160
|
onMouseOver={(e) => handleMouseOver(e, d)}
|
|
133
161
|
onMouseOut={hideTooltip}
|
|
134
162
|
onMouseLeave={hideTooltip}
|
|
135
163
|
style={{ cursor: 'pointer' }}
|
|
164
|
+
initial={
|
|
165
|
+
animate
|
|
166
|
+
? {
|
|
167
|
+
d:
|
|
168
|
+
arcGenerator({
|
|
169
|
+
startAngle,
|
|
170
|
+
endAngle,
|
|
171
|
+
innerRadius,
|
|
172
|
+
outerRadius: innerRadius,
|
|
173
|
+
}) ?? undefined,
|
|
174
|
+
}
|
|
175
|
+
: {
|
|
176
|
+
d: pathData ?? undefined,
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
animate={{
|
|
180
|
+
d: pathData ?? undefined,
|
|
181
|
+
}}
|
|
182
|
+
transition={
|
|
183
|
+
animate
|
|
184
|
+
? {
|
|
185
|
+
duration: 0.2,
|
|
186
|
+
delay: index * 0.1,
|
|
187
|
+
ease: 'easeOut',
|
|
188
|
+
}
|
|
189
|
+
: { duration: 0 }
|
|
190
|
+
}
|
|
136
191
|
/>
|
|
137
|
-
<
|
|
192
|
+
<motion.text
|
|
138
193
|
x={textX}
|
|
139
194
|
y={textY}
|
|
140
195
|
dominantBaseline="end"
|
|
@@ -142,11 +197,22 @@ const Chart = <T,>({
|
|
|
142
197
|
fontSize={theme.fontSize.small}
|
|
143
198
|
fontWeight="bold"
|
|
144
199
|
fill={theme.colors.text}
|
|
145
|
-
|
|
200
|
+
transform={`rotate(${toDegrees(midAngle)} ${textX} ${textY})`}
|
|
201
|
+
initial={animate ? { opacity: 0 } : { opacity: 1 }}
|
|
202
|
+
animate={{ opacity: 1 }}
|
|
203
|
+
transition={
|
|
204
|
+
animate
|
|
205
|
+
? {
|
|
206
|
+
duration: 0.3,
|
|
207
|
+
delay: index * 0.1 + 0.3,
|
|
208
|
+
ease: 'easeOut',
|
|
209
|
+
}
|
|
210
|
+
: { duration: 0 }
|
|
211
|
+
}
|
|
146
212
|
>
|
|
147
213
|
{xVal}
|
|
148
|
-
</
|
|
149
|
-
|
|
214
|
+
</motion.text>
|
|
215
|
+
</g>
|
|
150
216
|
);
|
|
151
217
|
})}
|
|
152
218
|
</Group>
|
|
@@ -7,6 +7,12 @@ import { styled } from '../../../styled';
|
|
|
7
7
|
export default {
|
|
8
8
|
title: 'Charts/RadialLineChart',
|
|
9
9
|
component: RadialLineChart,
|
|
10
|
+
args: {
|
|
11
|
+
animate: true,
|
|
12
|
+
},
|
|
13
|
+
argTypes: {
|
|
14
|
+
animate: { control: 'boolean' },
|
|
15
|
+
},
|
|
10
16
|
} as Meta<RadialLineChartProps<AppleStock>>;
|
|
11
17
|
|
|
12
18
|
const Wrapper = styled.div`
|
|
@@ -14,13 +20,24 @@ const Wrapper = styled.div`
|
|
|
14
20
|
width: 500px;
|
|
15
21
|
`;
|
|
16
22
|
|
|
17
|
-
export const Default: StoryFn<RadialLineChartProps<AppleStock>> = () => {
|
|
23
|
+
export const Default: StoryFn<RadialLineChartProps<AppleStock>> = (args) => {
|
|
18
24
|
const getDate = (d: AppleStock) => new Date(d.date).valueOf();
|
|
19
25
|
const getStockValue = (d: AppleStock) => d.close;
|
|
26
|
+
const tooltipAccessor = (d: AppleStock) => {
|
|
27
|
+
const date = new Date(d.date).toLocaleDateString();
|
|
28
|
+
return `Date: ${date}\nClose: $${d.close.toFixed(2)}`;
|
|
29
|
+
};
|
|
20
30
|
|
|
21
31
|
return (
|
|
22
32
|
<Wrapper>
|
|
23
|
-
<RadialLineChart<AppleStock>
|
|
33
|
+
<RadialLineChart<AppleStock>
|
|
34
|
+
{...args}
|
|
35
|
+
name="AppleStock"
|
|
36
|
+
xAccessor={getDate}
|
|
37
|
+
yAccessor={getStockValue}
|
|
38
|
+
data={appleStock}
|
|
39
|
+
tooltip={{ accessor: tooltipAccessor }}
|
|
40
|
+
/>
|
|
24
41
|
</Wrapper>
|
|
25
42
|
);
|
|
26
43
|
};
|