@coinbase/cds-mcp-server 8.66.0 → 8.66.1
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 +4 -0
- package/mcp-docs/mobile/components/AreaChart.txt +89 -249
- package/mcp-docs/mobile/components/Banner.txt +1 -1
- package/mcp-docs/mobile/components/BarChart.txt +2 -0
- package/mcp-docs/mobile/components/Button.txt +2 -2
- package/mcp-docs/mobile/components/CartesianChart.txt +20 -7
- package/mcp-docs/mobile/components/CellMedia.txt +1 -1
- package/mcp-docs/mobile/components/DotSymbol.txt +1 -1
- package/mcp-docs/mobile/components/Icon.txt +1 -1
- package/mcp-docs/mobile/components/IconButton.txt +1 -1
- package/mcp-docs/mobile/components/Tag.txt +2 -2
- package/mcp-docs/web/components/AreaChart.txt +228 -380
- package/mcp-docs/web/components/Banner.txt +1 -1
- package/mcp-docs/web/components/BarChart.txt +4 -2
- package/mcp-docs/web/components/Button.txt +2 -2
- package/mcp-docs/web/components/CartesianChart.txt +20 -5
- package/mcp-docs/web/components/CellMedia.txt +1 -1
- package/mcp-docs/web/components/DotSymbol.txt +1 -1
- package/mcp-docs/web/components/Icon.txt +1 -1
- package/mcp-docs/web/components/IconButton.txt +1 -1
- package/mcp-docs/web/components/Legend.txt +12 -2
- package/mcp-docs/web/components/LineChart.txt +0 -39
- package/mcp-docs/web/components/SidebarItem.txt +1 -1
- package/mcp-docs/web/components/Tag.txt +2 -2
- package/package.json +1 -1
|
@@ -12,9 +12,11 @@ import { AreaChart } from '@coinbase/cds-web-visualization'
|
|
|
12
12
|
|
|
13
13
|
## Examples
|
|
14
14
|
|
|
15
|
-
AreaChart is a
|
|
15
|
+
AreaChart is a wrapper for [CartesianChart](/components/charts/CartesianChart) that has some unique features over [LineChart](/components/charts/LineChart), such as the ability to stack areas on top of each other and a default value-axis minimum that follows the baseline (`0` when baseline is not set). Charts are built using SVGs.
|
|
16
16
|
|
|
17
|
-
###
|
|
17
|
+
### Basics
|
|
18
|
+
|
|
19
|
+
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.
|
|
18
20
|
|
|
19
21
|
```jsx live
|
|
20
22
|
<AreaChart
|
|
@@ -36,7 +38,11 @@ AreaChart is a cartesian chart variant that allows for easy visualization of sta
|
|
|
36
38
|
/>
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
###
|
|
41
|
+
### Data
|
|
42
|
+
|
|
43
|
+
#### Positive and Negative
|
|
44
|
+
|
|
45
|
+
Area grows from the baseline to each value, allowing for both positive and negative data to be shown. Also, you can set `baseline` to any value you'd like.
|
|
40
46
|
|
|
41
47
|
```jsx live
|
|
42
48
|
<AreaChart
|
|
@@ -44,26 +50,86 @@ AreaChart is a cartesian chart variant that allows for easy visualization of sta
|
|
|
44
50
|
inset={0}
|
|
45
51
|
series={[
|
|
46
52
|
{
|
|
47
|
-
id: '
|
|
48
|
-
data: [
|
|
53
|
+
id: 'area',
|
|
54
|
+
data: [-40, -28, -21, -5, 48, -5, -28, 2, -29, -48, 18, -30, -29, 8],
|
|
55
|
+
gradient: {
|
|
56
|
+
stops: [
|
|
57
|
+
{ offset: 0, color: 'var(--color-fgNegative)' },
|
|
58
|
+
{ offset: 0, color: 'var(--color-fgPositive)' },
|
|
59
|
+
],
|
|
60
|
+
},
|
|
49
61
|
},
|
|
50
62
|
]}
|
|
51
|
-
type="
|
|
63
|
+
type="dotted"
|
|
52
64
|
showLines
|
|
65
|
+
showYAxis
|
|
66
|
+
yAxis={{
|
|
67
|
+
showGrid: true,
|
|
68
|
+
}}
|
|
53
69
|
/>
|
|
54
70
|
```
|
|
55
71
|
|
|
72
|
+
#### Range
|
|
73
|
+
|
|
74
|
+
You can pass in `[min, max]` tuples as data points to render an area that span a range of values.
|
|
75
|
+
|
|
76
|
+
```jsx live
|
|
77
|
+
<AreaChart
|
|
78
|
+
legend={<Legend seriesIds={['marketCap']} />}
|
|
79
|
+
showXAxis
|
|
80
|
+
showYAxis
|
|
81
|
+
height={250}
|
|
82
|
+
series={[
|
|
83
|
+
{
|
|
84
|
+
id: 'marketCap',
|
|
85
|
+
label: 'Market Cap',
|
|
86
|
+
data: [5.4, 5.8, 6.1, 5.9, 6.0, 6.3],
|
|
87
|
+
showLines: true,
|
|
88
|
+
fillOpacity: 0,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'confidenceInterval',
|
|
92
|
+
label: 'Confidence Interval',
|
|
93
|
+
data: [
|
|
94
|
+
[5.3, 5.5],
|
|
95
|
+
[5.6, 6.0],
|
|
96
|
+
[5.8, 6.2],
|
|
97
|
+
[5.8, 6.1],
|
|
98
|
+
[5.9, 6.3],
|
|
99
|
+
[6.2, 6.5],
|
|
100
|
+
],
|
|
101
|
+
fillOpacity: 0.3,
|
|
102
|
+
},
|
|
103
|
+
]}
|
|
104
|
+
xAxis={{
|
|
105
|
+
showLine: true,
|
|
106
|
+
showTickMarks: true,
|
|
107
|
+
data: ['January', 'February', 'March', 'April', 'May', 'June'],
|
|
108
|
+
}}
|
|
109
|
+
yAxis={{
|
|
110
|
+
showGrid: true,
|
|
111
|
+
showLine: true,
|
|
112
|
+
showTickMarks: true,
|
|
113
|
+
domain: { min: 5.0, max: 7.0 },
|
|
114
|
+
tickLabelFormatter: (val) => `$${val}B`,
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
<Line seriesId="marketCap" />
|
|
118
|
+
</AreaChart>
|
|
119
|
+
```
|
|
120
|
+
|
|
56
121
|
### Stacking
|
|
57
122
|
|
|
58
|
-
You can use the `stacked` prop to stack all areas on top of each other. You can also use the `stackId` prop on a series to create different stack groups. See [CartesianChart](/components/charts/CartesianChart/#series-stacks) for more
|
|
123
|
+
You can use the `stacked` prop to stack all areas on top of each other. You can also use the `stackId` prop on a series to create different stack groups. See [CartesianChart](/components/charts/CartesianChart/#series-stacks) for more info on stacking.
|
|
59
124
|
|
|
60
125
|
```jsx live
|
|
61
126
|
<AreaChart
|
|
62
127
|
showLines
|
|
63
128
|
stacked
|
|
64
129
|
curve="natural"
|
|
130
|
+
legend
|
|
65
131
|
height={{ base: 150, tablet: 200, desktop: 250 }}
|
|
66
|
-
inset={0}
|
|
132
|
+
inset={{ top: 0, bottom: 8, left: 0, right: 0 }}
|
|
67
133
|
series={[
|
|
68
134
|
{
|
|
69
135
|
id: 'currentRewards',
|
|
@@ -72,6 +138,8 @@ You can use the `stacked` prop to stack all areas on top of each other. You can
|
|
|
72
138
|
3700, 4170,
|
|
73
139
|
],
|
|
74
140
|
color: 'var(--color-fg)',
|
|
141
|
+
legendShape: 'squircle',
|
|
142
|
+
label: 'Current Rewards',
|
|
75
143
|
},
|
|
76
144
|
{
|
|
77
145
|
id: 'potentialRewards',
|
|
@@ -80,7 +148,9 @@ You can use the `stacked` prop to stack all areas on top of each other. You can
|
|
|
80
148
|
3520, 3900,
|
|
81
149
|
],
|
|
82
150
|
color: 'var(--color-fgPositive)',
|
|
83
|
-
LineComponent: DottedLine
|
|
151
|
+
LineComponent: (props) => <DottedLine {...props} strokeDasharray="6 6" />,
|
|
152
|
+
legendShape: 'squircle',
|
|
153
|
+
label: 'Potential Rewards',
|
|
84
154
|
},
|
|
85
155
|
]}
|
|
86
156
|
AreaComponent={(props) => <DottedArea {...props} peakOpacity={0.4} baselineOpacity={0.4} />}
|
|
@@ -88,30 +158,9 @@ You can use the `stacked` prop to stack all areas on top of each other. You can
|
|
|
88
158
|
/>
|
|
89
159
|
```
|
|
90
160
|
|
|
91
|
-
###
|
|
92
|
-
|
|
93
|
-
When an area chart contains negative values, the baseline automatically adjusts to zero instead of the bottom of the chart. The area fills from the data line to the zero baseline, properly showing both positive and negative regions.
|
|
94
|
-
|
|
95
|
-
```jsx live
|
|
96
|
-
<AreaChart
|
|
97
|
-
height={{ base: 150, tablet: 200, desktop: 250 }}
|
|
98
|
-
inset={0}
|
|
99
|
-
series={[
|
|
100
|
-
{
|
|
101
|
-
id: 'pageViews',
|
|
102
|
-
data: [24, 13, -98, 39, 48, 38, 43],
|
|
103
|
-
},
|
|
104
|
-
]}
|
|
105
|
-
AreaComponent={(props) => <SolidArea {...props} opacity={0.4} />}
|
|
106
|
-
showLines
|
|
107
|
-
showYAxis
|
|
108
|
-
yAxis={{
|
|
109
|
-
showGrid: true,
|
|
110
|
-
}}
|
|
111
|
-
/>
|
|
112
|
-
```
|
|
161
|
+
### Styling
|
|
113
162
|
|
|
114
|
-
|
|
163
|
+
#### Areas
|
|
115
164
|
|
|
116
165
|
You can have different area styles for each series.
|
|
117
166
|
|
|
@@ -144,374 +193,173 @@ You can have different area styles for each series.
|
|
|
144
193
|
/>
|
|
145
194
|
```
|
|
146
195
|
|
|
147
|
-
|
|
196
|
+
#### Axes
|
|
148
197
|
|
|
149
|
-
|
|
198
|
+
Using `showXAxis` and `showYAxis` allows you to display the axes. For more information, such as adjusting domain and range, see [XAxis](/components/charts/XAxis) and [YAxis](/components/charts/YAxis).
|
|
150
199
|
|
|
151
200
|
```jsx live
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
let direction;
|
|
178
|
-
if (previousValue >= maxDataOffset) {
|
|
179
|
-
direction = -1;
|
|
180
|
-
} else if (previousValue <= minYValue) {
|
|
181
|
-
direction = 1;
|
|
182
|
-
} else {
|
|
183
|
-
direction = Math.random() < 0.5 ? -1 : 1;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
let newValue = previousValue + offset * direction;
|
|
187
|
-
newValue = Math.max(minYValue, Math.min(maxDataOffset, newValue));
|
|
188
|
-
return newValue;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function generateInitialData() {
|
|
192
|
-
const data = [];
|
|
193
|
-
|
|
194
|
-
let previousValue = minYValue + Math.random() * (maxDataOffset - minYValue);
|
|
195
|
-
data.push(previousValue);
|
|
196
|
-
|
|
197
|
-
for (let i = 1; i < dataCount; i++) {
|
|
198
|
-
const newValue = generateNextValue(previousValue);
|
|
199
|
-
data.push(newValue);
|
|
200
|
-
previousValue = newValue;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return data;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const MemoizedDottedArea = memo((props) => (
|
|
207
|
-
<DottedArea {...props} baselineOpacity={1} peakOpacity={1} />
|
|
208
|
-
));
|
|
209
|
-
|
|
210
|
-
function AnimatedChart(props) {
|
|
211
|
-
const [data, setData] = useState(generateInitialData);
|
|
212
|
-
|
|
213
|
-
useEffect(() => {
|
|
214
|
-
const intervalId = setInterval(() => {
|
|
215
|
-
setData((currentData) => {
|
|
216
|
-
const lastValue = currentData[currentData.length - 1] ?? 0;
|
|
217
|
-
const newValue = generateNextValue(lastValue);
|
|
218
|
-
|
|
219
|
-
return [...currentData.slice(1), newValue];
|
|
220
|
-
});
|
|
221
|
-
}, updateInterval);
|
|
222
|
-
|
|
223
|
-
return () => clearInterval(intervalId);
|
|
224
|
-
}, []);
|
|
225
|
-
|
|
226
|
-
const series = seriesConfig.map((config, index) => ({
|
|
227
|
-
id: config.id,
|
|
228
|
-
label: config.label,
|
|
229
|
-
color: config.color,
|
|
230
|
-
data: index === 0 ? data : Array(dataCount).fill(seriesSpacing),
|
|
231
|
-
}));
|
|
232
|
-
|
|
233
|
-
return (
|
|
234
|
-
<AreaChart
|
|
235
|
-
overflow="visible"
|
|
236
|
-
stacked
|
|
237
|
-
height={{ base: 200, tablet: 250, desktop: 300 }}
|
|
238
|
-
series={series}
|
|
239
|
-
type="dotted"
|
|
240
|
-
showLines
|
|
241
|
-
AreaComponent={MemoizedDottedArea}
|
|
242
|
-
transitions={{
|
|
243
|
-
enter: { type: 'spring', stiffness: 700, damping: 80 },
|
|
244
|
-
update: { type: 'spring', stiffness: 700, damping: 20 },
|
|
245
|
-
}}
|
|
246
|
-
inset={0}
|
|
247
|
-
showYAxis
|
|
248
|
-
yAxis={{
|
|
249
|
-
showGrid: true,
|
|
250
|
-
width: 0,
|
|
251
|
-
tickLabelFormatter: () => '',
|
|
252
|
-
domain: { min: 0, max: domainLimit },
|
|
253
|
-
}}
|
|
254
|
-
{...props}
|
|
255
|
-
/>
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function AnimatedChartExample() {
|
|
260
|
-
const animatedStates = [
|
|
261
|
-
{ id: 'on', label: 'On' },
|
|
262
|
-
{ id: 'off', label: 'Off' },
|
|
263
|
-
];
|
|
264
|
-
const [animatedState, setAnimatedState] = useState(animatedStates[0]);
|
|
265
|
-
|
|
266
|
-
return (
|
|
267
|
-
<VStack gap={2}>
|
|
268
|
-
<HStack justifyContent="flex-end" gap={2} alignItems="center">
|
|
269
|
-
<Text as="h3" font="headline">
|
|
270
|
-
Animations
|
|
271
|
-
</Text>
|
|
272
|
-
<SegmentedTabs
|
|
273
|
-
activeTab={animatedState}
|
|
274
|
-
onChange={setAnimatedState}
|
|
275
|
-
tabs={animatedStates}
|
|
276
|
-
/>
|
|
277
|
-
</HStack>
|
|
278
|
-
<AnimatedChart animate={animatedState.id === 'on'} />
|
|
279
|
-
</VStack>
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return <AnimatedChartExample />;
|
|
284
|
-
}
|
|
201
|
+
<AreaChart
|
|
202
|
+
showLines
|
|
203
|
+
showXAxis
|
|
204
|
+
showYAxis
|
|
205
|
+
height={{ base: 200, tablet: 225, desktop: 250 }}
|
|
206
|
+
series={[
|
|
207
|
+
{
|
|
208
|
+
id: 'prices',
|
|
209
|
+
data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58],
|
|
210
|
+
},
|
|
211
|
+
]}
|
|
212
|
+
xAxis={{
|
|
213
|
+
showGrid: true,
|
|
214
|
+
showLine: true,
|
|
215
|
+
showTickMarks: true,
|
|
216
|
+
tickLabelFormatter: (dataX) => `Day ${dataX}`,
|
|
217
|
+
}}
|
|
218
|
+
yAxis={{
|
|
219
|
+
showGrid: true,
|
|
220
|
+
showLine: true,
|
|
221
|
+
showTickMarks: true,
|
|
222
|
+
}}
|
|
223
|
+
fillOpacity={0.5}
|
|
224
|
+
/>
|
|
285
225
|
```
|
|
286
226
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
You can use the `gradient` prop on `series` or `Area` components to enable gradients.
|
|
227
|
+
#### Gradient
|
|
290
228
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
Values in between stops will be interpolated smoothly using [srgb color space](https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty).
|
|
229
|
+
You can build threshold-based gradients with hard transitions by reusing stop offsets.
|
|
294
230
|
|
|
295
231
|
```jsx live
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
border: `2px solid rgb(var(--${color}50))`,
|
|
325
|
-
outlineColor: `rgb(var(--${color}80))`,
|
|
326
|
-
outline:
|
|
327
|
-
currentSpectrumColor === color ? `2px solid rgb(var(--${color}80))` : undefined,
|
|
328
|
-
}}
|
|
329
|
-
width={{ base: 16, tablet: 24, desktop: 24 }}
|
|
330
|
-
height={{ base: 16, tablet: 24, desktop: 24 }}
|
|
331
|
-
borderRadius={1000}
|
|
332
|
-
/>
|
|
333
|
-
))}
|
|
334
|
-
</HStack>
|
|
335
|
-
<AreaChart
|
|
336
|
-
enableScrubbing
|
|
337
|
-
height={{ base: 150, tablet: 200, desktop: 250 }}
|
|
338
|
-
series={[
|
|
339
|
-
{
|
|
340
|
-
id: 'prices',
|
|
341
|
-
data: data,
|
|
342
|
-
gradient: {
|
|
343
|
-
stops: ({ min, max }) => [
|
|
344
|
-
// Allows a function which accepts min/max or direct array
|
|
345
|
-
{ offset: min, color: `rgb(var(--${currentSpectrumColor}80))` },
|
|
346
|
-
{ offset: max, color: `rgb(var(--${currentSpectrumColor}20))` },
|
|
347
|
-
],
|
|
348
|
-
},
|
|
349
|
-
},
|
|
350
|
-
]}
|
|
351
|
-
showYAxis
|
|
352
|
-
yAxis={{
|
|
353
|
-
showGrid: true,
|
|
354
|
-
}}
|
|
355
|
-
>
|
|
356
|
-
<Scrubber />
|
|
357
|
-
</AreaChart>
|
|
358
|
-
</VStack>
|
|
359
|
-
);
|
|
360
|
-
}
|
|
232
|
+
<AreaChart
|
|
233
|
+
showLines
|
|
234
|
+
showYAxis
|
|
235
|
+
height={{ base: 180, tablet: 220, desktop: 260 }}
|
|
236
|
+
series={[
|
|
237
|
+
{
|
|
238
|
+
id: 'netFlow',
|
|
239
|
+
label: 'Net Flow',
|
|
240
|
+
data: [-9, -7, -3, -1, 2, 5, 3, -2, 1, 6, 8, 4],
|
|
241
|
+
gradient: {
|
|
242
|
+
stops: ({ min, max }) => [
|
|
243
|
+
{ offset: min, color: 'var(--color-fgNegative)', opacity: 0.45 },
|
|
244
|
+
{ offset: -2, color: 'var(--color-fgNegative)', opacity: 0.45 },
|
|
245
|
+
{ offset: -2, color: 'var(--color-fgWarning)', opacity: 0.45 },
|
|
246
|
+
{ offset: 2, color: 'var(--color-fgWarning)', opacity: 0.45 },
|
|
247
|
+
{ offset: 2, color: 'var(--color-fgPositive)', opacity: 0.45 },
|
|
248
|
+
{ offset: max, color: 'var(--color-fgPositive)', opacity: 0.45 },
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
type: 'gradient',
|
|
252
|
+
},
|
|
253
|
+
]}
|
|
254
|
+
yAxis={{
|
|
255
|
+
showGrid: true,
|
|
256
|
+
domain: { min: -10, max: 10 },
|
|
257
|
+
tickLabelFormatter: (value) => `${value}%`,
|
|
258
|
+
}}
|
|
259
|
+
/>
|
|
361
260
|
```
|
|
362
261
|
|
|
363
|
-
|
|
262
|
+
### Composed Examples
|
|
364
263
|
|
|
365
|
-
|
|
264
|
+
#### Custom Baseline
|
|
366
265
|
|
|
367
|
-
|
|
368
|
-
function DiscreteGradient() {
|
|
369
|
-
const spectrumColors = [
|
|
370
|
-
'blue',
|
|
371
|
-
'green',
|
|
372
|
-
'orange',
|
|
373
|
-
'yellow',
|
|
374
|
-
'gray',
|
|
375
|
-
'indigo',
|
|
376
|
-
'pink',
|
|
377
|
-
'purple',
|
|
378
|
-
'red',
|
|
379
|
-
'teal',
|
|
380
|
-
'chartreuse',
|
|
381
|
-
];
|
|
382
|
-
const data = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58];
|
|
383
|
-
|
|
384
|
-
const [currentSpectrumColor, setCurrentSpectrumColor] = useState('pink');
|
|
266
|
+
You can combine a custom baseline with a scrubber label that shows both price and date.
|
|
385
267
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
{ offset: min + (max - min) / 3, color: `rgb(var(--${currentSpectrumColor}80))` },
|
|
418
|
-
{ offset: min + (max - min) / 3, color: `rgb(var(--${currentSpectrumColor}50))` },
|
|
419
|
-
{
|
|
420
|
-
offset: min + ((max - min) / 3) * 2,
|
|
421
|
-
color: `rgb(var(--${currentSpectrumColor}50))`,
|
|
422
|
-
},
|
|
423
|
-
{
|
|
424
|
-
offset: min + ((max - min) / 3) * 2,
|
|
425
|
-
color: `rgb(var(--${currentSpectrumColor}20))`,
|
|
426
|
-
},
|
|
427
|
-
{ offset: max, color: `rgb(var(--${currentSpectrumColor}20))` },
|
|
428
|
-
],
|
|
429
|
-
},
|
|
430
|
-
},
|
|
431
|
-
]}
|
|
432
|
-
showLines
|
|
433
|
-
strokeWidth={4}
|
|
434
|
-
showYAxis
|
|
435
|
-
yAxis={{
|
|
436
|
-
showGrid: true,
|
|
437
|
-
}}
|
|
438
|
-
fillOpacity={0.5}
|
|
439
|
-
>
|
|
440
|
-
<Scrubber />
|
|
441
|
-
</AreaChart>
|
|
442
|
-
</VStack>
|
|
268
|
+
```jsx live
|
|
269
|
+
function CustomBaseline() {
|
|
270
|
+
const candles = [...btcCandles].reverse().slice(0, 180);
|
|
271
|
+
const prices = candles.map((candle) => parseFloat(candle.close));
|
|
272
|
+
const dates = candles.map((candle) => new Date(parseInt(candle.start, 10) * 1000));
|
|
273
|
+
|
|
274
|
+
const startingPrice = prices[0];
|
|
275
|
+
|
|
276
|
+
const formatPrice = useCallback((price) => {
|
|
277
|
+
return `$${price.toLocaleString('en-US', {
|
|
278
|
+
minimumFractionDigits: 2,
|
|
279
|
+
maximumFractionDigits: 2,
|
|
280
|
+
})}`;
|
|
281
|
+
}, []);
|
|
282
|
+
|
|
283
|
+
const formatDate = useCallback((date) => {
|
|
284
|
+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
285
|
+
}, []);
|
|
286
|
+
|
|
287
|
+
const formatLabel = useCallback(
|
|
288
|
+
(dataIndex) => {
|
|
289
|
+
const price = prices[dataIndex];
|
|
290
|
+
const date = dates[dataIndex];
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<>
|
|
294
|
+
<tspan style={{ fontWeight: 'bold' }}>{formatPrice(price)}</tspan> {formatDate(date)}
|
|
295
|
+
</>
|
|
296
|
+
);
|
|
297
|
+
},
|
|
298
|
+
[dates, formatDate, formatPrice, prices],
|
|
443
299
|
);
|
|
444
|
-
}
|
|
445
|
-
```
|
|
446
300
|
|
|
447
|
-
|
|
301
|
+
const PriceLabel = memo((props) => (
|
|
302
|
+
<DefaultReferenceLineLabel
|
|
303
|
+
{...props}
|
|
304
|
+
background="var(--color-bgSecondary)"
|
|
305
|
+
borderRadius={12.5}
|
|
306
|
+
color="var(--color-fg)"
|
|
307
|
+
dx={12}
|
|
308
|
+
font="label1"
|
|
309
|
+
horizontalAlignment="left"
|
|
310
|
+
inset={{ top: 4, bottom: 4, left: 8, right: 8 }}
|
|
311
|
+
/>
|
|
312
|
+
));
|
|
448
313
|
|
|
449
|
-
|
|
314
|
+
const chartAccessibilityLabel = `Bitcoin area chart with custom baseline. Current price: ${formatPrice(
|
|
315
|
+
prices[prices.length - 1],
|
|
316
|
+
)}. Use arrow keys to navigate.`;
|
|
450
317
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
'green',
|
|
456
|
-
'orange',
|
|
457
|
-
'yellow',
|
|
458
|
-
'gray',
|
|
459
|
-
'indigo',
|
|
460
|
-
'pink',
|
|
461
|
-
'purple',
|
|
462
|
-
'red',
|
|
463
|
-
'teal',
|
|
464
|
-
'chartreuse',
|
|
465
|
-
];
|
|
466
|
-
const data = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58];
|
|
467
|
-
|
|
468
|
-
const [currentSpectrumColor, setCurrentSpectrumColor] = useState('pink');
|
|
318
|
+
const getScrubberAccessibilityLabel = useCallback(
|
|
319
|
+
(index) => `${formatPrice(prices[index])} ${formatDate(dates[index])}`,
|
|
320
|
+
[dates, formatDate, formatPrice, prices],
|
|
321
|
+
);
|
|
469
322
|
|
|
470
323
|
return (
|
|
471
|
-
<
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
/>
|
|
489
|
-
))}
|
|
490
|
-
</HStack>
|
|
491
|
-
<AreaChart
|
|
492
|
-
enableScrubbing
|
|
493
|
-
height={{ base: 150, tablet: 200, desktop: 250 }}
|
|
494
|
-
series={[
|
|
495
|
-
{
|
|
496
|
-
id: 'prices',
|
|
497
|
-
data: data,
|
|
498
|
-
gradient: {
|
|
499
|
-
axis: 'x',
|
|
500
|
-
stops: ({ min, max }) => [
|
|
501
|
-
{ offset: min, color: `rgb(var(--${currentSpectrumColor}80))`, opacity: 0 },
|
|
502
|
-
{ offset: max, color: `rgb(var(--${currentSpectrumColor}20))`, opacity: 1 },
|
|
503
|
-
],
|
|
504
|
-
},
|
|
324
|
+
<AreaChart
|
|
325
|
+
enableScrubbing
|
|
326
|
+
showLines
|
|
327
|
+
showYAxis
|
|
328
|
+
accessibilityLabel={chartAccessibilityLabel}
|
|
329
|
+
getScrubberAccessibilityLabel={getScrubberAccessibilityLabel}
|
|
330
|
+
fillOpacity={0.5}
|
|
331
|
+
height={300}
|
|
332
|
+
series={[
|
|
333
|
+
{
|
|
334
|
+
id: 'prices',
|
|
335
|
+
data: prices,
|
|
336
|
+
gradient: {
|
|
337
|
+
stops: [
|
|
338
|
+
{ offset: startingPrice, color: 'var(--color-fgNegative)' },
|
|
339
|
+
{ offset: startingPrice, color: 'var(--color-fgPositive)' },
|
|
340
|
+
],
|
|
505
341
|
},
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
342
|
+
},
|
|
343
|
+
]}
|
|
344
|
+
yAxis={{
|
|
345
|
+
baseline: startingPrice,
|
|
346
|
+
showGrid: true,
|
|
347
|
+
tickLabelFormatter: formatPrice,
|
|
348
|
+
domain: { min: 70000, max: 120000 },
|
|
349
|
+
width: 80,
|
|
350
|
+
ticks: [80000, 100000, 120000],
|
|
351
|
+
}}
|
|
352
|
+
>
|
|
353
|
+
<Scrubber label={formatLabel} labelElevated />
|
|
354
|
+
<ReferenceLine
|
|
355
|
+
LabelComponent={PriceLabel}
|
|
356
|
+
LineComponent={(props) => (
|
|
357
|
+
<DottedLine {...props} stroke="var(--color-fg)" strokeDasharray="0 16" strokeWidth={3} />
|
|
358
|
+
)}
|
|
359
|
+
dataY={startingPrice}
|
|
360
|
+
label={formatPrice(startingPrice)}
|
|
361
|
+
/>
|
|
362
|
+
</AreaChart>
|
|
515
363
|
);
|
|
516
364
|
}
|
|
517
365
|
```
|