@coinbase/cds-mcp-server 8.21.8 → 8.22.2
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/CHANGELOG.md +12 -0
- package/mcp-docs/mobile/components/AreaChart.txt +39 -37
- package/mcp-docs/mobile/components/Avatar.txt +18 -18
- package/mcp-docs/mobile/components/AvatarButton.txt +19 -19
- package/mcp-docs/mobile/components/Banner.txt +62 -23
- package/mcp-docs/mobile/components/BarChart.txt +37 -35
- package/mcp-docs/mobile/components/Box.txt +18 -18
- package/mcp-docs/mobile/components/BrowserBar.txt +18 -18
- package/mcp-docs/mobile/components/Button.txt +19 -19
- package/mcp-docs/mobile/components/Carousel.txt +18 -18
- package/mcp-docs/mobile/components/CartesianChart.txt +75 -44
- package/mcp-docs/mobile/components/CheckboxCell.txt +19 -19
- package/mcp-docs/mobile/components/Chip.txt +20 -20
- package/mcp-docs/mobile/components/Coachmark.txt +18 -18
- package/mcp-docs/mobile/components/ContentCard.txt +18 -18
- package/mcp-docs/mobile/components/ContentCardBody.txt +18 -18
- package/mcp-docs/mobile/components/ContentCardFooter.txt +18 -18
- package/mcp-docs/mobile/components/ContentCardHeader.txt +18 -18
- package/mcp-docs/mobile/components/ContentCell.txt +18 -18
- package/mcp-docs/mobile/components/ControlGroup.txt +18 -18
- package/mcp-docs/mobile/components/DatePicker.txt +1 -1
- package/mcp-docs/mobile/components/Divider.txt +18 -18
- package/mcp-docs/mobile/components/DotCount.txt +1 -1
- package/mcp-docs/mobile/components/DotSymbol.txt +2 -2
- package/mcp-docs/mobile/components/Fallback.txt +18 -18
- package/mcp-docs/mobile/components/HStack.txt +18 -18
- package/mcp-docs/mobile/components/Icon.txt +6 -0
- package/mcp-docs/mobile/components/IconButton.txt +19 -19
- package/mcp-docs/mobile/components/InputChip.txt +20 -20
- package/mcp-docs/mobile/components/Interactable.txt +19 -19
- package/mcp-docs/mobile/components/LineChart.txt +1608 -898
- package/mcp-docs/mobile/components/Link.txt +18 -18
- package/mcp-docs/mobile/components/ListCell.txt +37 -19
- package/mcp-docs/mobile/components/Lottie.txt +18 -18
- package/mcp-docs/mobile/components/MediaChip.txt +20 -20
- package/mcp-docs/mobile/components/MultiContentModule.txt +18 -18
- package/mcp-docs/mobile/components/NavigationTitle.txt +18 -18
- package/mcp-docs/mobile/components/NavigationTitleSelect.txt +18 -18
- package/mcp-docs/mobile/components/Numpad.txt +18 -18
- package/mcp-docs/mobile/components/Overlay.txt +18 -18
- package/mcp-docs/mobile/components/PageFooter.txt +17 -17
- package/mcp-docs/mobile/components/PageHeader.txt +17 -17
- package/mcp-docs/mobile/components/PeriodSelector.txt +26 -26
- package/mcp-docs/mobile/components/Point.txt +203 -98
- package/mcp-docs/mobile/components/Pressable.txt +19 -19
- package/mcp-docs/mobile/components/ProgressBar.txt +1 -1
- package/mcp-docs/mobile/components/ProgressBarWithFixedLabels.txt +1 -1
- package/mcp-docs/mobile/components/ProgressBarWithFloatLabel.txt +1 -1
- package/mcp-docs/mobile/components/ProgressCircle.txt +1 -1
- package/mcp-docs/mobile/components/RadioCell.txt +19 -19
- package/mcp-docs/mobile/components/ReferenceLine.txt +197 -54
- package/mcp-docs/mobile/components/RollingNumber.txt +18 -18
- package/mcp-docs/mobile/components/Scrubber.txt +597 -79
- package/mcp-docs/mobile/components/SegmentedTabs.txt +18 -18
- package/mcp-docs/mobile/components/SelectAlpha.txt +1 -1
- package/mcp-docs/mobile/components/SelectChip.txt +20 -20
- package/mcp-docs/mobile/components/SlideButton.txt +19 -19
- package/mcp-docs/mobile/components/Spacer.txt +6 -6
- package/mcp-docs/mobile/components/SparklineInteractive.txt +3 -3
- package/mcp-docs/mobile/components/Spinner.txt +1 -1
- package/mcp-docs/mobile/components/Stepper.txt +18 -18
- package/mcp-docs/mobile/components/TabLabel.txt +18 -18
- package/mcp-docs/mobile/components/TabNavigation.txt +18 -18
- package/mcp-docs/mobile/components/TabbedChips.txt +18 -18
- package/mcp-docs/mobile/components/TabbedChipsAlpha.txt +1 -1
- package/mcp-docs/mobile/components/Tabs.txt +18 -18
- package/mcp-docs/mobile/components/Tag.txt +18 -18
- package/mcp-docs/mobile/components/Text.txt +18 -18
- package/mcp-docs/mobile/components/Toast.txt +18 -18
- package/mcp-docs/mobile/components/Tooltip.txt +17 -1
- package/mcp-docs/mobile/components/TopNavBar.txt +18 -18
- package/mcp-docs/mobile/components/VStack.txt +18 -18
- package/mcp-docs/mobile/components/XAxis.txt +86 -24
- package/mcp-docs/mobile/components/YAxis.txt +75 -17
- package/mcp-docs/mobile/routes.txt +1 -1
- package/mcp-docs/web/components/AreaChart.txt +523 -301
- package/mcp-docs/web/components/Avatar.txt +27 -27
- package/mcp-docs/web/components/AvatarButton.txt +28 -28
- package/mcp-docs/web/components/Banner.txt +71 -32
- package/mcp-docs/web/components/BarChart.txt +182 -313
- package/mcp-docs/web/components/Box.txt +28 -28
- package/mcp-docs/web/components/Button.txt +28 -28
- package/mcp-docs/web/components/Calendar.txt +27 -27
- package/mcp-docs/web/components/Carousel.txt +27 -27
- package/mcp-docs/web/components/CartesianChart.txt +62 -309
- package/mcp-docs/web/components/CheckboxCell.txt +25 -25
- package/mcp-docs/web/components/Chip.txt +27 -27
- package/mcp-docs/web/components/Coachmark.txt +27 -27
- package/mcp-docs/web/components/ContainedAssetCard.txt +27 -27
- package/mcp-docs/web/components/ContentCard.txt +28 -28
- package/mcp-docs/web/components/ContentCardBody.txt +28 -28
- package/mcp-docs/web/components/ContentCardFooter.txt +28 -28
- package/mcp-docs/web/components/ContentCardHeader.txt +28 -28
- package/mcp-docs/web/components/ContentCell.txt +28 -28
- package/mcp-docs/web/components/ControlGroup.txt +27 -27
- package/mcp-docs/web/components/Divider.txt +27 -27
- package/mcp-docs/web/components/Fallback.txt +28 -28
- package/mcp-docs/web/components/FloatingAssetCard.txt +27 -27
- package/mcp-docs/web/components/Grid.txt +28 -28
- package/mcp-docs/web/components/GridColumn.txt +27 -27
- package/mcp-docs/web/components/HStack.txt +28 -28
- package/mcp-docs/web/components/Icon.txt +27 -27
- package/mcp-docs/web/components/IconButton.txt +28 -28
- package/mcp-docs/web/components/InputChip.txt +27 -27
- package/mcp-docs/web/components/Interactable.txt +28 -28
- package/mcp-docs/web/components/LineChart.txt +1598 -1116
- package/mcp-docs/web/components/Link.txt +28 -28
- package/mcp-docs/web/components/ListCell.txt +48 -30
- package/mcp-docs/web/components/Lottie.txt +27 -27
- package/mcp-docs/web/components/MediaChip.txt +27 -27
- package/mcp-docs/web/components/Modal.txt +27 -27
- package/mcp-docs/web/components/ModalBody.txt +27 -27
- package/mcp-docs/web/components/ModalFooter.txt +27 -27
- package/mcp-docs/web/components/ModalHeader.txt +27 -27
- package/mcp-docs/web/components/MultiContentModule.txt +28 -28
- package/mcp-docs/web/components/NavigationBar.txt +5 -5
- package/mcp-docs/web/components/NudgeCard.txt +27 -27
- package/mcp-docs/web/components/Overlay.txt +27 -27
- package/mcp-docs/web/components/PageFooter.txt +26 -26
- package/mcp-docs/web/components/PageHeader.txt +26 -26
- package/mcp-docs/web/components/Pagination.txt +27 -27
- package/mcp-docs/web/components/PeriodSelector.txt +49 -49
- package/mcp-docs/web/components/Point.txt +228 -79
- package/mcp-docs/web/components/Pressable.txt +28 -28
- package/mcp-docs/web/components/RadioCell.txt +25 -25
- package/mcp-docs/web/components/ReferenceLine.txt +208 -60
- package/mcp-docs/web/components/RemoteImage.txt +26 -26
- package/mcp-docs/web/components/RollingNumber.txt +28 -28
- package/mcp-docs/web/components/Scrubber.txt +463 -68
- package/mcp-docs/web/components/SectionHeader.txt +27 -27
- package/mcp-docs/web/components/SegmentedTabs.txt +27 -27
- package/mcp-docs/web/components/SelectChip.txt +27 -27
- package/mcp-docs/web/components/SelectOption.txt +27 -27
- package/mcp-docs/web/components/Sidebar.txt +27 -27
- package/mcp-docs/web/components/SidebarItem.txt +27 -27
- package/mcp-docs/web/components/Spacer.txt +34 -34
- package/mcp-docs/web/components/SparklineInteractive.txt +1 -1
- package/mcp-docs/web/components/Spinner.txt +27 -27
- package/mcp-docs/web/components/Stepper.txt +27 -27
- package/mcp-docs/web/components/TabLabel.txt +27 -27
- package/mcp-docs/web/components/TabNavigation.txt +26 -26
- package/mcp-docs/web/components/TabbedChips.txt +26 -26
- package/mcp-docs/web/components/TabbedChipsAlpha.txt +1 -1
- package/mcp-docs/web/components/Tabs.txt +27 -27
- package/mcp-docs/web/components/Tag.txt +27 -27
- package/mcp-docs/web/components/Text.txt +28 -28
- package/mcp-docs/web/components/TileButton.txt +28 -28
- package/mcp-docs/web/components/Toast.txt +27 -27
- package/mcp-docs/web/components/Tooltip.txt +17 -1
- package/mcp-docs/web/components/VStack.txt +28 -28
- package/mcp-docs/web/components/XAxis.txt +86 -22
- package/mcp-docs/web/components/YAxis.txt +133 -89
- package/package.json +1 -1
|
@@ -10,405 +10,150 @@ import { LineChart } from '@coinbase/cds-web-visualization'
|
|
|
10
10
|
|
|
11
11
|
## Examples
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
LineChart is a wrapper for [CartesianChart](/components/graphs/CartesianChart) that makes it easy to create standard line charts, supporting a single x/y axis pair. Charts are built using SVGs.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
function BasicExample() {
|
|
17
|
-
const [scrubIndex, setScrubIndex] = useState(undefined);
|
|
18
|
-
const data = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58];
|
|
19
|
-
|
|
20
|
-
const accessibilityLabel = useMemo(() => {
|
|
21
|
-
if (scrubIndex === undefined) return undefined;
|
|
22
|
-
return `Value: ${data[scrubIndex]} at index ${scrubIndex}`;
|
|
23
|
-
}, [scrubIndex, data]);
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<LineChart
|
|
27
|
-
enableScrubbing
|
|
28
|
-
onScrubberPositionChange={setScrubIndex}
|
|
29
|
-
height={{ base: 150, tablet: 200, desktop: 250 }}
|
|
30
|
-
series={[
|
|
31
|
-
{
|
|
32
|
-
id: 'prices',
|
|
33
|
-
data: data,
|
|
34
|
-
},
|
|
35
|
-
]}
|
|
36
|
-
curve="monotone"
|
|
37
|
-
showYAxis
|
|
38
|
-
showArea
|
|
39
|
-
yAxis={{
|
|
40
|
-
showGrid: true,
|
|
41
|
-
}}
|
|
42
|
-
accessibilityLabel={accessibilityLabel}
|
|
43
|
-
>
|
|
44
|
-
<Scrubber />
|
|
45
|
-
</LineChart>
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
```
|
|
15
|
+
### Basics
|
|
49
16
|
|
|
50
|
-
|
|
17
|
+
The only prop required is `series`, which takes an array of series objects. Each series object needs an `id` and a `data` array of numbers.
|
|
51
18
|
|
|
52
19
|
```jsx live
|
|
53
20
|
<LineChart
|
|
54
|
-
|
|
21
|
+
showArea
|
|
22
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
55
23
|
series={[
|
|
56
24
|
{
|
|
57
25
|
id: 'prices',
|
|
58
26
|
data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58],
|
|
59
27
|
},
|
|
60
28
|
]}
|
|
61
|
-
curve="monotone"
|
|
62
29
|
/>
|
|
63
30
|
```
|
|
64
31
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
You can specify the dimensions of the chart to make it more compact.
|
|
68
|
-
|
|
69
|
-
```jsx live
|
|
70
|
-
function CompactLineChart() {
|
|
71
|
-
const dimensions = { width: 62, height: 18 };
|
|
72
|
-
|
|
73
|
-
const sparklineData = prices
|
|
74
|
-
.map((price) => parseFloat(price))
|
|
75
|
-
.filter((price, index) => index % 10 === 0);
|
|
76
|
-
const positiveFloor = Math.min(...sparklineData) - 10;
|
|
77
|
-
|
|
78
|
-
const negativeData = sparklineData.map((price) => -1 * price).reverse();
|
|
79
|
-
const negativeCeiling = Math.max(...negativeData) + 10;
|
|
80
|
-
|
|
81
|
-
const formatPrice = useCallback((price: number) => {
|
|
82
|
-
return `$${price.toLocaleString('en-US', {
|
|
83
|
-
minimumFractionDigits: 2,
|
|
84
|
-
maximumFractionDigits: 2,
|
|
85
|
-
})}`;
|
|
86
|
-
}, []);
|
|
87
|
-
|
|
88
|
-
const CompactChart = memo(({ data, showArea, color, referenceY }) => (
|
|
89
|
-
<Box style={{ padding: 1 }}>
|
|
90
|
-
<LineChart
|
|
91
|
-
{...dimensions}
|
|
92
|
-
enableScrubbing={false}
|
|
93
|
-
overflow="visible"
|
|
94
|
-
inset={0}
|
|
95
|
-
showArea={showArea}
|
|
96
|
-
series={[
|
|
97
|
-
{
|
|
98
|
-
id: 'btc',
|
|
99
|
-
data,
|
|
100
|
-
color,
|
|
101
|
-
},
|
|
102
|
-
]}
|
|
103
|
-
>
|
|
104
|
-
<ReferenceLine dataY={referenceY} />
|
|
105
|
-
</LineChart>
|
|
106
|
-
</Box>
|
|
107
|
-
));
|
|
108
|
-
|
|
109
|
-
const ChartCell = memo(({ data, showArea, color, referenceY, subdetail, variant }) => {
|
|
110
|
-
const { isPhone } = useBreakpoints();
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<ListCell
|
|
114
|
-
spacingVariant="condensed"
|
|
115
|
-
description={isPhone ? undefined : assets.btc.symbol}
|
|
116
|
-
detail={formatPrice(parseFloat(prices[0]))}
|
|
117
|
-
intermediary={
|
|
118
|
-
<CompactChart data={data} showArea={showArea} color={color} referenceY={referenceY} />
|
|
119
|
-
}
|
|
120
|
-
media={<Avatar src={assets.btc.imageUrl} />}
|
|
121
|
-
onClick={() => console.log('clicked')}
|
|
122
|
-
subdetail={subdetail}
|
|
123
|
-
title={isPhone ? undefined : assets.btc.name}
|
|
124
|
-
variant={variant}
|
|
125
|
-
style={{ padding: 0 }}
|
|
126
|
-
/>
|
|
127
|
-
);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<VStack>
|
|
132
|
-
<ChartCell
|
|
133
|
-
data={sparklineData}
|
|
134
|
-
color={assets.btc.color}
|
|
135
|
-
referenceY={parseFloat(prices[Math.floor(prices.length / 4)])}
|
|
136
|
-
subdetail="-4.55%"
|
|
137
|
-
variant="negative"
|
|
138
|
-
/>
|
|
139
|
-
<ChartCell
|
|
140
|
-
data={sparklineData}
|
|
141
|
-
showArea
|
|
142
|
-
color={assets.btc.color}
|
|
143
|
-
referenceY={parseFloat(prices[Math.floor(prices.length / 4)])}
|
|
144
|
-
subdetail="-4.55%"
|
|
145
|
-
variant="negative"
|
|
146
|
-
/>
|
|
147
|
-
<ChartCell
|
|
148
|
-
data={sparklineData}
|
|
149
|
-
showArea
|
|
150
|
-
color="var(--color-fgPositive)"
|
|
151
|
-
referenceY={positiveFloor}
|
|
152
|
-
subdetail="+0.25%"
|
|
153
|
-
variant="positive"
|
|
154
|
-
/>
|
|
155
|
-
<ChartCell
|
|
156
|
-
data={negativeData}
|
|
157
|
-
showArea
|
|
158
|
-
color="var(--color-fgNegative)"
|
|
159
|
-
referenceY={negativeCeiling}
|
|
160
|
-
subdetail="-4.55%"
|
|
161
|
-
variant="negative"
|
|
162
|
-
/>
|
|
163
|
-
</VStack>
|
|
164
|
-
);
|
|
165
|
-
};
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Gain/Loss
|
|
169
|
-
|
|
170
|
-
You can use the y-axis scale and a [linearGradient](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/linearGradient) to create a gain/loss chart.
|
|
32
|
+
LineChart also supports multiple lines, interaction, and axes.
|
|
33
|
+
Other props, such as `areaType` can be applied to the chart as a whole or per series.
|
|
171
34
|
|
|
172
35
|
```jsx live
|
|
173
|
-
function
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
const data = [-40, -28, -21, -5, 48, -5, -28, 2, -29, -46, 16, -30, -29, 8];
|
|
177
|
-
|
|
178
|
-
const priceFormatter = useCallback(
|
|
179
|
-
(value) =>
|
|
180
|
-
new Intl.NumberFormat('en-US', {
|
|
181
|
-
style: 'currency',
|
|
182
|
-
currency: 'USD',
|
|
183
|
-
maximumFractionDigits: 0,
|
|
184
|
-
}).format(value),
|
|
36
|
+
function MultipleLine() {
|
|
37
|
+
const pages = useMemo(
|
|
38
|
+
() => ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'],
|
|
185
39
|
[],
|
|
186
40
|
);
|
|
41
|
+
const pageViews = useMemo(() => [2400, 1398, 9800, 3908, 4800, 3800, 4300], []);
|
|
42
|
+
const uniqueVisitors = useMemo(() => [4000, 3000, 2000, 2780, 1890, 2390, 3490], []);
|
|
187
43
|
|
|
188
|
-
const
|
|
189
|
-
const { getYScale } = useCartesianChartContext();
|
|
190
|
-
// get the default y-axis scale
|
|
191
|
-
const yScale = getYScale();
|
|
192
|
-
|
|
193
|
-
if (yScale) {
|
|
194
|
-
const domain = yScale.domain();
|
|
195
|
-
const range = yScale.range();
|
|
44
|
+
const chartAccessibilityLabel = `Website visitors across ${pageViews.length} pages.`;
|
|
196
45
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return (
|
|
203
|
-
<defs>
|
|
204
|
-
<linearGradient
|
|
205
|
-
gradientUnits="userSpaceOnUse"
|
|
206
|
-
id={`${gradientId}-solid`}
|
|
207
|
-
x1="0%"
|
|
208
|
-
x2="0%"
|
|
209
|
-
y1={range[0]}
|
|
210
|
-
y2={range[1]}
|
|
211
|
-
>
|
|
212
|
-
<stop offset="0%" stopColor={negativeColor} />
|
|
213
|
-
<stop offset={`${baselinePercentage}%`} stopColor={negativeColor} />
|
|
214
|
-
<stop offset={`${baselinePercentage}%`} stopColor={positiveColor} />
|
|
215
|
-
<stop offset="100%" stopColor={positiveColor} />
|
|
216
|
-
</linearGradient>
|
|
217
|
-
<linearGradient
|
|
218
|
-
gradientUnits="userSpaceOnUse"
|
|
219
|
-
id={`${gradientId}-gradient`}
|
|
220
|
-
x1="0%"
|
|
221
|
-
x2="0%"
|
|
222
|
-
y1={range[0]}
|
|
223
|
-
y2={range[1]}
|
|
224
|
-
>
|
|
225
|
-
<stop offset="0%" stopColor={negativeColor} stopOpacity={0.3} />
|
|
226
|
-
<stop offset={`${baselinePercentage}%`} stopColor={negativeColor} stopOpacity={0} />
|
|
227
|
-
<stop offset={`${baselinePercentage}%`} stopColor={positiveColor} stopOpacity={0} />
|
|
228
|
-
<stop offset="100%" stopColor={positiveColor} stopOpacity={0.3} />
|
|
229
|
-
</linearGradient>
|
|
230
|
-
</defs>
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return null;
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
const solidColor = `url(#${gradientId}-solid)`;
|
|
238
|
-
|
|
239
|
-
return (
|
|
240
|
-
<CartesianChart
|
|
241
|
-
enableScrubbing
|
|
242
|
-
height={{ base: 150, tablet: 200, desktop: 250 }}
|
|
243
|
-
series={[
|
|
244
|
-
{
|
|
245
|
-
id: 'prices',
|
|
246
|
-
data: data,
|
|
247
|
-
color: solidColor,
|
|
248
|
-
},
|
|
249
|
-
]}
|
|
250
|
-
padding={{ top: 1.5, bottom: 1.5, left: 2, right: 0 }}
|
|
251
|
-
>
|
|
252
|
-
<ChartDefs />
|
|
253
|
-
<YAxis requestedTickCount={2} showGrid tickLabelFormatter={priceFormatter} />
|
|
254
|
-
<Area seriesId="prices" curve="monotone" fill={`url(#${gradientId}-gradient)`} />
|
|
255
|
-
<Line strokeWidth={3} curve="monotone" seriesId="prices" stroke={solidColor} />
|
|
256
|
-
<Scrubber hideOverlay />
|
|
257
|
-
</CartesianChart>
|
|
46
|
+
const scrubberAccessibilityLabel = useCallback(
|
|
47
|
+
(index: number) => {
|
|
48
|
+
return `${pages[index]} has ${pageViews[index]} views and ${uniqueVisitors[index]} unique visitors.`;
|
|
49
|
+
},
|
|
50
|
+
[pages, pageViews, uniqueVisitors],
|
|
258
51
|
);
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Multiple Series
|
|
263
|
-
|
|
264
|
-
You can add multiple series to a line chart.
|
|
265
|
-
|
|
266
|
-
```jsx live
|
|
267
|
-
function MultipleSeriesChart() {
|
|
268
|
-
const [scrubIndex, setScrubIndex] = useState(undefined);
|
|
269
52
|
|
|
270
|
-
const
|
|
271
|
-
|
|
53
|
+
const numberFormatter = useCallback(
|
|
54
|
+
(value: number) => new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(value),
|
|
55
|
+
[],
|
|
56
|
+
);
|
|
272
57
|
|
|
273
58
|
return (
|
|
274
59
|
<LineChart
|
|
275
60
|
enableScrubbing
|
|
276
|
-
|
|
61
|
+
showArea
|
|
62
|
+
showXAxis
|
|
63
|
+
showYAxis
|
|
64
|
+
accessibilityLabel={chartAccessibilityLabel}
|
|
65
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
277
66
|
series={[
|
|
278
67
|
{
|
|
279
|
-
id: '
|
|
280
|
-
data:
|
|
281
|
-
|
|
282
|
-
|
|
68
|
+
id: 'pageViews',
|
|
69
|
+
data: pageViews,
|
|
70
|
+
color: 'var(--color-accentBoldGreen)',
|
|
71
|
+
// Label will render next to scrubber beacon
|
|
72
|
+
label: 'Page Views',
|
|
283
73
|
},
|
|
284
74
|
{
|
|
285
|
-
id: '
|
|
286
|
-
data:
|
|
287
|
-
|
|
288
|
-
|
|
75
|
+
id: 'uniqueVisitors',
|
|
76
|
+
data: uniqueVisitors,
|
|
77
|
+
color: 'var(--color-accentBoldPurple)',
|
|
78
|
+
label: 'Unique Visitors',
|
|
79
|
+
// Default area is gradient
|
|
80
|
+
areaType: 'dotted',
|
|
289
81
|
},
|
|
290
82
|
]}
|
|
291
|
-
|
|
83
|
+
xAxis={{
|
|
84
|
+
// Used on the x-axis to provide context for each index from the series data array
|
|
85
|
+
data: pages,
|
|
86
|
+
}}
|
|
292
87
|
yAxis={{
|
|
293
|
-
domain: {
|
|
294
|
-
min: 0,
|
|
295
|
-
},
|
|
296
88
|
showGrid: true,
|
|
89
|
+
tickLabelFormatter: numberFormatter,
|
|
297
90
|
}}
|
|
298
|
-
curve="monotone"
|
|
299
91
|
>
|
|
300
|
-
<Scrubber />
|
|
92
|
+
<Scrubber accessibilityLabel={scrubberAccessibilityLabel} />
|
|
301
93
|
</LineChart>
|
|
302
94
|
);
|
|
303
95
|
}
|
|
304
96
|
```
|
|
305
97
|
|
|
306
|
-
###
|
|
98
|
+
### Data
|
|
307
99
|
|
|
308
|
-
You can
|
|
100
|
+
The data array for each series defines the y values for that series. You can adjust the y values for a series of data by setting the `data` prop on the xAxis.
|
|
309
101
|
|
|
310
102
|
```jsx live
|
|
311
|
-
function
|
|
312
|
-
const
|
|
313
|
-
const
|
|
103
|
+
function DataFormat() {
|
|
104
|
+
const yData = useMemo(() => [2, 5.5, 2, 8.5, 1.5, 5], []);
|
|
105
|
+
const xData = useMemo(() => [1, 2, 3, 5, 8, 10], []);
|
|
106
|
+
|
|
107
|
+
const chartAccessibilityLabel = `Chart with custom X and Y data. ${yData.length} data points`;
|
|
108
|
+
|
|
109
|
+
const scrubberAccessibilityLabel = useCallback(
|
|
110
|
+
(index: number) => {
|
|
111
|
+
return `Point ${index + 1}: X value ${xData[index]}, Y value ${yData[index]}`;
|
|
112
|
+
},
|
|
113
|
+
[xData, yData],
|
|
114
|
+
);
|
|
314
115
|
|
|
315
116
|
return (
|
|
316
|
-
<
|
|
317
|
-
|
|
117
|
+
<LineChart
|
|
118
|
+
enableScrubbing
|
|
119
|
+
showArea
|
|
120
|
+
showXAxis
|
|
121
|
+
showYAxis
|
|
122
|
+
accessibilityLabel={chartAccessibilityLabel}
|
|
123
|
+
curve="natural"
|
|
124
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
125
|
+
inset={{ top: 16, right: 16, bottom: 0, left: 0 }}
|
|
126
|
+
points
|
|
318
127
|
series={[
|
|
319
128
|
{
|
|
320
|
-
id: '
|
|
321
|
-
data:
|
|
129
|
+
id: 'line',
|
|
130
|
+
data: yData,
|
|
322
131
|
},
|
|
323
132
|
]}
|
|
133
|
+
xAxis={{ data: xData, showLine: true, showTickMarks: true, showGrid: true }}
|
|
134
|
+
yAxis={{
|
|
135
|
+
domain: { min: 0 },
|
|
136
|
+
position: 'left',
|
|
137
|
+
showLine: true,
|
|
138
|
+
showTickMarks: true,
|
|
139
|
+
showGrid: true,
|
|
140
|
+
}}
|
|
324
141
|
>
|
|
325
|
-
<
|
|
326
|
-
|
|
327
|
-
seriesId="prices"
|
|
328
|
-
renderPoints={({ dataX, dataY, ...props }) =>
|
|
329
|
-
keyMarketShiftIndices.includes(dataX)
|
|
330
|
-
? {
|
|
331
|
-
...props,
|
|
332
|
-
strokeWidth: 2,
|
|
333
|
-
stroke: 'var(--color-bg)',
|
|
334
|
-
radius: 5,
|
|
335
|
-
onClick: () =>
|
|
336
|
-
alert(
|
|
337
|
-
`You have clicked a key market shift at position ${dataX + 1} with value ${dataY}!`,
|
|
338
|
-
),
|
|
339
|
-
accessibilityLabel: `Key market shift point at position ${dataX + 1}, value ${dataY}. Click to view details.`,
|
|
340
|
-
}
|
|
341
|
-
: false
|
|
342
|
-
}
|
|
343
|
-
curve="monotone"
|
|
344
|
-
/>
|
|
345
|
-
</CartesianChart>
|
|
142
|
+
<Scrubber hideOverlay accessibilityLabel={scrubberAccessibilityLabel} />
|
|
143
|
+
</LineChart>
|
|
346
144
|
);
|
|
347
145
|
}
|
|
348
146
|
```
|
|
349
147
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
This example shows how to use an empty state for a line chart.
|
|
353
|
-
|
|
354
|
-
```jsx live
|
|
355
|
-
<LineChart
|
|
356
|
-
series={[
|
|
357
|
-
{
|
|
358
|
-
id: 'line',
|
|
359
|
-
color: 'rgb(var(--gray50))',
|
|
360
|
-
data: [1, 1],
|
|
361
|
-
showArea: true,
|
|
362
|
-
},
|
|
363
|
-
]}
|
|
364
|
-
yAxis={{ domain: { min: -1, max: 3 } }}
|
|
365
|
-
height={{ base: 150, tablet: 200, desktop: 250 }}
|
|
366
|
-
/>
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
### Line Styles
|
|
148
|
+
#### Live Updates
|
|
370
149
|
|
|
371
|
-
|
|
372
|
-
<LineChart
|
|
373
|
-
height={{ base: 150, tablet: 200, desktop: 250 }}
|
|
374
|
-
series={[
|
|
375
|
-
{
|
|
376
|
-
id: 'top',
|
|
377
|
-
data: [15, 28, 32, 44, 46, 36, 40, 45, 48, 38],
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
id: 'upperMiddle',
|
|
381
|
-
data: [12, 23, 21, 29, 34, 28, 31, 38, 42, 35],
|
|
382
|
-
color: '#ef4444',
|
|
383
|
-
type: 'dotted',
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
id: 'lowerMiddle',
|
|
387
|
-
data: [8, 15, 14, 25, 20, 18, 22, 28, 24, 30],
|
|
388
|
-
color: '#f59e0b',
|
|
389
|
-
curve: 'natural',
|
|
390
|
-
LineComponent: (props) => (
|
|
391
|
-
<GradientLine {...props} endColor="#F7931A" startColor="#E3D74D" strokeWidth={4} />
|
|
392
|
-
),
|
|
393
|
-
},
|
|
394
|
-
{
|
|
395
|
-
id: 'bottom',
|
|
396
|
-
data: [4, 8, 11, 15, 16, 14, 16, 10, 12, 14],
|
|
397
|
-
color: '#800080',
|
|
398
|
-
curve: 'step',
|
|
399
|
-
AreaComponent: DottedArea,
|
|
400
|
-
showArea: true,
|
|
401
|
-
},
|
|
402
|
-
]}
|
|
403
|
-
/>
|
|
404
|
-
```
|
|
150
|
+
You can change the data passed in via `series` prop to update the chart.
|
|
405
151
|
|
|
406
|
-
|
|
152
|
+
You can also use the `useRef` hook to reference the scrubber and pulse it on each update.
|
|
407
153
|
|
|
408
154
|
```jsx live
|
|
409
|
-
function
|
|
410
|
-
const scrubberRef = useRef(null);
|
|
411
|
-
const [scrubIndex, setScrubIndex] = useState(undefined);
|
|
155
|
+
function LiveUpdates() {
|
|
156
|
+
const scrubberRef = useRef<ScrubberRef>(null);
|
|
412
157
|
|
|
413
158
|
const initialData = useMemo(() => {
|
|
414
159
|
return sparklineInteractiveData.hour.map((d) => d.value);
|
|
@@ -461,19 +206,25 @@ function LiveAssetPrice() {
|
|
|
461
206
|
return () => clearInterval(priceUpdateInterval);
|
|
462
207
|
}, [intervalSeconds, maxPercentChange]);
|
|
463
208
|
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
209
|
+
const chartAccessibilityLabel = useMemo(() => {
|
|
210
|
+
return `Live Bitcoin price chart. Current price: $${priceData[priceData.length - 1].toFixed(2)}`;
|
|
211
|
+
}, [priceData]);
|
|
212
|
+
|
|
213
|
+
const scrubberAccessibilityLabel = useCallback(
|
|
214
|
+
(index: number) => {
|
|
215
|
+
const price = priceData[index];
|
|
216
|
+
return `Bitcoin price at position ${index + 1}: $${price.toFixed(2)}`;
|
|
217
|
+
},
|
|
218
|
+
[priceData],
|
|
219
|
+
);
|
|
470
220
|
|
|
471
221
|
return (
|
|
472
222
|
<LineChart
|
|
473
223
|
enableScrubbing
|
|
474
|
-
onScrubberPositionChange={setScrubIndex}
|
|
475
224
|
showArea
|
|
476
|
-
|
|
225
|
+
accessibilityLabel={chartAccessibilityLabel}
|
|
226
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
227
|
+
inset={{ right: 64 }}
|
|
477
228
|
series={[
|
|
478
229
|
{
|
|
479
230
|
id: 'btc',
|
|
@@ -481,154 +232,1030 @@ function LiveAssetPrice() {
|
|
|
481
232
|
color: assets.btc.color,
|
|
482
233
|
},
|
|
483
234
|
]}
|
|
484
|
-
inset={{ right: 64 }}
|
|
485
|
-
accessibilityLabel={accessibilityLabel}
|
|
486
235
|
>
|
|
487
|
-
<Scrubber
|
|
236
|
+
<Scrubber
|
|
237
|
+
ref={scrubberRef}
|
|
238
|
+
accessibilityLabel={scrubberAccessibilityLabel}
|
|
239
|
+
/>
|
|
488
240
|
</LineChart>
|
|
489
241
|
);
|
|
490
242
|
}
|
|
491
243
|
```
|
|
492
244
|
|
|
493
|
-
|
|
245
|
+
#### Missing Data
|
|
494
246
|
|
|
495
|
-
|
|
247
|
+
By default, null values in data create gaps in a line. Use `connectNulls` to skip null values and draw a continuous line.
|
|
248
|
+
Note that scrubber beacons and points are still only shown at non-null data values.
|
|
496
249
|
|
|
497
250
|
```jsx live
|
|
498
|
-
function
|
|
499
|
-
const [
|
|
500
|
-
|
|
501
|
-
const
|
|
502
|
-
const xData = [1, 2, 3, 5, 8, 10];
|
|
251
|
+
function MissingData() {
|
|
252
|
+
const pages = ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'];
|
|
253
|
+
const pageViews = [2400, 1398, null, 3908, 4800, 3800, 4300];
|
|
254
|
+
const uniqueVisitors = [4000, 3000, null, 2780, 1890, 2390, 3490];
|
|
503
255
|
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
256
|
+
const numberFormatter = useCallback(
|
|
257
|
+
(value: number) => new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(value),
|
|
258
|
+
[],
|
|
259
|
+
);
|
|
508
260
|
|
|
509
261
|
return (
|
|
510
262
|
<LineChart
|
|
511
263
|
enableScrubbing
|
|
512
|
-
|
|
264
|
+
showArea
|
|
265
|
+
showXAxis
|
|
266
|
+
showYAxis
|
|
267
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
268
|
+
// You can render points at every valid data point by always returning true
|
|
269
|
+
points
|
|
513
270
|
series={[
|
|
514
271
|
{
|
|
515
|
-
id: '
|
|
516
|
-
data:
|
|
272
|
+
id: 'pageViews',
|
|
273
|
+
data: pageViews,
|
|
274
|
+
color: 'var(--color-accentBoldGreen)',
|
|
275
|
+
// Label will render next to scrubber beacon
|
|
276
|
+
label: 'Page Views',
|
|
277
|
+
connectNulls: true,
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: 'uniqueVisitors',
|
|
281
|
+
data: uniqueVisitors,
|
|
282
|
+
color: 'var(--color-accentBoldPurple)',
|
|
283
|
+
label: 'Unique Visitors',
|
|
517
284
|
},
|
|
518
285
|
]}
|
|
519
|
-
|
|
286
|
+
xAxis={{
|
|
287
|
+
// Used on the x-axis to provide context for each index from the series data array
|
|
288
|
+
data: pages,
|
|
289
|
+
}}
|
|
290
|
+
yAxis={{
|
|
291
|
+
showGrid: true,
|
|
292
|
+
tickLabelFormatter: numberFormatter,
|
|
293
|
+
}}
|
|
294
|
+
>
|
|
295
|
+
{/* We can offset the overlay to account for the points being drawn on the lines */}
|
|
296
|
+
<Scrubber overlayOffset={6} />
|
|
297
|
+
</LineChart>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
##### Empty State
|
|
303
|
+
|
|
304
|
+
```jsx live
|
|
305
|
+
<LineChart
|
|
306
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
307
|
+
series={[
|
|
308
|
+
{
|
|
309
|
+
id: 'line',
|
|
310
|
+
color: 'rgb(var(--gray50))',
|
|
311
|
+
data: [1, 1],
|
|
312
|
+
showArea: true,
|
|
313
|
+
},
|
|
314
|
+
]}
|
|
315
|
+
yAxis={{ domain: { min: -1, max: 3 } }}
|
|
316
|
+
/>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### Scales
|
|
320
|
+
|
|
321
|
+
LineChart uses `linear` scaling on axes by default, but you can also use other types, such as `log`. See [XAxis](/components/graphs/XAxis) and [YAxis](/components/graphs/YAxis) for more information.
|
|
322
|
+
|
|
323
|
+
```jsx live
|
|
324
|
+
<LineChart
|
|
325
|
+
showArea
|
|
326
|
+
showYAxis
|
|
327
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
328
|
+
series={[
|
|
329
|
+
{
|
|
330
|
+
id: 'prices',
|
|
331
|
+
data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58],
|
|
332
|
+
},
|
|
333
|
+
]}
|
|
334
|
+
yAxis={{
|
|
335
|
+
scaleType: 'log',
|
|
336
|
+
showGrid: true,
|
|
337
|
+
ticks: [1, 10, 100],
|
|
338
|
+
}}
|
|
339
|
+
/>
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Interaction
|
|
343
|
+
|
|
344
|
+
Charts have built in functionality enabled through scrubbing, which can be used by setting `enableScrubbing` to true. You can listen to value changes through `onScrubberPositionChange`. Adding `Scrubber` to LineChart showcases the current scrubber position.
|
|
345
|
+
|
|
346
|
+
```jsx live
|
|
347
|
+
function Interaction() {
|
|
348
|
+
const [scrubberPosition, setScrubberPosition] = useState<number | undefined>();
|
|
349
|
+
|
|
350
|
+
return (
|
|
351
|
+
<VStack gap={2}>
|
|
352
|
+
<Text font="label1">
|
|
353
|
+
{scrubberPosition !== undefined
|
|
354
|
+
? `Scrubber position: ${scrubberPosition}`
|
|
355
|
+
: 'Not scrubbing'}
|
|
356
|
+
</Text>
|
|
357
|
+
<LineChart
|
|
358
|
+
enableScrubbing
|
|
359
|
+
showArea
|
|
360
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
361
|
+
onScrubberPositionChange={setScrubberPosition}
|
|
362
|
+
series={[
|
|
363
|
+
{
|
|
364
|
+
id: 'prices',
|
|
365
|
+
data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58],
|
|
366
|
+
},
|
|
367
|
+
]}
|
|
368
|
+
>
|
|
369
|
+
<Scrubber />
|
|
370
|
+
</LineChart>
|
|
371
|
+
</VStack>
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
#### Points
|
|
377
|
+
|
|
378
|
+
You can use `points` from LineChart with `onClick` listeners to render instances of [Point](/components/graphs/Point) that are interactable.
|
|
379
|
+
|
|
380
|
+
```jsx live
|
|
381
|
+
function Points() {
|
|
382
|
+
const keyMarketShiftIndices = [4, 6, 7, 9, 10];
|
|
383
|
+
const data = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58];
|
|
384
|
+
|
|
385
|
+
return (
|
|
386
|
+
<CartesianChart
|
|
387
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
388
|
+
series={[
|
|
389
|
+
{
|
|
390
|
+
id: 'prices',
|
|
391
|
+
data: data,
|
|
392
|
+
},
|
|
393
|
+
]}
|
|
394
|
+
>
|
|
395
|
+
<Area fill="rgb(var(--blue5))" seriesId="prices" />
|
|
396
|
+
<Line
|
|
397
|
+
points={({ dataX, dataY, ...props }) =>
|
|
398
|
+
keyMarketShiftIndices.includes(dataX)
|
|
399
|
+
? {
|
|
400
|
+
...props,
|
|
401
|
+
strokeWidth: 2,
|
|
402
|
+
stroke: 'var(--color-bg)',
|
|
403
|
+
radius: 5,
|
|
404
|
+
onClick: () =>
|
|
405
|
+
alert(
|
|
406
|
+
`You have clicked a key market shift at position ${dataX + 1} with value ${dataY}!`,
|
|
407
|
+
),
|
|
408
|
+
accessibilityLabel: `Key market shift point at position ${dataX + 1}, value ${dataY}. Click to view details.`,
|
|
409
|
+
}
|
|
410
|
+
: false
|
|
411
|
+
}
|
|
412
|
+
seriesId="prices"
|
|
413
|
+
/>
|
|
414
|
+
</CartesianChart>
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Animations
|
|
420
|
+
|
|
421
|
+
You can configure chart transitions using `transition` on LineChart and `beaconTransitions` on [Scrubber](/components/graphs/Scrubber). You can also disable animations by setting the `animate` on LineChart to `false`.
|
|
422
|
+
|
|
423
|
+
```jsx live
|
|
424
|
+
function Transitions() {
|
|
425
|
+
const dataCount = 20;
|
|
426
|
+
const maxDataOffset = 15000;
|
|
427
|
+
const minStepOffset = 2500;
|
|
428
|
+
const maxStepOffset = 10000;
|
|
429
|
+
const domainLimit = 20000;
|
|
430
|
+
const updateInterval = 500;
|
|
431
|
+
|
|
432
|
+
const myTransitionConfig = { type: 'spring', stiffness: 700, damping: 20 };
|
|
433
|
+
const negativeColor = 'rgb(var(--gray15))';
|
|
434
|
+
const positiveColor = 'var(--color-fgPositive)';
|
|
435
|
+
|
|
436
|
+
function generateNextValue(previousValue: number) {
|
|
437
|
+
const range = maxStepOffset - minStepOffset;
|
|
438
|
+
const offset = Math.random() * range + minStepOffset;
|
|
439
|
+
|
|
440
|
+
let direction;
|
|
441
|
+
if (previousValue >= maxDataOffset) {
|
|
442
|
+
direction = -1;
|
|
443
|
+
} else if (previousValue <= -maxDataOffset) {
|
|
444
|
+
direction = 1;
|
|
445
|
+
} else {
|
|
446
|
+
direction = Math.random() < 0.5 ? -1 : 1;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
let newValue = previousValue + offset * direction;
|
|
450
|
+
newValue = Math.max(-maxDataOffset, Math.min(maxDataOffset, newValue));
|
|
451
|
+
return newValue;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function generateInitialData() {
|
|
455
|
+
const data = [];
|
|
456
|
+
|
|
457
|
+
let previousValue = Math.random() * 2 * maxDataOffset - maxDataOffset;
|
|
458
|
+
data.push(previousValue);
|
|
459
|
+
|
|
460
|
+
for (let i = 1; i < dataCount; i++) {
|
|
461
|
+
const newValue = generateNextValue(previousValue);
|
|
462
|
+
data.push(newValue);
|
|
463
|
+
previousValue = newValue;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return data;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const MyGradient = memo((props: DottedAreaProps) => {
|
|
470
|
+
const areaGradient = {
|
|
471
|
+
stops: ({ min, max }: AxisBounds) => [
|
|
472
|
+
{ offset: min, color: negativeColor, opacity: 1 },
|
|
473
|
+
{ offset: 0, color: negativeColor, opacity: 0 },
|
|
474
|
+
{ offset: 0, color: positiveColor, opacity: 0 },
|
|
475
|
+
{ offset: max, color: positiveColor, opacity: 1 },
|
|
476
|
+
],
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
return <DottedArea {...props} gradient={areaGradient} />;
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
function CustomTransitionsChart() {
|
|
483
|
+
const [data, setData] = useState(generateInitialData);
|
|
484
|
+
|
|
485
|
+
useEffect(() => {
|
|
486
|
+
const intervalId = setInterval(() => {
|
|
487
|
+
setData((currentData) => {
|
|
488
|
+
const lastValue = currentData[currentData.length - 1] ?? 0;
|
|
489
|
+
const newValue = generateNextValue(lastValue);
|
|
490
|
+
|
|
491
|
+
return [...currentData.slice(1), newValue];
|
|
492
|
+
});
|
|
493
|
+
}, updateInterval);
|
|
494
|
+
|
|
495
|
+
return () => clearInterval(intervalId);
|
|
496
|
+
}, []);
|
|
497
|
+
|
|
498
|
+
const tickLabelFormatter = useCallback(
|
|
499
|
+
(value: number) =>
|
|
500
|
+
new Intl.NumberFormat('en-US', {
|
|
501
|
+
style: 'currency',
|
|
502
|
+
currency: 'USD',
|
|
503
|
+
maximumFractionDigits: 0,
|
|
504
|
+
}).format(value),
|
|
505
|
+
[],
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
const valueAtIndexFormatter = useCallback(
|
|
509
|
+
(dataIndex: number) =>
|
|
510
|
+
new Intl.NumberFormat('en-US', {
|
|
511
|
+
style: 'currency',
|
|
512
|
+
currency: 'USD',
|
|
513
|
+
}).format(data[dataIndex]),
|
|
514
|
+
[data],
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
const lineGradient = {
|
|
518
|
+
stops: [
|
|
519
|
+
{ offset: 0, color: negativeColor },
|
|
520
|
+
{ offset: 0, color: positiveColor },
|
|
521
|
+
],
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
return (
|
|
525
|
+
<CartesianChart
|
|
526
|
+
enableScrubbing
|
|
527
|
+
height={{ base: 200, tablet: 250, desktop: 300 }}
|
|
528
|
+
inset={{ top: 32, bottom: 32, left: 16, right: 16 }}
|
|
529
|
+
series={[
|
|
530
|
+
{
|
|
531
|
+
id: 'prices',
|
|
532
|
+
data: data,
|
|
533
|
+
gradient: lineGradient,
|
|
534
|
+
},
|
|
535
|
+
]}
|
|
536
|
+
yAxis={{ domain: { min: -domainLimit, max: domainLimit } }}
|
|
537
|
+
>
|
|
538
|
+
<YAxis showGrid requestedTickCount={2} tickLabelFormatter={tickLabelFormatter} />
|
|
539
|
+
<Line
|
|
540
|
+
showArea
|
|
541
|
+
AreaComponent={MyGradient}
|
|
542
|
+
seriesId="prices"
|
|
543
|
+
strokeWidth={3}
|
|
544
|
+
transition={myTransitionConfig}
|
|
545
|
+
/>
|
|
546
|
+
<Scrubber
|
|
547
|
+
hideOverlay
|
|
548
|
+
beaconTransitions={{ update: myTransitionConfig }}
|
|
549
|
+
label={valueAtIndexFormatter}
|
|
550
|
+
/>
|
|
551
|
+
</CartesianChart>
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return <CustomTransitionsChart />;
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Accessibility
|
|
560
|
+
|
|
561
|
+
You can use `accessibilityLabel` on both the chart and the scrubber to provide descriptive labels. The chart's label gives an overview, while the scrubber's label provides specific information about the current data point being viewed.
|
|
562
|
+
|
|
563
|
+
```jsx live
|
|
564
|
+
function BasicAccessible() {
|
|
565
|
+
const data = useMemo(() => [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58], []);
|
|
566
|
+
|
|
567
|
+
// Chart-level accessibility label provides overview
|
|
568
|
+
const chartAccessibilityLabel = useMemo(() => {
|
|
569
|
+
const currentPrice = data[data.length - 1];
|
|
570
|
+
return `Price chart showing trend over ${data.length} data points. Current value: ${currentPrice}. Use arrow keys to adjust view`;
|
|
571
|
+
}, [data]);
|
|
572
|
+
|
|
573
|
+
// Scrubber-level accessibility label provides specific position info
|
|
574
|
+
const scrubberAccessibilityLabel = useCallback(
|
|
575
|
+
(index: number) => {
|
|
576
|
+
return `Price at position ${index + 1} of ${data.length}: ${data[index]}`;
|
|
577
|
+
},
|
|
578
|
+
[data],
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
return (
|
|
582
|
+
<LineChart
|
|
583
|
+
enableScrubbing
|
|
520
584
|
showArea
|
|
521
|
-
renderPoints={() => true}
|
|
522
|
-
curve="natural"
|
|
523
|
-
showXAxis
|
|
524
|
-
xAxis={{ data: xData, showLine: true, showTickMarks: true, showGrid: true }}
|
|
525
585
|
showYAxis
|
|
586
|
+
accessibilityLabel={chartAccessibilityLabel}
|
|
587
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
588
|
+
series={[
|
|
589
|
+
{
|
|
590
|
+
id: 'prices',
|
|
591
|
+
data: data,
|
|
592
|
+
},
|
|
593
|
+
]}
|
|
526
594
|
yAxis={{
|
|
527
|
-
domain: { min: 0 },
|
|
528
|
-
position: 'left',
|
|
529
|
-
showLine: true,
|
|
530
|
-
showTickMarks: true,
|
|
531
595
|
showGrid: true,
|
|
532
596
|
}}
|
|
533
|
-
inset={{ top: 16, right: 16, bottom: 0, left: 0 }}
|
|
534
|
-
accessibilityLabel={accessibilityLabel}
|
|
535
597
|
>
|
|
536
|
-
<Scrubber
|
|
598
|
+
<Scrubber accessibilityLabel={scrubberAccessibilityLabel} />
|
|
599
|
+
</LineChart>
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
When a chart has a visible header or title, you can use `aria-labelledby` to reference it, and still provide a dynamic scrubber accessibility label.
|
|
605
|
+
|
|
606
|
+
```jsx live
|
|
607
|
+
function AccessibleWithHeader() {
|
|
608
|
+
const headerId = useId();
|
|
609
|
+
const data = useMemo(() => [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58], []);
|
|
610
|
+
|
|
611
|
+
// Display label provides overview
|
|
612
|
+
const displayLabel = useMemo(
|
|
613
|
+
() => `Revenue chart showing trend. Current value: ${data[data.length - 1]}`,
|
|
614
|
+
[data],
|
|
615
|
+
);
|
|
616
|
+
|
|
617
|
+
// Scrubber-specific accessibility label
|
|
618
|
+
const scrubberAccessibilityLabel = useCallback(
|
|
619
|
+
(index: number) => {
|
|
620
|
+
return `Viewing position ${index + 1} of ${data.length}, value: ${data[index]}`;
|
|
621
|
+
},
|
|
622
|
+
[data],
|
|
623
|
+
);
|
|
624
|
+
|
|
625
|
+
return (
|
|
626
|
+
<VStack gap={2}>
|
|
627
|
+
<Text font="label1" id={headerId}>
|
|
628
|
+
{displayLabel}
|
|
629
|
+
</Text>
|
|
630
|
+
<LineChart
|
|
631
|
+
enableScrubbing
|
|
632
|
+
showArea
|
|
633
|
+
showYAxis
|
|
634
|
+
aria-labelledby={headerId}
|
|
635
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
636
|
+
series={[
|
|
637
|
+
{
|
|
638
|
+
id: 'revenue',
|
|
639
|
+
data: data,
|
|
640
|
+
},
|
|
641
|
+
]}
|
|
642
|
+
yAxis={{
|
|
643
|
+
showGrid: true,
|
|
644
|
+
}}
|
|
645
|
+
>
|
|
646
|
+
<Scrubber accessibilityLabel={scrubberAccessibilityLabel} />
|
|
647
|
+
</LineChart>
|
|
648
|
+
</VStack>
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
### Styling
|
|
654
|
+
|
|
655
|
+
#### Axes
|
|
656
|
+
|
|
657
|
+
Using `showXAxis` and `showYAxis` allows you to display the axes. For more information, such as adjusting domain and range, see [XAxis](/components/graphs/XAxis) and [YAxis](/components/graphs/YAxis).
|
|
658
|
+
|
|
659
|
+
```jsx live
|
|
660
|
+
<LineChart
|
|
661
|
+
showArea
|
|
662
|
+
showXAxis
|
|
663
|
+
showYAxis
|
|
664
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
665
|
+
series={[
|
|
666
|
+
{
|
|
667
|
+
id: 'prices',
|
|
668
|
+
data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58],
|
|
669
|
+
},
|
|
670
|
+
]}
|
|
671
|
+
xAxis={{
|
|
672
|
+
showGrid: true,
|
|
673
|
+
showLine: true,
|
|
674
|
+
showTickMarks: true,
|
|
675
|
+
tickLabelFormatter: (dataX: number) => `Day ${dataX}`,
|
|
676
|
+
}}
|
|
677
|
+
yAxis={{
|
|
678
|
+
showGrid: true,
|
|
679
|
+
showLine: true,
|
|
680
|
+
showTickMarks: true,
|
|
681
|
+
}}
|
|
682
|
+
/>
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
#### Gradients
|
|
686
|
+
|
|
687
|
+
Gradients can be applied to the y-axis (default) or x-axis. Each stop requires an `offset`, which is based on the data within the x/y scale and `color`, with an optional `opacity` (defaults to 1).
|
|
688
|
+
|
|
689
|
+
Values in between stops will be interpolated smoothly using [srgb color space](https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty).
|
|
690
|
+
|
|
691
|
+
```jsx live
|
|
692
|
+
function Gradients() {
|
|
693
|
+
const spectrumColors = [
|
|
694
|
+
'blue',
|
|
695
|
+
'green',
|
|
696
|
+
'orange',
|
|
697
|
+
'yellow',
|
|
698
|
+
'gray',
|
|
699
|
+
'indigo',
|
|
700
|
+
'pink',
|
|
701
|
+
'purple',
|
|
702
|
+
'red',
|
|
703
|
+
'teal',
|
|
704
|
+
'chartreuse',
|
|
705
|
+
];
|
|
706
|
+
const data = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58];
|
|
707
|
+
|
|
708
|
+
const [currentSpectrumColor, setCurrentSpectrumColor] = useState('pink');
|
|
709
|
+
|
|
710
|
+
return (
|
|
711
|
+
<VStack gap={2}>
|
|
712
|
+
<HStack flexWrap="wrap" gap={1} justifyContent="flex-end">
|
|
713
|
+
{spectrumColors.map((color) => (
|
|
714
|
+
<Pressable
|
|
715
|
+
key={color}
|
|
716
|
+
accessibilityLabel={`Select ${color}`}
|
|
717
|
+
borderRadius={1000}
|
|
718
|
+
height={{ base: 16, tablet: 24, desktop: 24 }}
|
|
719
|
+
onClick={() => setCurrentSpectrumColor(color)}
|
|
720
|
+
style={{
|
|
721
|
+
backgroundColor: `rgb(var(--${color}20))`,
|
|
722
|
+
border: `2px solid rgb(var(--${color}50))`,
|
|
723
|
+
outlineColor: `rgb(var(--${color}80))`,
|
|
724
|
+
outline:
|
|
725
|
+
currentSpectrumColor === color ? `2px solid rgb(var(--${color}80))` : undefined,
|
|
726
|
+
}}
|
|
727
|
+
width={{ base: 16, tablet: 24, desktop: 24 }}
|
|
728
|
+
/>
|
|
729
|
+
))}
|
|
730
|
+
</HStack>
|
|
731
|
+
<LineChart
|
|
732
|
+
showYAxis
|
|
733
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
734
|
+
points
|
|
735
|
+
series={[
|
|
736
|
+
{
|
|
737
|
+
id: 'continuousGradient',
|
|
738
|
+
data: data,
|
|
739
|
+
gradient: {
|
|
740
|
+
stops: [
|
|
741
|
+
{ offset: 0, color: `rgb(var(--${currentSpectrumColor}80))` },
|
|
742
|
+
{ offset: Math.max(...data), color: `rgb(var(--${currentSpectrumColor}20))` },
|
|
743
|
+
],
|
|
744
|
+
},
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
id: 'discreteGradient',
|
|
748
|
+
data: data.map((d) => d + 50),
|
|
749
|
+
// You can create a "discrete" gradient by having multiple stops at the same offset
|
|
750
|
+
gradient: {
|
|
751
|
+
stops: ({ min, max }) => [
|
|
752
|
+
// Allows a function which accepts min/max or direct array
|
|
753
|
+
{ offset: min, color: `rgb(var(--${currentSpectrumColor}80))` },
|
|
754
|
+
{ offset: min + (max - min) / 3, color: `rgb(var(--${currentSpectrumColor}80))` },
|
|
755
|
+
{ offset: min + (max - min) / 3, color: `rgb(var(--${currentSpectrumColor}50))` },
|
|
756
|
+
{
|
|
757
|
+
offset: min + ((max - min) / 3) * 2,
|
|
758
|
+
color: `rgb(var(--${currentSpectrumColor}50))`,
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
offset: min + ((max - min) / 3) * 2,
|
|
762
|
+
color: `rgb(var(--${currentSpectrumColor}20))`,
|
|
763
|
+
},
|
|
764
|
+
{ offset: max, color: `rgb(var(--${currentSpectrumColor}20))` },
|
|
765
|
+
],
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
id: 'xAxisGradient',
|
|
770
|
+
data: data.map((d) => d + 100),
|
|
771
|
+
gradient: {
|
|
772
|
+
// You can also configure by the x-axis.
|
|
773
|
+
axis: 'x',
|
|
774
|
+
stops: ({ min, max }) => [
|
|
775
|
+
{ offset: min, color: `rgb(var(--${currentSpectrumColor}80))`, opacity: 0 },
|
|
776
|
+
{ offset: max, color: `rgb(var(--${currentSpectrumColor}20))`, opacity: 1 },
|
|
777
|
+
],
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
]}
|
|
781
|
+
strokeWidth={4}
|
|
782
|
+
yAxis={{
|
|
783
|
+
showGrid: true,
|
|
784
|
+
}}
|
|
785
|
+
/>
|
|
786
|
+
</VStack>
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
You can even pass in a separate gradient for your `Line` and `Area` components.
|
|
792
|
+
|
|
793
|
+
```jsx live
|
|
794
|
+
function GainLossChart() {
|
|
795
|
+
const data = useMemo(() => [-40, -28, -21, -5, 48, -5, -28, 2, -29, -46, 16, -30, -29, 8], []);
|
|
796
|
+
const negativeColor = 'rgb(var(--gray15))';
|
|
797
|
+
const positiveColor = 'var(--color-fgPositive)';
|
|
798
|
+
|
|
799
|
+
const tickLabelFormatter = useCallback(
|
|
800
|
+
(value: number) =>
|
|
801
|
+
new Intl.NumberFormat('en-US', {
|
|
802
|
+
style: 'currency',
|
|
803
|
+
currency: 'USD',
|
|
804
|
+
maximumFractionDigits: 0,
|
|
805
|
+
}).format(value),
|
|
806
|
+
[],
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
// Line gradient: hard color change at 0 (full opacity for line)
|
|
810
|
+
const lineGradient = {
|
|
811
|
+
stops: [
|
|
812
|
+
{ offset: 0, color: negativeColor },
|
|
813
|
+
{ offset: 0, color: positiveColor },
|
|
814
|
+
],
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
const chartAccessibilityLabel = `Gain/Loss chart showing price changes. Current value: ${tickLabelFormatter(data[data.length - 1])}`;
|
|
818
|
+
|
|
819
|
+
const scrubberAccessibilityLabel = useCallback(
|
|
820
|
+
(index: number) => {
|
|
821
|
+
const value = data[index];
|
|
822
|
+
const status = value >= 0 ? 'gain' : 'loss';
|
|
823
|
+
return `Position ${index + 1} of ${data.length}: ${tickLabelFormatter(value)} ${status}`;
|
|
824
|
+
},
|
|
825
|
+
[data, tickLabelFormatter],
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
const GradientDottedArea = memo((props: DottedAreaProps) => (
|
|
829
|
+
<DottedArea
|
|
830
|
+
{...props}
|
|
831
|
+
gradient={{
|
|
832
|
+
stops: ({ min, max }) => [
|
|
833
|
+
{ offset: min, color: negativeColor, opacity: 0.4 },
|
|
834
|
+
{ offset: 0, color: negativeColor, opacity: 0 },
|
|
835
|
+
{ offset: 0, color: positiveColor, opacity: 0 },
|
|
836
|
+
{ offset: max, color: positiveColor, opacity: 0.4 },
|
|
837
|
+
],
|
|
838
|
+
}}
|
|
839
|
+
/>
|
|
840
|
+
));
|
|
841
|
+
|
|
842
|
+
return (
|
|
843
|
+
<CartesianChart
|
|
844
|
+
enableScrubbing
|
|
845
|
+
accessibilityLabel={chartAccessibilityLabel}
|
|
846
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
847
|
+
series={[
|
|
848
|
+
{
|
|
849
|
+
id: 'prices',
|
|
850
|
+
data: data,
|
|
851
|
+
gradient: lineGradient,
|
|
852
|
+
},
|
|
853
|
+
]}
|
|
854
|
+
xAxis={{
|
|
855
|
+
range: ({ min, max }) => ({ min, max: max - 16 }),
|
|
856
|
+
}}
|
|
857
|
+
>
|
|
858
|
+
<YAxis showGrid requestedTickCount={2} tickLabelFormatter={tickLabelFormatter} />
|
|
859
|
+
<Line showArea AreaComponent={GradientDottedArea} seriesId="prices" strokeWidth={3} />
|
|
860
|
+
<Scrubber hideOverlay accessibilityLabel={scrubberAccessibilityLabel} />
|
|
861
|
+
</CartesianChart>
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
#### Lines
|
|
867
|
+
|
|
868
|
+
You can customize lines by placing props in `LineChart` or at each individual series. Lines can have a `type` of `solid` or `dotted`. They can optionally show an area underneath them (using `showArea`).
|
|
869
|
+
|
|
870
|
+
```jsx live
|
|
871
|
+
<LineChart
|
|
872
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
873
|
+
series={[
|
|
874
|
+
{
|
|
875
|
+
id: 'top',
|
|
876
|
+
data: [15, 28, 32, 44, 46, 36, 40, 45, 48, 38],
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
id: 'upperMiddle',
|
|
880
|
+
data: [12, 23, 21, 29, 34, 28, 31, 38, 42, 35],
|
|
881
|
+
color: '#ef4444',
|
|
882
|
+
type: 'dotted',
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
id: 'lowerMiddle',
|
|
886
|
+
data: [8, 15, 14, 25, 20, 18, 22, 28, 24, 30],
|
|
887
|
+
color: '#f59e0b',
|
|
888
|
+
curve: 'natural',
|
|
889
|
+
gradient: {
|
|
890
|
+
axis: 'x',
|
|
891
|
+
stops: [
|
|
892
|
+
{ offset: 0, color: '#E3D74D' },
|
|
893
|
+
{ offset: 9, color: '#F7931A' },
|
|
894
|
+
],
|
|
895
|
+
},
|
|
896
|
+
strokeWidth: 6,
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
id: 'bottom',
|
|
900
|
+
data: [4, 8, 11, 15, 16, 14, 16, 10, 12, 14],
|
|
901
|
+
color: '#800080',
|
|
902
|
+
curve: 'step',
|
|
903
|
+
AreaComponent: DottedArea,
|
|
904
|
+
showArea: true,
|
|
905
|
+
},
|
|
906
|
+
]}
|
|
907
|
+
/>
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
You can also add instances of [ReferenceLine](/components/graphs/ReferenceLine) to your LineChart to highlight a specific x or y value.
|
|
911
|
+
|
|
912
|
+
```jsx live
|
|
913
|
+
<LineChart
|
|
914
|
+
enableScrubbing
|
|
915
|
+
showArea
|
|
916
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
917
|
+
series={[
|
|
918
|
+
{
|
|
919
|
+
id: 'prices',
|
|
920
|
+
data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58],
|
|
921
|
+
color: 'var(--color-fgPositive)',
|
|
922
|
+
},
|
|
923
|
+
]}
|
|
924
|
+
xAxis={{
|
|
925
|
+
// Give space before the end of the chart for the scrubber
|
|
926
|
+
range: ({ min, max }) => ({ min, max: max - 24 }),
|
|
927
|
+
}}
|
|
928
|
+
>
|
|
929
|
+
<ReferenceLine
|
|
930
|
+
LineComponent={(props) => <DottedLine {...props} strokeDasharray="0 16" strokeWidth={3} />}
|
|
931
|
+
dataY={10}
|
|
932
|
+
stroke="var(--color-fg)"
|
|
933
|
+
/>
|
|
934
|
+
<Scrubber />
|
|
935
|
+
</LineChart>
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
#### Points
|
|
939
|
+
|
|
940
|
+
You can also add instances of [Point](/components/graphs/Point) directly inside of a LineChart.
|
|
941
|
+
|
|
942
|
+
```jsx live
|
|
943
|
+
function HighLowPrice() {
|
|
944
|
+
const data = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58];
|
|
945
|
+
const minPrice = Math.min(...data);
|
|
946
|
+
const maxPrice = Math.max(...data);
|
|
947
|
+
|
|
948
|
+
const minPriceIndex = data.indexOf(minPrice);
|
|
949
|
+
const maxPriceIndex = data.indexOf(maxPrice);
|
|
950
|
+
|
|
951
|
+
const formatPrice = useCallback((price: number) => {
|
|
952
|
+
return `$${price.toLocaleString('en-US', {
|
|
953
|
+
minimumFractionDigits: 2,
|
|
954
|
+
maximumFractionDigits: 2,
|
|
955
|
+
})}`;
|
|
956
|
+
}, []);
|
|
957
|
+
|
|
958
|
+
return (
|
|
959
|
+
<LineChart
|
|
960
|
+
showArea
|
|
961
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
962
|
+
series={[
|
|
963
|
+
{
|
|
964
|
+
id: 'prices',
|
|
965
|
+
data: data,
|
|
966
|
+
},
|
|
967
|
+
]}
|
|
968
|
+
>
|
|
969
|
+
<Point
|
|
970
|
+
dataX={minPriceIndex}
|
|
971
|
+
dataY={minPrice}
|
|
972
|
+
label={formatPrice(minPrice)}
|
|
973
|
+
labelPosition="bottom"
|
|
974
|
+
/>
|
|
975
|
+
<Point
|
|
976
|
+
dataX={maxPriceIndex}
|
|
977
|
+
dataY={maxPrice}
|
|
978
|
+
label={formatPrice(maxPrice)}
|
|
979
|
+
labelPosition="top"
|
|
980
|
+
/>
|
|
537
981
|
</LineChart>
|
|
538
982
|
);
|
|
539
983
|
}
|
|
540
984
|
```
|
|
541
985
|
|
|
542
|
-
|
|
986
|
+
#### Scrubber
|
|
987
|
+
|
|
988
|
+
When using [Scrubber](/components/graphs/Scrubber) with series that have labels, labels will automatically render to the side of the scrubber beacon.
|
|
543
989
|
|
|
544
|
-
You can
|
|
990
|
+
You can customize the line used for and which series will render a scrubber beacon.
|
|
991
|
+
|
|
992
|
+
You can have scrubber beacon's pulse by either adding `idlePulse` to Scrubber or use Scrubber's ref to dynamically pulse.
|
|
545
993
|
|
|
546
994
|
```jsx live
|
|
547
|
-
function
|
|
548
|
-
const [
|
|
549
|
-
const
|
|
995
|
+
function StylingScrubber() {
|
|
996
|
+
const pages = ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'];
|
|
997
|
+
const pageViews = [2400, 1398, 9800, 3908, 4800, 3800, 4300];
|
|
998
|
+
const uniqueVisitors = [4000, 3000, 2000, 2780, 1890, 2390, 3490];
|
|
550
999
|
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
return `Price at position ${scrubIndex + 1}: ${data[scrubIndex]}`;
|
|
556
|
-
}, [scrubIndex, data]);
|
|
1000
|
+
const numberFormatter = useCallback(
|
|
1001
|
+
(value: number) => new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(value),
|
|
1002
|
+
[],
|
|
1003
|
+
);
|
|
557
1004
|
|
|
558
1005
|
return (
|
|
559
1006
|
<LineChart
|
|
560
1007
|
enableScrubbing
|
|
561
|
-
|
|
562
|
-
|
|
1008
|
+
showArea
|
|
1009
|
+
showXAxis
|
|
1010
|
+
showYAxis
|
|
1011
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
563
1012
|
series={[
|
|
564
1013
|
{
|
|
565
|
-
id: '
|
|
566
|
-
data:
|
|
1014
|
+
id: 'pageViews',
|
|
1015
|
+
data: pageViews,
|
|
1016
|
+
color: 'var(--color-accentBoldGreen)',
|
|
1017
|
+
// Label will render next to scrubber beacon
|
|
1018
|
+
label: 'Page Views',
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
id: 'uniqueVisitors',
|
|
1022
|
+
data: uniqueVisitors,
|
|
1023
|
+
color: 'var(--color-accentBoldPurple)',
|
|
1024
|
+
label: 'Unique Visitors',
|
|
1025
|
+
// Default area is gradient
|
|
1026
|
+
areaType: 'dotted',
|
|
567
1027
|
},
|
|
568
1028
|
]}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
1029
|
+
xAxis={{
|
|
1030
|
+
// Used on the x-axis to provide context for each index from the series data array
|
|
1031
|
+
data: pages,
|
|
1032
|
+
}}
|
|
572
1033
|
yAxis={{
|
|
573
1034
|
showGrid: true,
|
|
1035
|
+
tickLabelFormatter: numberFormatter,
|
|
574
1036
|
}}
|
|
575
|
-
accessibilityLabel={accessibilityLabel}
|
|
576
1037
|
>
|
|
577
|
-
<Scrubber />
|
|
1038
|
+
<Scrubber idlePulse LineComponent={SolidLine} seriesIds={['pageViews']} />
|
|
578
1039
|
</LineChart>
|
|
579
1040
|
);
|
|
580
1041
|
}
|
|
581
1042
|
```
|
|
582
1043
|
|
|
583
|
-
|
|
1044
|
+
#### Sizing
|
|
1045
|
+
|
|
1046
|
+
Charts by default take up `100%` of the `width` and `height` available, but can be customized as any other component.
|
|
584
1047
|
|
|
585
1048
|
```jsx live
|
|
586
|
-
function
|
|
587
|
-
const
|
|
588
|
-
const
|
|
589
|
-
const
|
|
1049
|
+
function DynamicChartSizing() {
|
|
1050
|
+
const candles = [...btcCandles].reverse();
|
|
1051
|
+
const prices = candles.map((candle) => parseFloat(candle.close));
|
|
1052
|
+
const highs = candles.map((candle) => parseFloat(candle.high));
|
|
1053
|
+
const lows = candles.map((candle) => parseFloat(candle.low));
|
|
590
1054
|
|
|
591
|
-
const
|
|
592
|
-
|
|
593
|
-
|
|
1055
|
+
const latestPrice = prices[prices.length - 1];
|
|
1056
|
+
const previousPrice = prices[prices.length - 2];
|
|
1057
|
+
const change24h = ((latestPrice - previousPrice) / previousPrice) * 100;
|
|
1058
|
+
|
|
1059
|
+
function DetailCell({ title, description }: { title: string; description: string }) {
|
|
1060
|
+
return (
|
|
1061
|
+
<VStack>
|
|
1062
|
+
<Text color="fgMuted" font="label2">
|
|
1063
|
+
{title}
|
|
1064
|
+
</Text>
|
|
1065
|
+
<Text font="headline">{description}</Text>
|
|
1066
|
+
</VStack>
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// Calculate 7-day moving average
|
|
1071
|
+
const calculateMA = (data: number[], period: number): number[] => {
|
|
1072
|
+
const ma: number[] = [];
|
|
1073
|
+
for (let i = 0; i < data.length; i++) {
|
|
1074
|
+
if (i >= period - 1) {
|
|
1075
|
+
const sum = data.slice(i - period + 1, i + 1).reduce((a, b) => a + b, 0);
|
|
1076
|
+
ma.push(sum / period);
|
|
1077
|
+
}
|
|
594
1078
|
}
|
|
595
|
-
return
|
|
596
|
-
}
|
|
1079
|
+
return ma;
|
|
1080
|
+
};
|
|
1081
|
+
|
|
1082
|
+
const ma7 = calculateMA(prices, 7);
|
|
1083
|
+
const latestMA7: number = ma7[ma7.length - 1];
|
|
1084
|
+
|
|
1085
|
+
const periodHigh = Math.max(...highs);
|
|
1086
|
+
const periodLow = Math.min(...lows);
|
|
1087
|
+
|
|
1088
|
+
const formatPrice = useCallback((price: number) => {
|
|
1089
|
+
return `$${price.toLocaleString('en-US', {
|
|
1090
|
+
minimumFractionDigits: 2,
|
|
1091
|
+
maximumFractionDigits: 2,
|
|
1092
|
+
})}`;
|
|
1093
|
+
}, []);
|
|
1094
|
+
|
|
1095
|
+
const formatPercentage = useCallback((value: number) => {
|
|
1096
|
+
const sign = value >= 0 ? '+' : '';
|
|
1097
|
+
return `${sign}${value.toFixed(2)}%`;
|
|
1098
|
+
}, []);
|
|
597
1099
|
|
|
598
1100
|
return (
|
|
599
|
-
<
|
|
600
|
-
<
|
|
601
|
-
{
|
|
602
|
-
|
|
1101
|
+
<HStack gap={3}>
|
|
1102
|
+
<Box
|
|
1103
|
+
borderBottomLeftRadius={300}
|
|
1104
|
+
borderTopLeftRadius={300}
|
|
1105
|
+
flexGrow={1}
|
|
1106
|
+
style={{
|
|
1107
|
+
background: 'linear-gradient(0deg, #D07609 0%, #F7931A 100%)',
|
|
1108
|
+
marginTop: 'calc(-1 * var(--space-3))',
|
|
1109
|
+
marginLeft: 'calc(-1 * var(--space-3))',
|
|
1110
|
+
marginBottom: 'calc(-1 * var(--space-3))',
|
|
1111
|
+
}}
|
|
1112
|
+
>
|
|
1113
|
+
{/* LineChart fills to take up available width and height */}
|
|
1114
|
+
<LineChart
|
|
1115
|
+
series={[
|
|
1116
|
+
{
|
|
1117
|
+
id: 'btc',
|
|
1118
|
+
data: prices,
|
|
1119
|
+
color: 'white',
|
|
1120
|
+
},
|
|
1121
|
+
]}
|
|
1122
|
+
/>
|
|
1123
|
+
</Box>
|
|
1124
|
+
<VStack gap={1}>
|
|
1125
|
+
<VStack>
|
|
1126
|
+
<Text font="title1">BTC</Text>
|
|
1127
|
+
<Text font="title2">{formatPrice(latestPrice)}</Text>
|
|
1128
|
+
</VStack>
|
|
1129
|
+
<DetailCell description={formatPrice(periodHigh)} title="High" />
|
|
1130
|
+
<DetailCell description={formatPrice(periodLow)} title="Low" />
|
|
1131
|
+
<VStack display={{ base: 'none', tablet: 'flex', desktop: 'flex' }} gap={1}>
|
|
1132
|
+
<DetailCell description={formatPercentage(change24h)} title="24h" />
|
|
1133
|
+
<DetailCell description={formatPrice(latestMA7)} title="7d MA" />
|
|
1134
|
+
</VStack>
|
|
1135
|
+
</VStack>
|
|
1136
|
+
</HStack>
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
##### Compact
|
|
1142
|
+
|
|
1143
|
+
You can also have charts in a compact form.
|
|
1144
|
+
|
|
1145
|
+
```jsx live
|
|
1146
|
+
function Compact() {
|
|
1147
|
+
const dimensions = { width: 62, height: 18 };
|
|
1148
|
+
|
|
1149
|
+
const sparklineData = prices
|
|
1150
|
+
.map((price) => parseFloat(price))
|
|
1151
|
+
.filter((price, index) => index % 10 === 0);
|
|
1152
|
+
const positiveFloor = Math.min(...sparklineData) - 10;
|
|
1153
|
+
|
|
1154
|
+
const negativeData = sparklineData.map((price) => -1 * price).reverse();
|
|
1155
|
+
const negativeCeiling = Math.max(...negativeData) + 10;
|
|
1156
|
+
|
|
1157
|
+
const formatPrice = useCallback((price: number) => {
|
|
1158
|
+
return `$${price.toLocaleString('en-US', {
|
|
1159
|
+
minimumFractionDigits: 2,
|
|
1160
|
+
maximumFractionDigits: 2,
|
|
1161
|
+
})}`;
|
|
1162
|
+
}, []);
|
|
1163
|
+
|
|
1164
|
+
type CompactChartProps = {
|
|
1165
|
+
data: number[];
|
|
1166
|
+
showArea?: boolean;
|
|
1167
|
+
color?: string;
|
|
1168
|
+
referenceY: number;
|
|
1169
|
+
};
|
|
1170
|
+
|
|
1171
|
+
const CompactChart = memo(({ data, showArea, color, referenceY }: CompactChartProps) => (
|
|
1172
|
+
<Box style={{ padding: 1 }}>
|
|
603
1173
|
<LineChart
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
1174
|
+
{...dimensions}
|
|
1175
|
+
enableScrubbing={false}
|
|
1176
|
+
inset={0}
|
|
607
1177
|
series={[
|
|
608
1178
|
{
|
|
609
|
-
id: '
|
|
610
|
-
data
|
|
1179
|
+
id: 'btc',
|
|
1180
|
+
data,
|
|
1181
|
+
color,
|
|
611
1182
|
},
|
|
612
1183
|
]}
|
|
613
|
-
|
|
614
|
-
showYAxis
|
|
615
|
-
showArea
|
|
616
|
-
yAxis={{
|
|
617
|
-
showGrid: true,
|
|
618
|
-
}}
|
|
619
|
-
aria-labelledby={headerId}
|
|
1184
|
+
showArea={showArea}
|
|
620
1185
|
>
|
|
621
|
-
<
|
|
1186
|
+
<ReferenceLine dataY={referenceY} />
|
|
622
1187
|
</LineChart>
|
|
1188
|
+
</Box>
|
|
1189
|
+
));
|
|
1190
|
+
|
|
1191
|
+
const ChartCell = memo(
|
|
1192
|
+
({
|
|
1193
|
+
data,
|
|
1194
|
+
showArea,
|
|
1195
|
+
color,
|
|
1196
|
+
referenceY,
|
|
1197
|
+
subdetail,
|
|
1198
|
+
}: CompactChartProps & { subdetail: string }) => {
|
|
1199
|
+
const { isPhone } = useBreakpoints();
|
|
1200
|
+
|
|
1201
|
+
return (
|
|
1202
|
+
<ListCell
|
|
1203
|
+
description={isPhone ? undefined : assets.btc.symbol}
|
|
1204
|
+
detail={formatPrice(parseFloat(prices[0]))}
|
|
1205
|
+
intermediary={
|
|
1206
|
+
<CompactChart color={color} data={data} referenceY={referenceY} showArea={showArea} />
|
|
1207
|
+
}
|
|
1208
|
+
media={<Avatar src={assets.btc.imageUrl} />}
|
|
1209
|
+
onClick={() => console.log('clicked')}
|
|
1210
|
+
spacingVariant="condensed"
|
|
1211
|
+
style={{ padding: 0 }}
|
|
1212
|
+
subdetail={subdetail}
|
|
1213
|
+
title={isPhone ? undefined : assets.btc.name}
|
|
1214
|
+
/>
|
|
1215
|
+
);
|
|
1216
|
+
},
|
|
1217
|
+
);
|
|
1218
|
+
|
|
1219
|
+
return (
|
|
1220
|
+
<VStack>
|
|
1221
|
+
<ChartCell
|
|
1222
|
+
color={assets.btc.color}
|
|
1223
|
+
data={sparklineData}
|
|
1224
|
+
referenceY={parseFloat(prices[Math.floor(prices.length / 4)])}
|
|
1225
|
+
subdetail="-4.55%"
|
|
1226
|
+
/>
|
|
1227
|
+
<ChartCell
|
|
1228
|
+
showArea
|
|
1229
|
+
color={assets.btc.color}
|
|
1230
|
+
data={sparklineData}
|
|
1231
|
+
referenceY={parseFloat(prices[Math.floor(prices.length / 4)])}
|
|
1232
|
+
subdetail="-4.55%"
|
|
1233
|
+
/>
|
|
1234
|
+
<ChartCell
|
|
1235
|
+
showArea
|
|
1236
|
+
color="var(--color-fgPositive)"
|
|
1237
|
+
data={sparklineData}
|
|
1238
|
+
referenceY={positiveFloor}
|
|
1239
|
+
subdetail="+0.25%"
|
|
1240
|
+
/>
|
|
1241
|
+
<ChartCell
|
|
1242
|
+
showArea
|
|
1243
|
+
color="var(--color-fgNegative)"
|
|
1244
|
+
data={negativeData}
|
|
1245
|
+
referenceY={negativeCeiling}
|
|
1246
|
+
subdetail="-4.55%"
|
|
1247
|
+
/>
|
|
623
1248
|
</VStack>
|
|
624
1249
|
);
|
|
625
1250
|
}
|
|
626
1251
|
```
|
|
627
1252
|
|
|
628
|
-
###
|
|
1253
|
+
### Composed Examples
|
|
629
1254
|
|
|
630
1255
|
#### Asset Price with Dotted Area
|
|
631
1256
|
|
|
1257
|
+
You can use [PeriodSelector](/components/graphs/PeriodSelector) to have a chart where the user can select a time period and the chart automatically animates.
|
|
1258
|
+
|
|
632
1259
|
```jsx live
|
|
633
1260
|
function AssetPriceWithDottedArea() {
|
|
634
1261
|
const BTCTab: TabComponent = memo(
|
|
@@ -657,7 +1284,7 @@ function AssetPriceWithDottedArea() {
|
|
|
657
1284
|
),
|
|
658
1285
|
);
|
|
659
1286
|
|
|
660
|
-
const BTCActiveIndicator = memo(({ style, ...props }: TabsActiveIndicatorProps) => (
|
|
1287
|
+
const BTCActiveIndicator = memo(({ style, ...props }: TabsActiveIndicatorProps) => (
|
|
661
1288
|
<PeriodSelectorActiveIndicator
|
|
662
1289
|
{...props}
|
|
663
1290
|
style={{ ...style, backgroundColor: `${assets.btc.color}1A` }}
|
|
@@ -665,200 +1292,50 @@ const BTCActiveIndicator = memo(({ style, ...props }: TabsActiveIndicatorProps)
|
|
|
665
1292
|
));
|
|
666
1293
|
|
|
667
1294
|
const AssetPriceDotted = memo(() => {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
return sparklineInteractiveData[timePeriod.id as keyof typeof sparklineInteractiveData];
|
|
683
|
-
}, [timePeriod]);
|
|
684
|
-
|
|
685
|
-
const sparklineTimePeriodDataValues = useMemo(() => {
|
|
686
|
-
return sparklineTimePeriodData.map((d) => d.value);
|
|
687
|
-
}, [sparklineTimePeriodData]);
|
|
688
|
-
|
|
689
|
-
const sparklineTimePeriodDataTimestamps = useMemo(() => {
|
|
690
|
-
return sparklineTimePeriodData.map((d) => d.date);
|
|
691
|
-
}, [sparklineTimePeriodData]);
|
|
692
|
-
|
|
693
|
-
const onPeriodChange = useCallback(
|
|
694
|
-
(period: TabValue | null) => {
|
|
695
|
-
setTimePeriod(period || tabs[0]);
|
|
696
|
-
},
|
|
697
|
-
[tabs, setTimePeriod],
|
|
698
|
-
);
|
|
699
|
-
|
|
700
|
-
const priceFormatter = useMemo(
|
|
701
|
-
() =>
|
|
702
|
-
new Intl.NumberFormat('en-US', {
|
|
703
|
-
style: 'currency',
|
|
704
|
-
currency: 'USD',
|
|
705
|
-
}),
|
|
706
|
-
[],
|
|
707
|
-
);
|
|
708
|
-
|
|
709
|
-
const scrubberPriceFormatter = useMemo(
|
|
710
|
-
() =>
|
|
711
|
-
new Intl.NumberFormat('en-US', {
|
|
712
|
-
minimumFractionDigits: 2,
|
|
713
|
-
maximumFractionDigits: 2,
|
|
714
|
-
}),
|
|
715
|
-
[],
|
|
716
|
-
);
|
|
717
|
-
|
|
718
|
-
const formatPrice = useCallback((price: number) => {
|
|
719
|
-
return priceFormatter.format(price);
|
|
720
|
-
}, [priceFormatter]);
|
|
721
|
-
|
|
722
|
-
const formatDate = useCallback((date: Date) => {
|
|
723
|
-
const dayOfWeek = date.toLocaleDateString('en-US', { weekday: 'short' });
|
|
724
|
-
|
|
725
|
-
const monthDay = date.toLocaleDateString('en-US', {
|
|
726
|
-
month: 'short',
|
|
727
|
-
day: 'numeric',
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
const time = date.toLocaleTimeString('en-US', {
|
|
731
|
-
hour: 'numeric',
|
|
732
|
-
minute: '2-digit',
|
|
733
|
-
hour12: true,
|
|
734
|
-
});
|
|
735
|
-
|
|
736
|
-
return `${dayOfWeek}, ${monthDay}, ${time}`;
|
|
737
|
-
}, []);
|
|
738
|
-
|
|
739
|
-
const scrubberLabel = useCallback(
|
|
740
|
-
(index: number) => {
|
|
741
|
-
const price = scrubberPriceFormatter.format(sparklineTimePeriodDataValues[index]);
|
|
742
|
-
const date = formatDate(sparklineTimePeriodDataTimestamps[index]);
|
|
743
|
-
return (
|
|
744
|
-
<>
|
|
745
|
-
<tspan style={{ fontWeight: 'bold' }}>{price} USD</tspan> {date}
|
|
746
|
-
</>
|
|
747
|
-
);
|
|
748
|
-
},
|
|
749
|
-
[scrubberPriceFormatter, sparklineTimePeriodDataValues, sparklineTimePeriodDataTimestamps, formatDate],
|
|
750
|
-
);
|
|
751
|
-
|
|
752
|
-
const accessibilityLabel = useCallback(
|
|
753
|
-
(index: number) => {
|
|
754
|
-
const price = scrubberPriceFormatter.format(sparklineTimePeriodDataValues[index]);
|
|
755
|
-
const date = formatDate(sparklineTimePeriodDataTimestamps[index]);
|
|
756
|
-
return `${price} USD ${date}`;
|
|
757
|
-
},
|
|
758
|
-
[scrubberPriceFormatter, sparklineTimePeriodDataValues, sparklineTimePeriodDataTimestamps, formatDate],
|
|
759
|
-
);
|
|
760
|
-
|
|
761
|
-
return (
|
|
762
|
-
<VStack gap={2}>
|
|
763
|
-
<SectionHeader
|
|
764
|
-
style={{ padding: 0 }}
|
|
765
|
-
title={<Text font="title1">Bitcoin</Text>}
|
|
766
|
-
balance={<Text font="title2">{formatPrice(currentPrice)}</Text>}
|
|
767
|
-
end={
|
|
768
|
-
<VStack justifyContent="center">
|
|
769
|
-
<RemoteImage source={assets.btc.imageUrl} size="xl" shape="circle" />
|
|
770
|
-
</VStack>
|
|
771
|
-
}
|
|
772
|
-
/>
|
|
773
|
-
<LineChart
|
|
774
|
-
overflow="visible"
|
|
775
|
-
enableScrubbing
|
|
776
|
-
onScrubberPositionChange={setScrubIndex}
|
|
777
|
-
series={[
|
|
778
|
-
{
|
|
779
|
-
id: 'btc',
|
|
780
|
-
data: sparklineTimePeriodDataValues,
|
|
781
|
-
color: assets.btc.color,
|
|
782
|
-
},
|
|
783
|
-
]}
|
|
784
|
-
showArea
|
|
785
|
-
areaType="dotted"
|
|
786
|
-
height={{ base: 150, tablet: 200, desktop: 250 }}
|
|
787
|
-
style={{ outlineColor: assets.btc.color }}
|
|
788
|
-
accessibilityLabel={scrubberLabel}
|
|
789
|
-
padding={{ left: 2, right: 2 }}
|
|
790
|
-
>
|
|
791
|
-
<Scrubber label={scrubberLabel} labelProps={{ elevation: 1 }} idlePulse />
|
|
792
|
-
</LineChart>
|
|
793
|
-
<PeriodSelector
|
|
794
|
-
TabComponent={BTCTab}
|
|
795
|
-
TabsActiveIndicatorComponent={BTCActiveIndicator}
|
|
796
|
-
tabs={tabs}
|
|
797
|
-
activeTab={timePeriod}
|
|
798
|
-
onChange={onPeriodChange}
|
|
799
|
-
/>
|
|
800
|
-
</VStack>
|
|
801
|
-
)});
|
|
802
|
-
|
|
803
|
-
return <AssetPriceDotted />;
|
|
804
|
-
};
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
#### Forecast Asset Price
|
|
808
|
-
|
|
809
|
-
```jsx live
|
|
810
|
-
function ForecastAssetPrice() {
|
|
811
|
-
const ForecastAreaComponent = memo(
|
|
812
|
-
(props: AreaComponentProps) => (
|
|
813
|
-
<DottedArea {...props} peakOpacity={0.4} baselineOpacity={0.4} />
|
|
814
|
-
),
|
|
815
|
-
);
|
|
816
|
-
|
|
817
|
-
const ForecastChart = memo(() => {
|
|
818
|
-
const [scrubIndex, setScrubIndex] = useState<number | undefined>(undefined);
|
|
819
|
-
|
|
820
|
-
const getDataFromSparkline = useCallback((startDate: Date) => {
|
|
821
|
-
const allData = sparklineInteractiveData.all;
|
|
822
|
-
if (!allData || allData.length === 0) return [];
|
|
823
|
-
|
|
824
|
-
const timelineData = allData.filter((point) => point.date >= startDate);
|
|
825
|
-
|
|
826
|
-
return timelineData.map((point) => ({
|
|
827
|
-
date: point.date,
|
|
828
|
-
value: point.value,
|
|
829
|
-
}));
|
|
830
|
-
}, []);
|
|
831
|
-
|
|
832
|
-
const historicalData = useMemo(() => getDataFromSparkline(new Date('2019-01-01')), [getDataFromSparkline]);
|
|
833
|
-
|
|
834
|
-
const annualGrowthRate = 10;
|
|
1295
|
+
const currentPrice =
|
|
1296
|
+
sparklineInteractiveData.hour[sparklineInteractiveData.hour.length - 1].value;
|
|
1297
|
+
const tabs = useMemo(
|
|
1298
|
+
() => [
|
|
1299
|
+
{ id: 'hour', label: '1H' },
|
|
1300
|
+
{ id: 'day', label: '1D' },
|
|
1301
|
+
{ id: 'week', label: '1W' },
|
|
1302
|
+
{ id: 'month', label: '1M' },
|
|
1303
|
+
{ id: 'year', label: '1Y' },
|
|
1304
|
+
{ id: 'all', label: 'All' },
|
|
1305
|
+
],
|
|
1306
|
+
[],
|
|
1307
|
+
);
|
|
1308
|
+
const [timePeriod, setTimePeriod] = useState<TabValue>(tabs[0]);
|
|
835
1309
|
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
const forecastData = [];
|
|
840
|
-
const fiveYearsFromNow = new Date(lastDate);
|
|
841
|
-
fiveYearsFromNow.setFullYear(fiveYearsFromNow.getFullYear() + 5);
|
|
1310
|
+
const sparklineTimePeriodData = useMemo(() => {
|
|
1311
|
+
return sparklineInteractiveData[timePeriod.id as keyof typeof sparklineInteractiveData];
|
|
1312
|
+
}, [timePeriod]);
|
|
842
1313
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
1314
|
+
const sparklineTimePeriodDataValues = useMemo(() => {
|
|
1315
|
+
return sparklineTimePeriodData.map((d) => d.value);
|
|
1316
|
+
}, [sparklineTimePeriodData]);
|
|
846
1317
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
date: new Date(currentDate),
|
|
851
|
-
value: Math.round(currentPrice),
|
|
852
|
-
});
|
|
853
|
-
currentDate.setDate(currentDate.getDate() + 10);
|
|
854
|
-
}
|
|
1318
|
+
const sparklineTimePeriodDataTimestamps = useMemo(() => {
|
|
1319
|
+
return sparklineTimePeriodData.map((d) => d.date);
|
|
1320
|
+
}, [sparklineTimePeriodData]);
|
|
855
1321
|
|
|
856
|
-
|
|
1322
|
+
const onPeriodChange = useCallback(
|
|
1323
|
+
(period: TabValue | null) => {
|
|
1324
|
+
setTimePeriod(period || tabs[0]);
|
|
857
1325
|
},
|
|
858
|
-
[],
|
|
1326
|
+
[tabs, setTimePeriod],
|
|
859
1327
|
);
|
|
860
1328
|
|
|
861
1329
|
const priceFormatter = useMemo(
|
|
1330
|
+
() =>
|
|
1331
|
+
new Intl.NumberFormat('en-US', {
|
|
1332
|
+
style: 'currency',
|
|
1333
|
+
currency: 'USD',
|
|
1334
|
+
}),
|
|
1335
|
+
[],
|
|
1336
|
+
);
|
|
1337
|
+
|
|
1338
|
+
const scrubberPriceFormatter = useMemo(
|
|
862
1339
|
() =>
|
|
863
1340
|
new Intl.NumberFormat('en-US', {
|
|
864
1341
|
minimumFractionDigits: 2,
|
|
@@ -867,6 +1344,13 @@ function ForecastAssetPrice() {
|
|
|
867
1344
|
[],
|
|
868
1345
|
);
|
|
869
1346
|
|
|
1347
|
+
const formatPrice = useCallback(
|
|
1348
|
+
(price: number) => {
|
|
1349
|
+
return priceFormatter.format(price);
|
|
1350
|
+
},
|
|
1351
|
+
[priceFormatter],
|
|
1352
|
+
);
|
|
1353
|
+
|
|
870
1354
|
const formatDate = useCallback((date: Date) => {
|
|
871
1355
|
const dayOfWeek = date.toLocaleDateString('en-US', { weekday: 'short' });
|
|
872
1356
|
|
|
@@ -884,250 +1368,253 @@ function ForecastAssetPrice() {
|
|
|
884
1368
|
return `${dayOfWeek}, ${monthDay}, ${time}`;
|
|
885
1369
|
}, []);
|
|
886
1370
|
|
|
887
|
-
const forecastData = useMemo(() => {
|
|
888
|
-
if (historicalData.length === 0) return [];
|
|
889
|
-
const lastPoint = historicalData[historicalData.length - 1];
|
|
890
|
-
return generateForecastData(lastPoint.date, lastPoint.value, annualGrowthRate);
|
|
891
|
-
}, [generateForecastData, historicalData, annualGrowthRate]);
|
|
892
|
-
|
|
893
|
-
// Combine all data points with dates converted to timestamps for x-axis
|
|
894
|
-
const allDataPoints = useMemo(
|
|
895
|
-
() => [...historicalData, ...forecastData],
|
|
896
|
-
[historicalData, forecastData],
|
|
897
|
-
);
|
|
898
|
-
|
|
899
|
-
const historicalDataValues = useMemo(
|
|
900
|
-
() => historicalData.map((d) => d.value),
|
|
901
|
-
[historicalData],
|
|
902
|
-
);
|
|
903
|
-
|
|
904
|
-
const forecastDataValues = useMemo(
|
|
905
|
-
() => [...historicalData.map((d) => null), ...forecastData.map((d) => d.value)],
|
|
906
|
-
[historicalData, forecastData],
|
|
907
|
-
);
|
|
908
|
-
|
|
909
|
-
const xAxisData = useMemo(
|
|
910
|
-
() => allDataPoints.map((d) => d.date.getTime()),
|
|
911
|
-
[allDataPoints],
|
|
912
|
-
);
|
|
913
|
-
|
|
914
1371
|
const scrubberLabel = useCallback(
|
|
915
1372
|
(index: number) => {
|
|
916
|
-
const price =
|
|
917
|
-
const date = formatDate(
|
|
1373
|
+
const price = scrubberPriceFormatter.format(sparklineTimePeriodDataValues[index]);
|
|
1374
|
+
const date = formatDate(sparklineTimePeriodDataTimestamps[index]);
|
|
918
1375
|
return (
|
|
919
1376
|
<>
|
|
920
1377
|
<tspan style={{ fontWeight: 'bold' }}>{price} USD</tspan> {date}
|
|
921
1378
|
</>
|
|
922
1379
|
);
|
|
923
1380
|
},
|
|
924
|
-
[
|
|
1381
|
+
[
|
|
1382
|
+
scrubberPriceFormatter,
|
|
1383
|
+
sparklineTimePeriodDataValues,
|
|
1384
|
+
sparklineTimePeriodDataTimestamps,
|
|
1385
|
+
formatDate,
|
|
1386
|
+
],
|
|
925
1387
|
);
|
|
926
1388
|
|
|
927
|
-
const
|
|
1389
|
+
const chartAccessibilityLabel = `Bitcoin price chart for ${timePeriod.label} period. Current price: ${formatPrice(currentPrice)}`;
|
|
1390
|
+
|
|
1391
|
+
const scrubberAccessibilityLabel = useCallback(
|
|
928
1392
|
(index: number) => {
|
|
929
|
-
const price =
|
|
930
|
-
const date = formatDate(
|
|
1393
|
+
const price = scrubberPriceFormatter.format(sparklineTimePeriodDataValues[index]);
|
|
1394
|
+
const date = formatDate(sparklineTimePeriodDataTimestamps[index]);
|
|
931
1395
|
return `${price} USD ${date}`;
|
|
932
1396
|
},
|
|
933
|
-
[
|
|
1397
|
+
[
|
|
1398
|
+
scrubberPriceFormatter,
|
|
1399
|
+
sparklineTimePeriodDataValues,
|
|
1400
|
+
sparklineTimePeriodDataTimestamps,
|
|
1401
|
+
formatDate,
|
|
1402
|
+
],
|
|
934
1403
|
);
|
|
935
1404
|
|
|
936
1405
|
return (
|
|
937
|
-
<
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
</
|
|
1406
|
+
<VStack gap={2}>
|
|
1407
|
+
<SectionHeader
|
|
1408
|
+
balance={<Text font="title2">{formatPrice(currentPrice)}</Text>}
|
|
1409
|
+
end={
|
|
1410
|
+
<VStack justifyContent="center">
|
|
1411
|
+
<RemoteImage shape="circle" size="xl" source={assets.btc.imageUrl} />
|
|
1412
|
+
</VStack>
|
|
1413
|
+
}
|
|
1414
|
+
style={{ padding: 0 }}
|
|
1415
|
+
title={<Text font="title1">Bitcoin</Text>}
|
|
1416
|
+
/>
|
|
1417
|
+
<LineChart
|
|
1418
|
+
enableScrubbing
|
|
1419
|
+
showArea
|
|
1420
|
+
accessibilityLabel={chartAccessibilityLabel}
|
|
1421
|
+
areaType="dotted"
|
|
1422
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
1423
|
+
series={[
|
|
1424
|
+
{
|
|
1425
|
+
id: 'btc',
|
|
1426
|
+
data: sparklineTimePeriodDataValues,
|
|
1427
|
+
color: assets.btc.color,
|
|
1428
|
+
},
|
|
1429
|
+
]}
|
|
1430
|
+
style={{ outlineColor: assets.btc.color }}
|
|
1431
|
+
inset={{ top: 60 }}
|
|
1432
|
+
>
|
|
1433
|
+
<Scrubber
|
|
1434
|
+
idlePulse
|
|
1435
|
+
accessibilityLabel={scrubberAccessibilityLabel}
|
|
1436
|
+
label={scrubberLabel}
|
|
1437
|
+
labelElevated
|
|
1438
|
+
/>
|
|
1439
|
+
</LineChart>
|
|
1440
|
+
<PeriodSelector
|
|
1441
|
+
TabComponent={BTCTab}
|
|
1442
|
+
TabsActiveIndicatorComponent={BTCActiveIndicator}
|
|
1443
|
+
activeTab={timePeriod}
|
|
1444
|
+
onChange={onPeriodChange}
|
|
1445
|
+
tabs={tabs}
|
|
1446
|
+
/>
|
|
1447
|
+
</VStack>
|
|
979
1448
|
);
|
|
980
1449
|
});
|
|
981
1450
|
|
|
982
|
-
return <
|
|
983
|
-
}
|
|
1451
|
+
return <AssetPriceDotted />;
|
|
1452
|
+
}
|
|
984
1453
|
```
|
|
985
1454
|
|
|
986
|
-
####
|
|
1455
|
+
#### Monotone Asset Price
|
|
1456
|
+
|
|
1457
|
+
You can adjust [YAxis](/components/graphs/YAxis) and [Scrubber](/components/graphs/Scrubber) to have a chart where the y-axis is overlaid and the beacon is inverted in style.
|
|
987
1458
|
|
|
988
1459
|
```jsx live
|
|
989
|
-
function
|
|
990
|
-
const
|
|
1460
|
+
function MonotoneAssetPrice() {
|
|
1461
|
+
const prices = sparklineInteractiveData.hour;
|
|
991
1462
|
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
{
|
|
1014
|
-
date: new Date('2022-01-10'),
|
|
1015
|
-
availability: 86,
|
|
1463
|
+
const priceFormatter = useMemo(
|
|
1464
|
+
() =>
|
|
1465
|
+
new Intl.NumberFormat('en-US', {
|
|
1466
|
+
style: 'currency',
|
|
1467
|
+
currency: 'USD',
|
|
1468
|
+
}),
|
|
1469
|
+
[],
|
|
1470
|
+
);
|
|
1471
|
+
|
|
1472
|
+
const scrubberPriceFormatter = useMemo(
|
|
1473
|
+
() =>
|
|
1474
|
+
new Intl.NumberFormat('en-US', {
|
|
1475
|
+
minimumFractionDigits: 2,
|
|
1476
|
+
maximumFractionDigits: 2,
|
|
1477
|
+
}),
|
|
1478
|
+
[],
|
|
1479
|
+
);
|
|
1480
|
+
|
|
1481
|
+
const formatPrice = useCallback(
|
|
1482
|
+
(price: number) => {
|
|
1483
|
+
return priceFormatter.format(price);
|
|
1016
1484
|
},
|
|
1017
|
-
|
|
1485
|
+
[priceFormatter],
|
|
1486
|
+
);
|
|
1487
|
+
|
|
1488
|
+
const CustomYAxisTickLabel = useCallback(
|
|
1489
|
+
(props) => (
|
|
1490
|
+
<DefaultAxisTickLabel
|
|
1491
|
+
{...props}
|
|
1492
|
+
dx={4}
|
|
1493
|
+
dy={-12}
|
|
1494
|
+
horizontalAlignment="left"
|
|
1495
|
+
/>
|
|
1496
|
+
),
|
|
1497
|
+
[],
|
|
1498
|
+
);
|
|
1499
|
+
|
|
1500
|
+
const formatDate = useCallback((date: Date) => {
|
|
1501
|
+
const dayOfWeek = date.toLocaleDateString('en-US', { weekday: 'short' });
|
|
1018
1502
|
|
|
1019
|
-
|
|
1020
|
-
if (scrubIndex === undefined) return undefined;
|
|
1021
|
-
const event = availabilityEvents[scrubIndex];
|
|
1022
|
-
const formattedDate = event.date.toLocaleDateString('en-US', {
|
|
1023
|
-
weekday: 'short',
|
|
1503
|
+
const monthDay = date.toLocaleDateString('en-US', {
|
|
1024
1504
|
month: 'short',
|
|
1025
1505
|
day: 'numeric',
|
|
1026
|
-
year: 'numeric',
|
|
1027
1506
|
});
|
|
1028
|
-
const status =
|
|
1029
|
-
event.availability >= 90 ? 'Good' : event.availability >= 85 ? 'Warning' : 'Critical';
|
|
1030
|
-
return `${formattedDate}: Availability ${event.availability}% - Status: ${status}`;
|
|
1031
|
-
}, [scrubIndex, availabilityEvents]);
|
|
1032
1507
|
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1508
|
+
const time = date.toLocaleTimeString('en-US', {
|
|
1509
|
+
hour: 'numeric',
|
|
1510
|
+
minute: '2-digit',
|
|
1511
|
+
hour12: true,
|
|
1512
|
+
});
|
|
1513
|
+
|
|
1514
|
+
return `${dayOfWeek}, ${monthDay}, ${time}`;
|
|
1515
|
+
}, []);
|
|
1516
|
+
|
|
1517
|
+
const scrubberLabel = useCallback(
|
|
1518
|
+
(index: number) => {
|
|
1519
|
+
const price = scrubberPriceFormatter.format(prices[index].value);
|
|
1520
|
+
const date = formatDate(prices[index].date);
|
|
1521
|
+
return (
|
|
1522
|
+
<>
|
|
1523
|
+
<tspan style={{ fontWeight: 'bold' }}>{price} USD</tspan> {date}
|
|
1524
|
+
</>
|
|
1525
|
+
);
|
|
1526
|
+
},
|
|
1527
|
+
[scrubberPriceFormatter, prices, formatDate],
|
|
1528
|
+
);
|
|
1037
1529
|
|
|
1038
|
-
|
|
1530
|
+
const CustomScrubberBeacon = memo(({ dataX, dataY, seriesId, isIdle }: ScrubberBeaconProps) => {
|
|
1531
|
+
const { getSeries, getXScale, getYScale } = useCartesianChartContext();
|
|
1532
|
+
const targetSeries = getSeries(seriesId);
|
|
1533
|
+
const xScale = getXScale();
|
|
1534
|
+
const yScale = getYScale(targetSeries?.yAxisId);
|
|
1039
1535
|
|
|
1040
|
-
const
|
|
1041
|
-
|
|
1042
|
-
|
|
1536
|
+
const pixelCoordinate = useMemo(() => {
|
|
1537
|
+
if (!xScale || !yScale) return;
|
|
1538
|
+
return projectPoint({ x: dataX, y: dataY, xScale, yScale });
|
|
1539
|
+
}, [dataX, dataY, xScale, yScale]);
|
|
1043
1540
|
|
|
1044
|
-
|
|
1045
|
-
const yellowThresholdY = yScale(yellowThresholdPercentage) ?? 0;
|
|
1046
|
-
const greenThresholdY = yScale(greenThresholdPercentage) ?? 0;
|
|
1047
|
-
const minY = yScale(rangeMax) ?? 0; // Top of chart (max value)
|
|
1048
|
-
const maxY = yScale(rangeMin) ?? drawingArea.height; // Bottom of chart (min value)
|
|
1541
|
+
if (!pixelCoordinate) return;
|
|
1049
1542
|
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1543
|
+
if (isIdle) {
|
|
1544
|
+
return (
|
|
1545
|
+
<m.circle
|
|
1546
|
+
animate={{ cx: pixelCoordinate.x, cy: pixelCoordinate.y }}
|
|
1547
|
+
cx={pixelCoordinate.x}
|
|
1548
|
+
cy={pixelCoordinate.y}
|
|
1549
|
+
fill="var(--color-bg)"
|
|
1550
|
+
r={5}
|
|
1551
|
+
stroke="var(--color-fg)"
|
|
1552
|
+
strokeWidth={3}
|
|
1553
|
+
transition={defaultTransition}
|
|
1554
|
+
/>
|
|
1555
|
+
);
|
|
1556
|
+
}
|
|
1053
1557
|
|
|
1054
1558
|
return (
|
|
1055
|
-
<
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
>
|
|
1064
|
-
<stop offset="0%" stopColor="var(--color-fgPositive)" />
|
|
1065
|
-
<stop offset={`${greenThreshold}%`} stopColor="var(--color-fgPositive)" />
|
|
1066
|
-
<stop offset={`${greenThreshold}%`} stopColor="var(--color-fgWarning)" />
|
|
1067
|
-
<stop offset={`${yellowThreshold}%`} stopColor="var(--color-fgWarning)" />
|
|
1068
|
-
<stop offset={`${yellowThreshold}%`} stopColor="var(--color-fgNegative)" />
|
|
1069
|
-
<stop offset="100%" stopColor="var(--color-fgNegative)" />
|
|
1070
|
-
</linearGradient>
|
|
1071
|
-
</defs>
|
|
1559
|
+
<circle
|
|
1560
|
+
cx={pixelCoordinate.x}
|
|
1561
|
+
cy={pixelCoordinate.y}
|
|
1562
|
+
fill="var(--color-bg)"
|
|
1563
|
+
r={5}
|
|
1564
|
+
stroke="var(--color-fg)"
|
|
1565
|
+
strokeWidth={3}
|
|
1566
|
+
/>
|
|
1072
1567
|
);
|
|
1073
1568
|
});
|
|
1074
1569
|
|
|
1075
1570
|
return (
|
|
1076
|
-
<
|
|
1571
|
+
<LineChart
|
|
1077
1572
|
enableScrubbing
|
|
1078
|
-
|
|
1079
|
-
height={{ base:
|
|
1573
|
+
showYAxis
|
|
1574
|
+
height={{ base: 200, tablet: 250, desktop: 300 }}
|
|
1575
|
+
inset={{ top: 64 }}
|
|
1080
1576
|
series={[
|
|
1081
1577
|
{
|
|
1082
|
-
id: '
|
|
1083
|
-
data:
|
|
1084
|
-
color: '
|
|
1578
|
+
id: 'btc',
|
|
1579
|
+
data: prices.map((price) => price.value),
|
|
1580
|
+
color: 'var(--color-fg)',
|
|
1581
|
+
gradient: {
|
|
1582
|
+
axis: 'x',
|
|
1583
|
+
stops: ({ min, max }) => [
|
|
1584
|
+
{ offset: min, color: 'var(--color-fg)', opacity: 0 },
|
|
1585
|
+
{ offset: 32, color: 'var(--color-fg)', opacity: 1 },
|
|
1586
|
+
],
|
|
1587
|
+
},
|
|
1085
1588
|
},
|
|
1086
1589
|
]}
|
|
1590
|
+
style={{ outlineColor: 'var(--color-fg)' }}
|
|
1087
1591
|
xAxis={{
|
|
1088
|
-
|
|
1592
|
+
range: ({ min, max }) => ({ min: 96, max: max }),
|
|
1089
1593
|
}}
|
|
1090
1594
|
yAxis={{
|
|
1091
|
-
|
|
1595
|
+
position: 'left',
|
|
1596
|
+
width: 0,
|
|
1597
|
+
showGrid: true,
|
|
1598
|
+
tickLabelFormatter: formatPrice,
|
|
1599
|
+
TickLabelComponent: CustomYAxisTickLabel,
|
|
1092
1600
|
}}
|
|
1093
|
-
padding={{ left: 2, right: 2 }}
|
|
1094
|
-
accessibilityLabel={accessibilityLabel}
|
|
1095
1601
|
>
|
|
1096
|
-
<
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
/>
|
|
1103
|
-
<YAxis
|
|
1104
|
-
showGrid
|
|
1105
|
-
showLine
|
|
1106
|
-
showTickMarks
|
|
1107
|
-
position="left"
|
|
1108
|
-
tickLabelFormatter={(value) => `${value}%`}
|
|
1109
|
-
/>
|
|
1110
|
-
<Line
|
|
1111
|
-
curve="stepAfter"
|
|
1112
|
-
renderPoints={() => ({
|
|
1113
|
-
fill: 'var(--color-bg)',
|
|
1114
|
-
stroke: 'url(#availabilityGradient)',
|
|
1115
|
-
strokeWidth: 2,
|
|
1116
|
-
})}
|
|
1117
|
-
seriesId="availability"
|
|
1602
|
+
<Scrubber
|
|
1603
|
+
hideOverlay
|
|
1604
|
+
BeaconComponent={CustomScrubberBeacon}
|
|
1605
|
+
LineComponent={SolidLine}
|
|
1606
|
+
label={scrubberLabel}
|
|
1607
|
+
labelElevated
|
|
1118
1608
|
/>
|
|
1119
|
-
|
|
1120
|
-
</CartesianChart>
|
|
1609
|
+
</LineChart>
|
|
1121
1610
|
);
|
|
1122
1611
|
}
|
|
1123
1612
|
```
|
|
1124
1613
|
|
|
1125
1614
|
#### Asset Price Widget
|
|
1126
1615
|
|
|
1127
|
-
You can coordinate LineChart with custom styles to create a custom card that shows the latest price and percent change.
|
|
1128
|
-
|
|
1129
1616
|
```jsx live
|
|
1130
|
-
function
|
|
1617
|
+
function AssetPriceWidget() {
|
|
1131
1618
|
const { isPhone } = useBreakpoints();
|
|
1132
1619
|
const prices = [...btcCandles].reverse().map((candle) => parseFloat(candle.close));
|
|
1133
1620
|
const latestPrice = prices[prices.length - 1];
|
|
@@ -1149,35 +1636,48 @@ function BitcoinChartWithScrubberBeacon() {
|
|
|
1149
1636
|
|
|
1150
1637
|
const percentChange = (latestPrice - prices[0]) / prices[0];
|
|
1151
1638
|
|
|
1639
|
+
const chartAccessibilityLabel = `Bitcoin price chart. Current price: ${formatPrice(latestPrice)}. Change: ${formatPercentChange(percentChange)}`;
|
|
1640
|
+
|
|
1641
|
+
const scrubberAccessibilityLabel = useCallback(
|
|
1642
|
+
(index: number) => {
|
|
1643
|
+
return `Bitcoin price at position ${index + 1}: ${formatPrice(prices[index])}`;
|
|
1644
|
+
},
|
|
1645
|
+
[prices],
|
|
1646
|
+
);
|
|
1647
|
+
|
|
1152
1648
|
return (
|
|
1153
1649
|
<VStack
|
|
1154
|
-
style={{
|
|
1155
|
-
background:
|
|
1156
|
-
'linear-gradient(0deg, rgba(0, 0, 0, 0.80) 0%, rgba(0, 0, 0, 0.80) 100%), #ED702F',
|
|
1157
|
-
}}
|
|
1158
1650
|
borderRadius={300}
|
|
1159
1651
|
gap={2}
|
|
1652
|
+
overflow="hidden"
|
|
1160
1653
|
padding={2}
|
|
1161
1654
|
paddingBottom={0}
|
|
1162
|
-
|
|
1655
|
+
style={{
|
|
1656
|
+
background:
|
|
1657
|
+
'linear-gradient(0deg, rgba(0, 0, 0, 0.80) 0%, rgba(0, 0, 0, 0.80) 100%), #ED702F',
|
|
1658
|
+
}}
|
|
1163
1659
|
>
|
|
1164
|
-
<HStack gap={2}
|
|
1165
|
-
<RemoteImage source={assets.btc.imageUrl}
|
|
1660
|
+
<HStack alignItems="center" gap={2}>
|
|
1661
|
+
<RemoteImage aria-hidden shape="circle" size="xxl" source={assets.btc.imageUrl} />
|
|
1166
1662
|
{!isPhone && (
|
|
1167
|
-
<VStack gap={0.25}
|
|
1168
|
-
<Text font="title1" style={{ color: 'white' }}
|
|
1663
|
+
<VStack flexGrow={1} gap={0.25}>
|
|
1664
|
+
<Text aria-hidden font="title1" style={{ color: 'white' }}>
|
|
1169
1665
|
BTC
|
|
1170
1666
|
</Text>
|
|
1171
|
-
<Text
|
|
1667
|
+
<Text color="fgMuted" font="label1">
|
|
1172
1668
|
Bitcoin
|
|
1173
1669
|
</Text>
|
|
1174
1670
|
</VStack>
|
|
1175
1671
|
)}
|
|
1176
|
-
<VStack
|
|
1672
|
+
<VStack alignItems="flex-end" flexGrow={isPhone ? 1 : undefined} gap={0.25}>
|
|
1177
1673
|
<Text font="title1" style={{ color: 'white' }}>
|
|
1178
1674
|
{formatPrice(latestPrice)}
|
|
1179
1675
|
</Text>
|
|
1180
|
-
<Text
|
|
1676
|
+
<Text
|
|
1677
|
+
accessibilityLabel={`Up ${formatPercentChange(percentChange)}`}
|
|
1678
|
+
color="fgPositive"
|
|
1679
|
+
font="label1"
|
|
1680
|
+
>
|
|
1181
1681
|
+{formatPercentChange(percentChange)}
|
|
1182
1682
|
</Text>
|
|
1183
1683
|
</VStack>
|
|
@@ -1189,6 +1689,9 @@ function BitcoinChartWithScrubberBeacon() {
|
|
|
1189
1689
|
}}
|
|
1190
1690
|
>
|
|
1191
1691
|
<LineChart
|
|
1692
|
+
showArea
|
|
1693
|
+
accessibilityLabel={chartAccessibilityLabel}
|
|
1694
|
+
height={92}
|
|
1192
1695
|
inset={{ left: 0, right: 18, bottom: 0, top: 0 }}
|
|
1193
1696
|
series={[
|
|
1194
1697
|
{
|
|
@@ -1197,16 +1700,234 @@ function BitcoinChartWithScrubberBeacon() {
|
|
|
1197
1700
|
color: assets.btc.color,
|
|
1198
1701
|
},
|
|
1199
1702
|
]}
|
|
1200
|
-
showArea
|
|
1201
1703
|
width="100%"
|
|
1202
|
-
height={92}
|
|
1203
1704
|
>
|
|
1204
|
-
<Scrubber
|
|
1705
|
+
<Scrubber
|
|
1706
|
+
idlePulse
|
|
1707
|
+
accessibilityLabel={scrubberAccessibilityLabel}
|
|
1708
|
+
styles={{ beacon: { stroke: 'white' } }}
|
|
1709
|
+
/>
|
|
1205
1710
|
</LineChart>
|
|
1206
1711
|
</div>
|
|
1207
1712
|
</VStack>
|
|
1208
1713
|
);
|
|
1209
|
-
}
|
|
1714
|
+
}
|
|
1715
|
+
```
|
|
1716
|
+
|
|
1717
|
+
#### Service Availability
|
|
1718
|
+
|
|
1719
|
+
You can have irregular data points by passing in `data` to `xAxis`.
|
|
1720
|
+
|
|
1721
|
+
```jsx live
|
|
1722
|
+
function ServiceAvailability() {
|
|
1723
|
+
const availabilityEvents = useMemo(
|
|
1724
|
+
() => [
|
|
1725
|
+
{ date: new Date('2022-01-01'), availability: 79 },
|
|
1726
|
+
{ date: new Date('2022-01-03'), availability: 81 },
|
|
1727
|
+
{ date: new Date('2022-01-04'), availability: 82 },
|
|
1728
|
+
{ date: new Date('2022-01-06'), availability: 91 },
|
|
1729
|
+
{ date: new Date('2022-01-07'), availability: 92 },
|
|
1730
|
+
{ date: new Date('2022-01-10'), availability: 86 },
|
|
1731
|
+
],
|
|
1732
|
+
[],
|
|
1733
|
+
);
|
|
1734
|
+
|
|
1735
|
+
const chartAccessibilityLabel = `Availability chart showing ${availabilityEvents.length} data points over time`;
|
|
1736
|
+
|
|
1737
|
+
const scrubberAccessibilityLabel = useCallback(
|
|
1738
|
+
(index: number) => {
|
|
1739
|
+
const event = availabilityEvents[index];
|
|
1740
|
+
const formattedDate = event.date.toLocaleDateString('en-US', {
|
|
1741
|
+
weekday: 'short',
|
|
1742
|
+
month: 'short',
|
|
1743
|
+
day: 'numeric',
|
|
1744
|
+
year: 'numeric',
|
|
1745
|
+
});
|
|
1746
|
+
const status =
|
|
1747
|
+
event.availability >= 90 ? 'Good' : event.availability >= 85 ? 'Warning' : 'Critical';
|
|
1748
|
+
return `${formattedDate}: Availability ${event.availability}% - Status: ${status}`;
|
|
1749
|
+
},
|
|
1750
|
+
[availabilityEvents],
|
|
1751
|
+
);
|
|
1752
|
+
|
|
1753
|
+
return (
|
|
1754
|
+
<CartesianChart
|
|
1755
|
+
enableScrubbing
|
|
1756
|
+
accessibilityLabel={chartAccessibilityLabel}
|
|
1757
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
1758
|
+
series={[
|
|
1759
|
+
{
|
|
1760
|
+
id: 'availability',
|
|
1761
|
+
data: availabilityEvents.map((event) => event.availability),
|
|
1762
|
+
gradient: {
|
|
1763
|
+
stops: ({ min, max }) => [
|
|
1764
|
+
{ offset: min, color: 'var(--color-fgNegative)' },
|
|
1765
|
+
{ offset: 85, color: 'var(--color-fgNegative)' },
|
|
1766
|
+
{ offset: 85, color: 'var(--color-fgWarning)' },
|
|
1767
|
+
{ offset: 90, color: 'var(--color-fgWarning)' },
|
|
1768
|
+
{ offset: 90, color: 'var(--color-fgPositive)' },
|
|
1769
|
+
{ offset: max, color: 'var(--color-fgPositive)' },
|
|
1770
|
+
],
|
|
1771
|
+
},
|
|
1772
|
+
},
|
|
1773
|
+
]}
|
|
1774
|
+
xAxis={{
|
|
1775
|
+
data: availabilityEvents.map((event) => event.date.getTime()),
|
|
1776
|
+
}}
|
|
1777
|
+
yAxis={{
|
|
1778
|
+
domain: ({ min, max }) => ({ min: Math.max(min - 2, 0), max: Math.min(max + 2, 100) }),
|
|
1779
|
+
}}
|
|
1780
|
+
>
|
|
1781
|
+
<XAxis
|
|
1782
|
+
showGrid
|
|
1783
|
+
showLine
|
|
1784
|
+
showTickMarks
|
|
1785
|
+
tickLabelFormatter={(value) => new Date(value).toLocaleDateString()}
|
|
1786
|
+
/>
|
|
1787
|
+
<YAxis
|
|
1788
|
+
showGrid
|
|
1789
|
+
showLine
|
|
1790
|
+
showTickMarks
|
|
1791
|
+
position="left"
|
|
1792
|
+
tickLabelFormatter={(value) => `${value}%`}
|
|
1793
|
+
/>
|
|
1794
|
+
<Line
|
|
1795
|
+
curve="stepAfter"
|
|
1796
|
+
points={(props) => ({
|
|
1797
|
+
...props,
|
|
1798
|
+
fill: 'var(--color-bg)',
|
|
1799
|
+
stroke: props.fill,
|
|
1800
|
+
})}
|
|
1801
|
+
seriesId="availability"
|
|
1802
|
+
/>
|
|
1803
|
+
<Scrubber hideOverlay accessibilityLabel={scrubberAccessibilityLabel} />
|
|
1804
|
+
</CartesianChart>
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1807
|
+
```
|
|
1808
|
+
|
|
1809
|
+
#### Forecast Asset Price
|
|
1810
|
+
|
|
1811
|
+
You can combine multiple lines within a series to change styles dynamically.
|
|
1812
|
+
|
|
1813
|
+
```jsx live
|
|
1814
|
+
function ForecastAssetPrice() {
|
|
1815
|
+
const startYear = 2020;
|
|
1816
|
+
const data = [50, 45, 47, 46, 54, 54, 60, 61, 63, 66, 70];
|
|
1817
|
+
const currentIndex = 6;
|
|
1818
|
+
|
|
1819
|
+
const strokeWidth = 3;
|
|
1820
|
+
// To prevent cutting off the edge of our lines
|
|
1821
|
+
const clipOffset = strokeWidth;
|
|
1822
|
+
|
|
1823
|
+
const axisFormatter = useCallback(
|
|
1824
|
+
(dataIndex: number) => {
|
|
1825
|
+
return startYear + dataIndex;
|
|
1826
|
+
},
|
|
1827
|
+
[startYear],
|
|
1828
|
+
);
|
|
1829
|
+
|
|
1830
|
+
const HistoricalLineComponent = memo((props: SolidLineProps) => {
|
|
1831
|
+
const { drawingArea, getXScale } = useCartesianChartContext();
|
|
1832
|
+
const xScale = getXScale();
|
|
1833
|
+
|
|
1834
|
+
if (!xScale || !drawingArea) return;
|
|
1835
|
+
|
|
1836
|
+
const currentX = xScale(currentIndex);
|
|
1837
|
+
|
|
1838
|
+
if (currentX === undefined) return;
|
|
1839
|
+
|
|
1840
|
+
return (
|
|
1841
|
+
<>
|
|
1842
|
+
<defs>
|
|
1843
|
+
<clipPath id="historical-clip">
|
|
1844
|
+
<rect
|
|
1845
|
+
height={drawingArea.height + clipOffset * 2}
|
|
1846
|
+
width={currentX + clipOffset - drawingArea.x}
|
|
1847
|
+
x={drawingArea.x - clipOffset}
|
|
1848
|
+
y={drawingArea.y - clipOffset}
|
|
1849
|
+
/>
|
|
1850
|
+
</clipPath>
|
|
1851
|
+
</defs>
|
|
1852
|
+
<g clipPath="url(#historical-clip)">
|
|
1853
|
+
<SolidLine strokeWidth={strokeWidth} {...props} />
|
|
1854
|
+
</g>
|
|
1855
|
+
</>
|
|
1856
|
+
);
|
|
1857
|
+
});
|
|
1858
|
+
|
|
1859
|
+
// Since the solid and dotted line have different curves,
|
|
1860
|
+
// we need two separate line components. Otherwise we could
|
|
1861
|
+
// have one line component with SolidLine and DottedLine inside
|
|
1862
|
+
// of it and two clipPaths.
|
|
1863
|
+
const ForecastLineComponent = memo((props: DottedLineProps) => {
|
|
1864
|
+
const { drawingArea, getXScale } = useCartesianChartContext();
|
|
1865
|
+
const xScale = getXScale();
|
|
1866
|
+
|
|
1867
|
+
if (!xScale || !drawingArea) return;
|
|
1868
|
+
|
|
1869
|
+
const currentX = xScale(currentIndex);
|
|
1870
|
+
|
|
1871
|
+
if (currentX === undefined) return;
|
|
1872
|
+
|
|
1873
|
+
return (
|
|
1874
|
+
<>
|
|
1875
|
+
<defs>
|
|
1876
|
+
<clipPath id="forecast-clip">
|
|
1877
|
+
<rect
|
|
1878
|
+
height={drawingArea.height + clipOffset * 2}
|
|
1879
|
+
width={drawingArea.x + drawingArea.width - currentX + clipOffset * 2}
|
|
1880
|
+
x={currentX}
|
|
1881
|
+
y={drawingArea.y - clipOffset}
|
|
1882
|
+
/>
|
|
1883
|
+
</clipPath>
|
|
1884
|
+
</defs>
|
|
1885
|
+
<g clipPath="url(#forecast-clip)">
|
|
1886
|
+
<DottedLine
|
|
1887
|
+
strokeDasharray={`0 ${strokeWidth * 2}`}
|
|
1888
|
+
strokeWidth={strokeWidth}
|
|
1889
|
+
{...props}
|
|
1890
|
+
/>
|
|
1891
|
+
</g>
|
|
1892
|
+
</>
|
|
1893
|
+
);
|
|
1894
|
+
});
|
|
1895
|
+
|
|
1896
|
+
const CustomScrubber = memo(() => {
|
|
1897
|
+
const { scrubberPosition } = useScrubberContext();
|
|
1898
|
+
const isScrubbing = scrubberPosition !== undefined;
|
|
1899
|
+
// We need a fade in animation for the Scrubber
|
|
1900
|
+
return (
|
|
1901
|
+
<m.g
|
|
1902
|
+
animate={{ opacity: 1 }}
|
|
1903
|
+
initial={{ opacity: 0 }}
|
|
1904
|
+
transition={{ duration: 0.15, delay: 0.35 }}
|
|
1905
|
+
>
|
|
1906
|
+
<g style={{ opacity: isScrubbing ? 1 : 0 }}>
|
|
1907
|
+
<Scrubber hideOverlay />
|
|
1908
|
+
</g>
|
|
1909
|
+
<g style={{ opacity: isScrubbing ? 0 : 1 }}>
|
|
1910
|
+
<DefaultScrubberBeacon dataX={currentIndex} dataY={data[currentIndex]} seriesId="price" />
|
|
1911
|
+
</g>
|
|
1912
|
+
</m.g>
|
|
1913
|
+
);
|
|
1914
|
+
});
|
|
1915
|
+
|
|
1916
|
+
return (
|
|
1917
|
+
<CartesianChart
|
|
1918
|
+
enableScrubbing
|
|
1919
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
1920
|
+
maxWidth={512}
|
|
1921
|
+
series={[{ id: 'price', data, color: assets.btc.color }]}
|
|
1922
|
+
style={{ margin: '0 auto' }}
|
|
1923
|
+
>
|
|
1924
|
+
<Line LineComponent={HistoricalLineComponent} curve="linear" seriesId="price" />
|
|
1925
|
+
<Line LineComponent={ForecastLineComponent} curve="monotone" seriesId="price" type="dotted" />
|
|
1926
|
+
<XAxis position="bottom" requestedTickCount={3} tickLabelFormatter={axisFormatter} />
|
|
1927
|
+
<CustomScrubber />
|
|
1928
|
+
</CartesianChart>
|
|
1929
|
+
);
|
|
1930
|
+
}
|
|
1210
1931
|
```
|
|
1211
1932
|
|
|
1212
1933
|
## Props
|
|
@@ -1215,33 +1936,14 @@ function BitcoinChartWithScrubberBeacon() {
|
|
|
1215
1936
|
| --- | --- | --- | --- | --- |
|
|
1216
1937
|
| `AreaComponent` | `AreaComponent` | No | `-` | Custom component to render line area fill. |
|
|
1217
1938
|
| `LineComponent` | `LineComponent` | No | `-` | Component to render the line. Takes precedence over the type prop if provided. |
|
|
1218
|
-
| `
|
|
1219
|
-
| `
|
|
1220
|
-
| `
|
|
1221
|
-
| `alignContent` | `ResponsiveProp<center \| end \| normal \| start \| flex-start \| flex-end \| space-between \| space-around \| space-evenly \| stretch \| baseline \| first baseline \| last baseline>` | No | `-` | - |
|
|
1222
|
-
| `alignItems` | `ResponsiveProp<center \| end \| normal \| start \| flex-start \| flex-end \| stretch \| baseline \| first baseline \| last baseline \| self-start \| self-end>` | No | `-` | - |
|
|
1223
|
-
| `alignSelf` | `ResponsiveProp<center \| end \| normal \| auto \| start \| flex-start \| flex-end \| stretch \| baseline \| first baseline \| last baseline \| self-start \| self-end>` | No | `-` | - |
|
|
1224
|
-
| `alignmentBaseline` | `alphabetic \| hanging \| ideographic \| mathematical \| inherit \| auto \| baseline \| before-edge \| text-before-edge \| middle \| central \| after-edge \| text-after-edge` | No | `-` | - |
|
|
1225
|
-
| `allowReorder` | `no \| yes` | No | `-` | - |
|
|
1226
|
-
| `alphabetic` | `string \| number` | No | `-` | - |
|
|
1227
|
-
| `amplitude` | `string \| number` | No | `-` | - |
|
|
1939
|
+
| `alignContent` | `ResponsiveProp<center \| normal \| start \| end \| flex-start \| flex-end \| space-between \| space-around \| space-evenly \| stretch \| baseline \| first baseline \| last baseline>` | No | `-` | - |
|
|
1940
|
+
| `alignItems` | `ResponsiveProp<center \| normal \| start \| end \| flex-start \| flex-end \| stretch \| baseline \| first baseline \| last baseline \| self-start \| self-end>` | No | `-` | - |
|
|
1941
|
+
| `alignSelf` | `ResponsiveProp<center \| auto \| normal \| start \| end \| flex-start \| flex-end \| stretch \| baseline \| first baseline \| last baseline \| self-start \| self-end>` | No | `-` | - |
|
|
1228
1942
|
| `animate` | `boolean` | No | `true` | Whether to animate the chart. |
|
|
1229
|
-
| `arabicForm` | `initial \| medial \| terminal \| isolated` | No | `-` | - |
|
|
1230
1943
|
| `areaType` | `dotted \| solid \| gradient` | No | `'gradient'` | The type of area fill to add to the line. |
|
|
1231
|
-
| `as` | `
|
|
1232
|
-
| `
|
|
1233
|
-
| `aspectRatio` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - |
|
|
1234
|
-
| `attributeName` | `string` | No | `-` | - |
|
|
1235
|
-
| `attributeType` | `string` | No | `-` | - |
|
|
1236
|
-
| `autoReverse` | `false \| true \| true \| false` | No | `-` | - |
|
|
1237
|
-
| `azimuth` | `string \| number` | No | `-` | - |
|
|
1944
|
+
| `as` | `div` | No | `-` | - |
|
|
1945
|
+
| `aspectRatio` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1238
1946
|
| `background` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - |
|
|
1239
|
-
| `baseFrequency` | `string \| number` | No | `-` | - |
|
|
1240
|
-
| `baseProfile` | `string \| number` | No | `-` | - |
|
|
1241
|
-
| `baselineShift` | `string \| number` | No | `-` | - |
|
|
1242
|
-
| `bbox` | `string \| number` | No | `-` | - |
|
|
1243
|
-
| `begin` | `string \| number` | No | `-` | - |
|
|
1244
|
-
| `bias` | `string \| number` | No | `-` | - |
|
|
1245
1947
|
| `borderBottomLeftRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - |
|
|
1246
1948
|
| `borderBottomRightRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - |
|
|
1247
1949
|
| `borderBottomWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - |
|
|
@@ -1261,316 +1963,96 @@ function BitcoinChartWithScrubberBeacon() {
|
|
|
1261
1963
|
| `borderedTop` | `boolean` | No | `-` | Add a border to the top side of the box. |
|
|
1262
1964
|
| `borderedVertical` | `boolean` | No | `-` | Add a border to the top and bottom sides of the box. |
|
|
1263
1965
|
| `bottom` | `ResponsiveProp<Bottom<string \| number>>` | No | `-` | - |
|
|
1264
|
-
| `
|
|
1265
|
-
| `calcMode` | `string \| number` | No | `-` | - |
|
|
1266
|
-
| `capHeight` | `string \| number` | No | `-` | - |
|
|
1267
|
-
| `className` | `string` | No | `-` | - |
|
|
1268
|
-
| `clip` | `string \| number` | No | `-` | - |
|
|
1269
|
-
| `clipPath` | `string` | No | `-` | - |
|
|
1270
|
-
| `clipPathUnits` | `string \| number` | No | `-` | - |
|
|
1271
|
-
| `clipRule` | `string \| number` | No | `-` | - |
|
|
1966
|
+
| `classNames` | `{ root?: string; chart?: string \| undefined; } \| undefined` | No | `-` | Custom class names for the component. |
|
|
1272
1967
|
| `color` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - |
|
|
1273
|
-
| `
|
|
1274
|
-
| `
|
|
1275
|
-
| `
|
|
1276
|
-
| `colorRendering` | `string \| number` | No | `-` | - |
|
|
1277
|
-
| `columnGap` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1278
|
-
| `contentScriptType` | `string \| number` | No | `-` | - |
|
|
1279
|
-
| `contentStyleType` | `string \| number` | No | `-` | - |
|
|
1280
|
-
| `crossOrigin` | ` \| anonymous \| use-credentials` | No | `-` | - |
|
|
1281
|
-
| `cursor` | `string \| number` | No | `-` | - |
|
|
1282
|
-
| `curve` | `bump \| catmullRom \| linear \| linearClosed \| monotone \| natural \| step \| stepBefore \| stepAfter` | No | `'linear'` | The curve interpolation method to use for the line. |
|
|
1283
|
-
| `cx` | `string \| number` | No | `-` | - |
|
|
1284
|
-
| `cy` | `string \| number` | No | `-` | - |
|
|
1285
|
-
| `d` | `string` | No | `-` | - |
|
|
1968
|
+
| `columnGap` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
1969
|
+
| `connectNulls` | `boolean` | No | `-` | When true, the area is connected across null values. |
|
|
1970
|
+
| `curve` | `bump \| catmullRom \| linear \| linearClosed \| monotone \| natural \| step \| stepBefore \| stepAfter` | No | `'bump'` | The curve interpolation method to use for the line. |
|
|
1286
1971
|
| `dangerouslySetBackground` | `string` | No | `-` | - |
|
|
1287
|
-
| `
|
|
1288
|
-
| `descent` | `string \| number` | No | `-` | - |
|
|
1289
|
-
| `diffuseConstant` | `string \| number` | No | `-` | - |
|
|
1290
|
-
| `direction` | `string \| number` | No | `-` | - |
|
|
1291
|
-
| `display` | `ResponsiveProp<grid \| revert \| none \| block \| inline \| inline-block \| flex \| inline-flex \| inline-grid \| contents \| flow-root \| list-item>` | No | `-` | - |
|
|
1292
|
-
| `divisor` | `string \| number` | No | `-` | - |
|
|
1293
|
-
| `dominantBaseline` | `string \| number` | No | `-` | - |
|
|
1294
|
-
| `dur` | `string \| number` | No | `-` | - |
|
|
1295
|
-
| `dx` | `string \| number` | No | `-` | - |
|
|
1296
|
-
| `dy` | `string \| number` | No | `-` | - |
|
|
1297
|
-
| `edgeMode` | `string \| number` | No | `-` | - |
|
|
1972
|
+
| `display` | `ResponsiveProp<grid \| none \| block \| inline \| inline-block \| flex \| inline-flex \| inline-grid \| contents \| flow-root \| revert \| list-item>` | No | `-` | - |
|
|
1298
1973
|
| `elevation` | `0 \| 1 \| 2` | No | `-` | - |
|
|
1299
|
-
| `enableBackground` | `string \| number` | No | `-` | - |
|
|
1300
1974
|
| `enableScrubbing` | `boolean` | No | `-` | Enables scrubbing interactions. When true, allows scrubbing and makes scrubber components interactive. |
|
|
1301
|
-
| `end` | `string \| number` | No | `-` | - |
|
|
1302
|
-
| `exponent` | `string \| number` | No | `-` | - |
|
|
1303
|
-
| `externalResourcesRequired` | `false \| true \| true \| false` | No | `-` | - |
|
|
1304
|
-
| `fill` | `string` | No | `-` | - |
|
|
1305
|
-
| `fillOpacity` | `string \| number` | No | `-` | - |
|
|
1306
|
-
| `fillRule` | `inherit \| nonzero \| evenodd` | No | `-` | - |
|
|
1307
|
-
| `filter` | `string` | No | `-` | - |
|
|
1308
|
-
| `filterRes` | `string \| number` | No | `-` | - |
|
|
1309
|
-
| `filterUnits` | `string \| number` | No | `-` | - |
|
|
1310
1975
|
| `flexBasis` | `ResponsiveProp<FlexBasis<string \| number>>` | No | `-` | - |
|
|
1311
1976
|
| `flexDirection` | `ResponsiveProp<row \| row-reverse \| column \| column-reverse>` | No | `-` | - |
|
|
1312
|
-
| `flexGrow` |
|
|
1313
|
-
| `flexShrink` |
|
|
1977
|
+
| `flexGrow` | `inherit \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1978
|
+
| `flexShrink` | `inherit \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1314
1979
|
| `flexWrap` | `ResponsiveProp<nowrap \| wrap \| wrap-reverse>` | No | `-` | - |
|
|
1315
|
-
| `floodColor` | `string \| number` | No | `-` | - |
|
|
1316
|
-
| `floodOpacity` | `string \| number` | No | `-` | - |
|
|
1317
|
-
| `focusable` | `auto \| Booleanish` | No | `-` | - |
|
|
1318
1980
|
| `font` | `ResponsiveProp<FontFamily \| inherit>` | No | `-` | - |
|
|
1319
1981
|
| `fontFamily` | `ResponsiveProp<FontFamily \| inherit>` | No | `-` | - |
|
|
1320
|
-
| `fontSize` | `ResponsiveProp<
|
|
1321
|
-
| `
|
|
1322
|
-
| `
|
|
1323
|
-
| `
|
|
1324
|
-
| `
|
|
1325
|
-
| `fontWeight` | `ResponsiveProp<FontWeight \| inherit>` | No | `-` | - |
|
|
1326
|
-
| `format` | `string \| number` | No | `-` | - |
|
|
1327
|
-
| `fr` | `string \| number` | No | `-` | - |
|
|
1328
|
-
| `from` | `string \| number` | No | `-` | - |
|
|
1329
|
-
| `fx` | `string \| number` | No | `-` | - |
|
|
1330
|
-
| `fy` | `string \| number` | No | `-` | - |
|
|
1331
|
-
| `g1` | `string \| number` | No | `-` | - |
|
|
1332
|
-
| `g2` | `string \| number` | No | `-` | - |
|
|
1333
|
-
| `gap` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1334
|
-
| `glyphName` | `string \| number` | No | `-` | - |
|
|
1335
|
-
| `glyphOrientationHorizontal` | `string \| number` | No | `-` | - |
|
|
1336
|
-
| `glyphOrientationVertical` | `string \| number` | No | `-` | - |
|
|
1337
|
-
| `glyphRef` | `string \| number` | No | `-` | - |
|
|
1338
|
-
| `gradientTransform` | `string` | No | `-` | - |
|
|
1339
|
-
| `gradientUnits` | `string` | No | `-` | - |
|
|
1340
|
-
| `grid` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| none` | No | `-` | - |
|
|
1341
|
-
| `gridArea` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - |
|
|
1982
|
+
| `fontSize` | `ResponsiveProp<inherit \| FontSize>` | No | `-` | - |
|
|
1983
|
+
| `fontWeight` | `ResponsiveProp<inherit \| FontWeight>` | No | `-` | - |
|
|
1984
|
+
| `gap` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
1985
|
+
| `grid` | `inherit \| none \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1986
|
+
| `gridArea` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1342
1987
|
| `gridAutoColumns` | `ResponsiveProp<GridAutoColumns<string \| number>>` | No | `-` | - |
|
|
1343
|
-
| `gridAutoFlow` |
|
|
1988
|
+
| `gridAutoFlow` | `inherit \| revert \| row \| column \| -moz-initial \| initial \| revert-layer \| unset \| dense` | No | `-` | - |
|
|
1344
1989
|
| `gridAutoRows` | `ResponsiveProp<GridAutoRows<string \| number>>` | No | `-` | - |
|
|
1345
|
-
| `gridColumn` |
|
|
1346
|
-
| `gridColumnEnd` |
|
|
1347
|
-
| `gridColumnStart` |
|
|
1348
|
-
| `gridRow` |
|
|
1349
|
-
| `gridRowEnd` |
|
|
1350
|
-
| `gridRowStart` |
|
|
1351
|
-
| `gridTemplate` |
|
|
1352
|
-
| `gridTemplateAreas` |
|
|
1990
|
+
| `gridColumn` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1991
|
+
| `gridColumnEnd` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1992
|
+
| `gridColumnStart` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1993
|
+
| `gridRow` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1994
|
+
| `gridRowEnd` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1995
|
+
| `gridRowStart` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1996
|
+
| `gridTemplate` | `inherit \| none \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1997
|
+
| `gridTemplateAreas` | `inherit \| none \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1353
1998
|
| `gridTemplateColumns` | `ResponsiveProp<GridTemplateColumns<string \| number>>` | No | `-` | - |
|
|
1354
1999
|
| `gridTemplateRows` | `ResponsiveProp<GridTemplateRows<string \| number>>` | No | `-` | - |
|
|
1355
|
-
| `hanging` | `string \| number` | No | `-` | - |
|
|
1356
2000
|
| `height` | `ResponsiveProp<Height<string \| number>>` | No | `-` | - |
|
|
1357
|
-
| `horizAdvX` | `string \| number` | No | `-` | - |
|
|
1358
|
-
| `horizOriginX` | `string \| number` | No | `-` | - |
|
|
1359
|
-
| `href` | `string` | No | `-` | - |
|
|
1360
|
-
| `id` | `string` | No | `-` | - |
|
|
1361
|
-
| `ideographic` | `string \| number` | No | `-` | - |
|
|
1362
|
-
| `imageRendering` | `string \| number` | No | `-` | - |
|
|
1363
|
-
| `in` | `string` | No | `-` | - |
|
|
1364
|
-
| `in2` | `string \| number` | No | `-` | - |
|
|
1365
2001
|
| `inset` | `number \| Partial<ChartInset>` | No | `-` | Inset around the entire chart (outside the axes). |
|
|
1366
|
-
| `
|
|
1367
|
-
| `justifyContent` | `ResponsiveProp<left \| right \| center \| end \| normal \| start \| flex-start \| flex-end \| space-between \| space-around \| space-evenly \| stretch>` | No | `-` | - |
|
|
1368
|
-
| `k` | `string \| number` | No | `-` | - |
|
|
1369
|
-
| `k1` | `string \| number` | No | `-` | - |
|
|
1370
|
-
| `k2` | `string \| number` | No | `-` | - |
|
|
1371
|
-
| `k3` | `string \| number` | No | `-` | - |
|
|
1372
|
-
| `k4` | `string \| number` | No | `-` | - |
|
|
1373
|
-
| `kernelMatrix` | `string \| number` | No | `-` | - |
|
|
1374
|
-
| `kernelUnitLength` | `string \| number` | No | `-` | - |
|
|
1375
|
-
| `kerning` | `string \| number` | No | `-` | - |
|
|
2002
|
+
| `justifyContent` | `ResponsiveProp<left \| right \| center \| normal \| start \| end \| flex-start \| flex-end \| space-between \| space-around \| space-evenly \| stretch>` | No | `-` | - |
|
|
1376
2003
|
| `key` | `Key \| null` | No | `-` | - |
|
|
1377
|
-
| `keyPoints` | `string \| number` | No | `-` | - |
|
|
1378
|
-
| `keySplines` | `string \| number` | No | `-` | - |
|
|
1379
|
-
| `keyTimes` | `string \| number` | No | `-` | - |
|
|
1380
|
-
| `lang` | `string` | No | `-` | - |
|
|
1381
2004
|
| `left` | `ResponsiveProp<Left<string \| number>>` | No | `-` | - |
|
|
1382
|
-
| `
|
|
1383
|
-
| `
|
|
1384
|
-
| `
|
|
1385
|
-
| `
|
|
1386
|
-
| `
|
|
1387
|
-
| `
|
|
1388
|
-
| `
|
|
1389
|
-
| `
|
|
1390
|
-
| `marginEnd` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - |
|
|
1391
|
-
| `marginStart` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - |
|
|
1392
|
-
| `marginTop` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - |
|
|
1393
|
-
| `marginX` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - |
|
|
1394
|
-
| `marginY` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - |
|
|
1395
|
-
| `markerEnd` | `string` | No | `-` | - |
|
|
1396
|
-
| `markerHeight` | `string \| number` | No | `-` | - |
|
|
1397
|
-
| `markerMid` | `string` | No | `-` | - |
|
|
1398
|
-
| `markerStart` | `string` | No | `-` | - |
|
|
1399
|
-
| `markerUnits` | `string \| number` | No | `-` | - |
|
|
1400
|
-
| `markerWidth` | `string \| number` | No | `-` | - |
|
|
1401
|
-
| `mask` | `string` | No | `-` | - |
|
|
1402
|
-
| `maskContentUnits` | `string \| number` | No | `-` | - |
|
|
1403
|
-
| `maskUnits` | `string \| number` | No | `-` | - |
|
|
1404
|
-
| `mathematical` | `string \| number` | No | `-` | - |
|
|
1405
|
-
| `max` | `string \| number` | No | `-` | - |
|
|
2005
|
+
| `lineHeight` | `ResponsiveProp<inherit \| LineHeight>` | No | `-` | - |
|
|
2006
|
+
| `margin` | `ResponsiveProp<0 \| -1 \| -2 \| -0.25 \| -0.5 \| -0.75 \| -1.5 \| -3 \| -4 \| -5 \| -6 \| -7 \| -8 \| -9 \| -10>` | No | `-` | - |
|
|
2007
|
+
| `marginBottom` | `ResponsiveProp<0 \| -1 \| -2 \| -0.25 \| -0.5 \| -0.75 \| -1.5 \| -3 \| -4 \| -5 \| -6 \| -7 \| -8 \| -9 \| -10>` | No | `-` | - |
|
|
2008
|
+
| `marginEnd` | `ResponsiveProp<0 \| -1 \| -2 \| -0.25 \| -0.5 \| -0.75 \| -1.5 \| -3 \| -4 \| -5 \| -6 \| -7 \| -8 \| -9 \| -10>` | No | `-` | - |
|
|
2009
|
+
| `marginStart` | `ResponsiveProp<0 \| -1 \| -2 \| -0.25 \| -0.5 \| -0.75 \| -1.5 \| -3 \| -4 \| -5 \| -6 \| -7 \| -8 \| -9 \| -10>` | No | `-` | - |
|
|
2010
|
+
| `marginTop` | `ResponsiveProp<0 \| -1 \| -2 \| -0.25 \| -0.5 \| -0.75 \| -1.5 \| -3 \| -4 \| -5 \| -6 \| -7 \| -8 \| -9 \| -10>` | No | `-` | - |
|
|
2011
|
+
| `marginX` | `ResponsiveProp<0 \| -1 \| -2 \| -0.25 \| -0.5 \| -0.75 \| -1.5 \| -3 \| -4 \| -5 \| -6 \| -7 \| -8 \| -9 \| -10>` | No | `-` | - |
|
|
2012
|
+
| `marginY` | `ResponsiveProp<0 \| -1 \| -2 \| -0.25 \| -0.5 \| -0.75 \| -1.5 \| -3 \| -4 \| -5 \| -6 \| -7 \| -8 \| -9 \| -10>` | No | `-` | - |
|
|
1406
2013
|
| `maxHeight` | `ResponsiveProp<MaxHeight<string \| number>>` | No | `-` | - |
|
|
1407
2014
|
| `maxWidth` | `ResponsiveProp<MaxWidth<string \| number>>` | No | `-` | - |
|
|
1408
|
-
| `media` | `string` | No | `-` | - |
|
|
1409
|
-
| `method` | `string` | No | `-` | - |
|
|
1410
|
-
| `min` | `string \| number` | No | `-` | - |
|
|
1411
2015
|
| `minHeight` | `ResponsiveProp<MinHeight<string \| number>>` | No | `-` | - |
|
|
1412
2016
|
| `minWidth` | `ResponsiveProp<MinWidth<string \| number>>` | No | `-` | - |
|
|
1413
|
-
| `
|
|
1414
|
-
| `
|
|
1415
|
-
| `numOctaves` | `string \| number` | No | `-` | - |
|
|
1416
|
-
| `offset` | `string \| number` | No | `-` | - |
|
|
1417
|
-
| `onChange` | `FormEventHandler<SVGSVGElement>` | No | `-` | - |
|
|
1418
|
-
| `onPointClick` | `((event: MouseEvent<Element, MouseEvent>, point: { x: number; y: number; dataX: number; dataY: number; }) => void)` | No | `-` | Handler for when a dot is clicked. Automatically makes dots appear pressable when provided. |
|
|
2017
|
+
| `onChange` | `FormEventHandler<HTMLDivElement>` | No | `-` | - |
|
|
2018
|
+
| `onPointClick` | `((event: MouseEvent<Element, MouseEvent>, point: { x: number; y: number; dataX: number; dataY: number; }) => void)` | No | `-` | Handler for when a point is clicked. Passed through to Point components rendered via points. |
|
|
1419
2019
|
| `onScrubberPositionChange` | `((index: number) => void) \| undefined` | No | `-` | Callback fired when the scrubber position changes. Receives the dataIndex of the scrubber or undefined when not scrubbing. |
|
|
1420
|
-
| `opacity` |
|
|
1421
|
-
| `
|
|
1422
|
-
| `
|
|
1423
|
-
| `
|
|
1424
|
-
| `
|
|
1425
|
-
| `
|
|
1426
|
-
| `
|
|
1427
|
-
| `
|
|
1428
|
-
| `
|
|
1429
|
-
| `padding` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1430
|
-
| `paddingBottom` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1431
|
-
| `paddingEnd` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1432
|
-
| `paddingStart` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1433
|
-
| `paddingTop` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1434
|
-
| `paddingX` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1435
|
-
| `paddingY` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1436
|
-
| `paintOrder` | `string \| number` | No | `-` | - |
|
|
1437
|
-
| `panose1` | `string \| number` | No | `-` | - |
|
|
1438
|
-
| `path` | `string` | No | `-` | - |
|
|
1439
|
-
| `pathLength` | `string \| number` | No | `-` | - |
|
|
1440
|
-
| `patternContentUnits` | `string` | No | `-` | - |
|
|
1441
|
-
| `patternTransform` | `string \| number` | No | `-` | - |
|
|
1442
|
-
| `patternUnits` | `string` | No | `-` | - |
|
|
2020
|
+
| `opacity` | `number \| ({ base?: Opacity; phone?: Opacity \| undefined; tablet?: Opacity \| undefined; desktop?: Opacity \| undefined; } & number) \| undefined` | No | `1` | Opacity of the lines stroke. Will also be applied to points and area fill. |
|
|
2021
|
+
| `overflow` | `ResponsiveProp<hidden \| auto \| visible \| clip \| scroll>` | No | `-` | - |
|
|
2022
|
+
| `padding` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
2023
|
+
| `paddingBottom` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
2024
|
+
| `paddingEnd` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
2025
|
+
| `paddingStart` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
2026
|
+
| `paddingTop` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
2027
|
+
| `paddingX` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
2028
|
+
| `paddingY` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
1443
2029
|
| `pin` | `top \| bottom \| left \| right \| all` | No | `-` | Direction in which to absolutely pin the box. |
|
|
1444
|
-
| `
|
|
1445
|
-
| `points` | `string` | No | `-` | - |
|
|
1446
|
-
| `pointsAtX` | `string \| number` | No | `-` | - |
|
|
1447
|
-
| `pointsAtY` | `string \| number` | No | `-` | - |
|
|
1448
|
-
| `pointsAtZ` | `string \| number` | No | `-` | - |
|
|
2030
|
+
| `points` | `boolean \| ((defaults: PointBaseProps) => boolean \| Partial<PointProps> \| null) \| undefined` | No | `-` | Controls whether and how to render points at each data point in the series. - true: Show all points with default styling - false or undefined: Hide all points - Function: Called for every entry in the data array to customize individual points |
|
|
1449
2031
|
| `position` | `ResponsiveProp<static \| relative \| absolute \| fixed \| sticky>` | No | `-` | - |
|
|
1450
|
-
| `preserveAlpha` | `false \| true \| true \| false` | No | `-` | - |
|
|
1451
|
-
| `preserveAspectRatio` | `string` | No | `-` | - |
|
|
1452
|
-
| `primitiveUnits` | `string \| number` | No | `-` | - |
|
|
1453
|
-
| `r` | `string \| number` | No | `-` | - |
|
|
1454
|
-
| `radius` | `string \| number` | No | `-` | - |
|
|
1455
2032
|
| `ref` | `((instance: SVGSVGElement \| null) => void) \| RefObject<SVGSVGElement> \| null` | No | `-` | - |
|
|
1456
|
-
| `refX` | `string \| number` | No | `-` | - |
|
|
1457
|
-
| `refY` | `string \| number` | No | `-` | - |
|
|
1458
|
-
| `renderPoints` | `((params: RenderPointsParams) => boolean \| PointConfig \| null) \| undefined` | No | `-` | Callback function to determine how to render points at each data point in the series. Called for every entry in the data array. |
|
|
1459
|
-
| `renderingIntent` | `string \| number` | No | `-` | - |
|
|
1460
|
-
| `repeatCount` | `string \| number` | No | `-` | - |
|
|
1461
|
-
| `repeatDur` | `string \| number` | No | `-` | - |
|
|
1462
|
-
| `requiredExtensions` | `string \| number` | No | `-` | - |
|
|
1463
|
-
| `requiredFeatures` | `string \| number` | No | `-` | - |
|
|
1464
|
-
| `restart` | `string \| number` | No | `-` | - |
|
|
1465
|
-
| `result` | `string` | No | `-` | - |
|
|
1466
2033
|
| `right` | `ResponsiveProp<Right<string \| number>>` | No | `-` | - |
|
|
1467
|
-
| `
|
|
1468
|
-
| `rotate` | `string \| number` | No | `-` | - |
|
|
1469
|
-
| `rowGap` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - |
|
|
1470
|
-
| `rx` | `string \| number` | No | `-` | - |
|
|
1471
|
-
| `ry` | `string \| number` | No | `-` | - |
|
|
1472
|
-
| `scale` | `string \| number` | No | `-` | - |
|
|
1473
|
-
| `seed` | `string \| number` | No | `-` | - |
|
|
2034
|
+
| `rowGap` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
1474
2035
|
| `series` | `LineSeries[]` | No | `-` | Configuration objects that define how to visualize the data. Each series supports Line component props for individual customization. |
|
|
1475
|
-
| `
|
|
1476
|
-
| `showArea` | `boolean` | No | `-` | Show area fill under the line. |
|
|
2036
|
+
| `showArea` | `boolean` | No | `-` | Whether to show area fill under the line. |
|
|
1477
2037
|
| `showXAxis` | `boolean` | No | `-` | Whether to show the X axis. |
|
|
1478
2038
|
| `showYAxis` | `boolean` | No | `-` | Whether to show the Y axis. |
|
|
1479
|
-
| `
|
|
1480
|
-
| `
|
|
1481
|
-
| `
|
|
1482
|
-
| `
|
|
1483
|
-
| `speed` | `string \| number` | No | `-` | - |
|
|
1484
|
-
| `spreadMethod` | `string` | No | `-` | - |
|
|
1485
|
-
| `startOffset` | `string \| number` | No | `-` | - |
|
|
1486
|
-
| `stdDeviation` | `string \| number` | No | `-` | - |
|
|
1487
|
-
| `stemh` | `string \| number` | No | `-` | - |
|
|
1488
|
-
| `stemv` | `string \| number` | No | `-` | - |
|
|
1489
|
-
| `stitchTiles` | `string \| number` | No | `-` | - |
|
|
1490
|
-
| `stopColor` | `string` | No | `-` | - |
|
|
1491
|
-
| `stopOpacity` | `string \| number` | No | `-` | - |
|
|
1492
|
-
| `strikethroughPosition` | `string \| number` | No | `-` | - |
|
|
1493
|
-
| `strikethroughThickness` | `string \| number` | No | `-` | - |
|
|
1494
|
-
| `string` | `string \| number` | No | `-` | - |
|
|
1495
|
-
| `stroke` | `string` | No | `-` | - |
|
|
1496
|
-
| `strokeDasharray` | `string \| number` | No | `-` | - |
|
|
1497
|
-
| `strokeDashoffset` | `string \| number` | No | `-` | - |
|
|
1498
|
-
| `strokeLinecap` | `inherit \| butt \| round \| square` | No | `-` | - |
|
|
1499
|
-
| `strokeLinejoin` | `inherit \| round \| miter \| bevel` | No | `-` | - |
|
|
1500
|
-
| `strokeMiterlimit` | `string \| number` | No | `-` | - |
|
|
1501
|
-
| `strokeOpacity` | `string \| number` | No | `-` | - |
|
|
1502
|
-
| `strokeWidth` | `number` | No | `-` | - |
|
|
1503
|
-
| `style` | `CSSProperties` | No | `-` | - |
|
|
1504
|
-
| `suppressHydrationWarning` | `boolean` | No | `-` | - |
|
|
1505
|
-
| `surfaceScale` | `string \| number` | No | `-` | - |
|
|
1506
|
-
| `systemLanguage` | `string \| number` | No | `-` | - |
|
|
1507
|
-
| `tabIndex` | `number` | No | `-` | - |
|
|
1508
|
-
| `tableValues` | `string \| number` | No | `-` | - |
|
|
1509
|
-
| `target` | `string` | No | `-` | - |
|
|
1510
|
-
| `targetX` | `string \| number` | No | `-` | - |
|
|
1511
|
-
| `targetY` | `string \| number` | No | `-` | - |
|
|
2039
|
+
| `strokeOpacity` | `number` | No | `1` | Opacity of the line |
|
|
2040
|
+
| `strokeWidth` | `number` | No | `2` | Width of the line |
|
|
2041
|
+
| `style` | `CSSProperties` | No | `-` | Custom styles for the root element. |
|
|
2042
|
+
| `styles` | `{ root?: CSSProperties; chart?: CSSProperties \| undefined; } \| undefined` | No | `-` | Custom styles for the component. |
|
|
1512
2043
|
| `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID |
|
|
1513
|
-
| `textAlign` | `ResponsiveProp<center \|
|
|
1514
|
-
| `textAnchor` | `string` | No | `-` | - |
|
|
2044
|
+
| `textAlign` | `ResponsiveProp<center \| start \| end \| justify>` | No | `-` | - |
|
|
1515
2045
|
| `textDecoration` | `ResponsiveProp<none \| underline \| overline \| line-through \| underline overline \| underline double>` | No | `-` | - |
|
|
1516
|
-
| `
|
|
1517
|
-
| `textRendering` | `string \| number` | No | `-` | - |
|
|
1518
|
-
| `textTransform` | `ResponsiveProp<capitalize \| lowercase \| none \| uppercase>` | No | `-` | - |
|
|
1519
|
-
| `to` | `string \| number` | No | `-` | - |
|
|
2046
|
+
| `textTransform` | `ResponsiveProp<none \| uppercase \| lowercase \| capitalize>` | No | `-` | - |
|
|
1520
2047
|
| `top` | `ResponsiveProp<Top<string \| number>>` | No | `-` | - |
|
|
1521
|
-
| `transform` |
|
|
1522
|
-
| `
|
|
1523
|
-
| `
|
|
1524
|
-
| `
|
|
1525
|
-
| `
|
|
1526
|
-
| `underlineThickness` | `string \| number` | No | `-` | - |
|
|
1527
|
-
| `unicode` | `string \| number` | No | `-` | - |
|
|
1528
|
-
| `unicodeBidi` | `string \| number` | No | `-` | - |
|
|
1529
|
-
| `unicodeRange` | `string \| number` | No | `-` | - |
|
|
1530
|
-
| `unitsPerEm` | `string \| number` | No | `-` | - |
|
|
1531
|
-
| `userSelect` | `ResponsiveProp<text \| none \| auto \| all>` | No | `-` | - |
|
|
1532
|
-
| `vAlphabetic` | `string \| number` | No | `-` | - |
|
|
1533
|
-
| `vHanging` | `string \| number` | No | `-` | - |
|
|
1534
|
-
| `vIdeographic` | `string \| number` | No | `-` | - |
|
|
1535
|
-
| `vMathematical` | `string \| number` | No | `-` | - |
|
|
1536
|
-
| `values` | `string` | No | `-` | - |
|
|
1537
|
-
| `vectorEffect` | `string \| number` | No | `-` | - |
|
|
1538
|
-
| `version` | `string` | No | `-` | - |
|
|
1539
|
-
| `vertAdvY` | `string \| number` | No | `-` | - |
|
|
1540
|
-
| `vertOriginX` | `string \| number` | No | `-` | - |
|
|
1541
|
-
| `vertOriginY` | `string \| number` | No | `-` | - |
|
|
1542
|
-
| `viewBox` | `string` | No | `-` | - |
|
|
1543
|
-
| `viewTarget` | `string \| number` | No | `-` | - |
|
|
1544
|
-
| `visibility` | `ResponsiveProp<visible \| hidden>` | No | `-` | - |
|
|
2048
|
+
| `transform` | `inherit \| none \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
2049
|
+
| `transition` | `Orchestration & Repeat & Tween \| Orchestration & Repeat & Spring \| Orchestration & Repeat & Keyframes \| Orchestration & Repeat & Inertia \| Orchestration & Repeat & Just \| Orchestration & Repeat & None \| Orchestration & Repeat & PermissiveTransitionDefinition \| Orchestration & Repeat & Tween & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & Spring & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & Keyframes & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & Inertia & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & Just & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & None & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & PermissiveTransitionDefinition & { [key: string]: TransitionDefinition; }` | No | `-` | Transition configuration for line animations. |
|
|
2050
|
+
| `type` | `dotted \| solid` | No | `'solid'` | The type of line to render. |
|
|
2051
|
+
| `userSelect` | `ResponsiveProp<text \| none \| all \| auto>` | No | `-` | - |
|
|
2052
|
+
| `visibility` | `ResponsiveProp<hidden \| visible>` | No | `-` | - |
|
|
1545
2053
|
| `width` | `ResponsiveProp<Width<string \| number>>` | No | `-` | - |
|
|
1546
|
-
| `
|
|
1547
|
-
| `
|
|
1548
|
-
| `
|
|
1549
|
-
| `x` | `string \| number` | No | `-` | - |
|
|
1550
|
-
| `x1` | `string \| number` | No | `-` | - |
|
|
1551
|
-
| `x2` | `string \| number` | No | `-` | - |
|
|
1552
|
-
| `xAxis` | `(Partial<AxisConfigProps> & AxisBaseProps & { className?: string; classNames?: { root?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; } & { position?: top \| bottom \| undefined; height?: number \| undefined; }) \| undefined` | No | `-` | - |
|
|
1553
|
-
| `xChannelSelector` | `string` | No | `-` | - |
|
|
1554
|
-
| `xHeight` | `string \| number` | No | `-` | - |
|
|
1555
|
-
| `xlinkActuate` | `string` | No | `-` | - |
|
|
1556
|
-
| `xlinkArcrole` | `string` | No | `-` | - |
|
|
1557
|
-
| `xlinkHref` | `string` | No | `-` | - |
|
|
1558
|
-
| `xlinkRole` | `string` | No | `-` | - |
|
|
1559
|
-
| `xlinkShow` | `string` | No | `-` | - |
|
|
1560
|
-
| `xlinkTitle` | `string` | No | `-` | - |
|
|
1561
|
-
| `xlinkType` | `string` | No | `-` | - |
|
|
1562
|
-
| `xmlBase` | `string` | No | `-` | - |
|
|
1563
|
-
| `xmlLang` | `string` | No | `-` | - |
|
|
1564
|
-
| `xmlSpace` | `string` | No | `-` | - |
|
|
1565
|
-
| `xmlns` | `string` | No | `-` | - |
|
|
1566
|
-
| `xmlnsXlink` | `string` | No | `-` | - |
|
|
1567
|
-
| `y` | `string \| number` | No | `-` | - |
|
|
1568
|
-
| `y1` | `string \| number` | No | `-` | - |
|
|
1569
|
-
| `y2` | `string \| number` | No | `-` | - |
|
|
1570
|
-
| `yAxis` | `(Partial<AxisConfigProps> & AxisBaseProps & { className?: string; classNames?: { root?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; } & { axisId?: string \| undefined; position?: left \| right \| undefined; width?: number \| undefined; }) \| undefined` | No | `-` | - |
|
|
1571
|
-
| `yChannelSelector` | `string` | No | `-` | - |
|
|
1572
|
-
| `z` | `string \| number` | No | `-` | - |
|
|
1573
|
-
| `zIndex` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - |
|
|
1574
|
-
| `zoomAndPan` | `string` | No | `-` | - |
|
|
2054
|
+
| `xAxis` | `(Partial<AxisConfigProps> & AxisBaseProps & { className?: string; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { position?: top \| bottom \| undefined; height?: number \| undefined; }) \| undefined` | No | `-` | Configuration for x-axis. Accepts axis config and axis props. To show the axis, set showXAxis to true. |
|
|
2055
|
+
| `yAxis` | `(Partial<AxisConfigProps> & AxisBaseProps & { className?: string; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { axisId?: string \| undefined; position?: left \| right \| undefined; width?: number \| undefined; }) \| undefined` | No | `-` | Configuration for y-axis. Accepts axis config and axis props. To show the axis, set showYAxis to true. |
|
|
2056
|
+
| `zIndex` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
|
|
1575
2057
|
|
|
1576
2058
|
|