@coinbase/cds-mobile-visualization 3.4.0-beta.23 → 3.4.0-beta.24
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 +6 -0
- package/dts/chart/CartesianChart.d.ts +19 -0
- package/dts/chart/CartesianChart.d.ts.map +1 -1
- package/dts/chart/line/LineChart.d.ts +17 -3
- package/dts/chart/line/LineChart.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberAccessibilityView.d.ts +12 -0
- package/dts/chart/scrubber/ScrubberAccessibilityView.d.ts.map +1 -0
- package/esm/chart/CartesianChart.js +39 -14
- package/esm/chart/__stories__/CartesianChart.stories.js +10 -0
- package/esm/chart/__stories__/ChartAccessibility.stories.js +721 -0
- package/esm/chart/area/__stories__/AreaChart.stories.js +17 -3
- package/esm/chart/axis/__stories__/Axis.stories.js +65 -48
- package/esm/chart/bar/__stories__/BarChart.stories.js +6 -0
- package/esm/chart/line/LineChart.js +22 -1
- package/esm/chart/line/__stories__/LineChart.stories.js +84 -46
- package/esm/chart/scrubber/ScrubberAccessibilityView.js +177 -0
- package/esm/chart/scrubber/__stories__/Scrubber.stories.js +57 -5
- package/package.json +5 -5
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
const _excluded = ["label"],
|
|
2
|
+
_excluded2 = ["style"];
|
|
3
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
4
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
5
|
+
import { forwardRef, memo, useCallback, useMemo, useState } from 'react';
|
|
6
|
+
import { assets } from '@coinbase/cds-common/internal/data/assets';
|
|
7
|
+
import { sparklineInteractiveData } from '@coinbase/cds-common/internal/visualizations/SparklineInteractiveData';
|
|
8
|
+
import { useTabsContext } from '@coinbase/cds-common/tabs/TabsContext';
|
|
9
|
+
import { useTheme } from '@coinbase/cds-mobile';
|
|
10
|
+
import { IconButton } from '@coinbase/cds-mobile/buttons';
|
|
11
|
+
import { ExampleScreen } from '@coinbase/cds-mobile/examples/ExampleScreen';
|
|
12
|
+
import { Box, HStack, VStack } from '@coinbase/cds-mobile/layout';
|
|
13
|
+
import { RemoteImage } from '@coinbase/cds-mobile/media';
|
|
14
|
+
import { SectionHeader } from '@coinbase/cds-mobile/section-header/SectionHeader';
|
|
15
|
+
import { SegmentedTab } from '@coinbase/cds-mobile/tabs/SegmentedTab';
|
|
16
|
+
import { Text } from '@coinbase/cds-mobile/typography';
|
|
17
|
+
import { FontWeight, Skia, TextAlign } from '@shopify/react-native-skia';
|
|
18
|
+
import { XAxis, YAxis } from '../axis';
|
|
19
|
+
import { BarChart } from '../bar/BarChart';
|
|
20
|
+
import { BarPlot } from '../bar/BarPlot';
|
|
21
|
+
import { CartesianChart } from '../CartesianChart';
|
|
22
|
+
import { Legend } from '../legend';
|
|
23
|
+
import { Line, ReferenceLine, SolidLine } from '../line';
|
|
24
|
+
import { LineChart } from '../line/LineChart';
|
|
25
|
+
import { PeriodSelector, PeriodSelectorActiveIndicator } from '../PeriodSelector';
|
|
26
|
+
import { Scrubber } from '../scrubber';
|
|
27
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
28
|
+
const ThinSolidLine = /*#__PURE__*/memo(props => /*#__PURE__*/_jsx(SolidLine, _extends({}, props, {
|
|
29
|
+
strokeWidth: 1
|
|
30
|
+
})));
|
|
31
|
+
const BasicLineChart = /*#__PURE__*/memo(function BasicLineChart() {
|
|
32
|
+
const theme = useTheme();
|
|
33
|
+
const data = useMemo(() => [2, 4, 3, 6, 5, 8, 7], []);
|
|
34
|
+
const categories = useMemo(() => ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], []);
|
|
35
|
+
const getScrubberAccessibilityLabel = useCallback(index => categories[index] + ": " + data[index], [categories, data]);
|
|
36
|
+
return /*#__PURE__*/_jsx(LineChart, {
|
|
37
|
+
enableScrubbing: true,
|
|
38
|
+
showArea: true,
|
|
39
|
+
showXAxis: true,
|
|
40
|
+
showYAxis: true,
|
|
41
|
+
accessibilityLabel: "Line chart with " + data.length + " days of data. Swipe to navigate.",
|
|
42
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
43
|
+
height: 180,
|
|
44
|
+
inset: {
|
|
45
|
+
top: 16,
|
|
46
|
+
right: 16,
|
|
47
|
+
bottom: 0,
|
|
48
|
+
left: 0
|
|
49
|
+
},
|
|
50
|
+
series: [{
|
|
51
|
+
id: 'line',
|
|
52
|
+
data,
|
|
53
|
+
color: theme.color.accentBoldBlue
|
|
54
|
+
}],
|
|
55
|
+
xAxis: {
|
|
56
|
+
data: categories,
|
|
57
|
+
showGrid: true
|
|
58
|
+
},
|
|
59
|
+
yAxis: {
|
|
60
|
+
domain: {
|
|
61
|
+
min: 0
|
|
62
|
+
},
|
|
63
|
+
showGrid: true
|
|
64
|
+
},
|
|
65
|
+
children: /*#__PURE__*/_jsx(Scrubber, {
|
|
66
|
+
hideOverlay: true
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
const DataFormatLineChart = /*#__PURE__*/memo(function DataFormatLineChart() {
|
|
71
|
+
const theme = useTheme();
|
|
72
|
+
const yData = useMemo(() => [2, 5.5, 2, 8.5, 1.5, 5], []);
|
|
73
|
+
const xData = useMemo(() => [1, 2, 3, 5, 8, 10], []);
|
|
74
|
+
const chartAccessibilityLabel = "Chart with uneven X values " + xData.join(', ') + ". " + yData.length + " data points.";
|
|
75
|
+
const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": X value " + xData[index] + ", Y value " + yData[index], [xData, yData]);
|
|
76
|
+
return /*#__PURE__*/_jsx(LineChart, {
|
|
77
|
+
enableScrubbing: true,
|
|
78
|
+
points: true,
|
|
79
|
+
showArea: true,
|
|
80
|
+
showXAxis: true,
|
|
81
|
+
showYAxis: true,
|
|
82
|
+
accessibilityLabel: chartAccessibilityLabel,
|
|
83
|
+
curve: "natural",
|
|
84
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
85
|
+
height: 180,
|
|
86
|
+
inset: {
|
|
87
|
+
top: 16,
|
|
88
|
+
right: 16,
|
|
89
|
+
bottom: 0,
|
|
90
|
+
left: 0
|
|
91
|
+
},
|
|
92
|
+
series: [{
|
|
93
|
+
id: 'line',
|
|
94
|
+
data: yData,
|
|
95
|
+
color: theme.color.accentBoldGreen
|
|
96
|
+
}],
|
|
97
|
+
xAxis: {
|
|
98
|
+
data: xData,
|
|
99
|
+
showLine: true,
|
|
100
|
+
showTickMarks: true,
|
|
101
|
+
showGrid: true
|
|
102
|
+
},
|
|
103
|
+
yAxis: {
|
|
104
|
+
domain: {
|
|
105
|
+
min: 0
|
|
106
|
+
},
|
|
107
|
+
position: 'left',
|
|
108
|
+
showLine: true,
|
|
109
|
+
showTickMarks: true,
|
|
110
|
+
showGrid: true
|
|
111
|
+
},
|
|
112
|
+
children: /*#__PURE__*/_jsx(Scrubber, {
|
|
113
|
+
hideOverlay: true
|
|
114
|
+
})
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
const AccessibilityBarChart = /*#__PURE__*/memo(function AccessibilityBarChart() {
|
|
118
|
+
const theme = useTheme();
|
|
119
|
+
const categories = useMemo(() => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], []);
|
|
120
|
+
const values = useMemo(() => [40, 65, 55, 80, 72, 90], []);
|
|
121
|
+
const getScrubberAccessibilityLabel = useCallback(index => categories[index] + ": " + values[index], [categories, values]);
|
|
122
|
+
return /*#__PURE__*/_jsx(BarChart, {
|
|
123
|
+
enableScrubbing: true,
|
|
124
|
+
showXAxis: true,
|
|
125
|
+
showYAxis: true,
|
|
126
|
+
accessibilityLabel: "Bar chart with " + values.length + " months. Swipe to navigate.",
|
|
127
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
128
|
+
height: 180,
|
|
129
|
+
inset: {
|
|
130
|
+
top: 16,
|
|
131
|
+
right: 16,
|
|
132
|
+
bottom: 0,
|
|
133
|
+
left: 0
|
|
134
|
+
},
|
|
135
|
+
series: [{
|
|
136
|
+
id: 'bars',
|
|
137
|
+
data: values,
|
|
138
|
+
color: theme.color.accentBoldPurple
|
|
139
|
+
}],
|
|
140
|
+
xAxis: {
|
|
141
|
+
data: categories,
|
|
142
|
+
showGrid: true
|
|
143
|
+
},
|
|
144
|
+
yAxis: {
|
|
145
|
+
domain: {
|
|
146
|
+
min: 0
|
|
147
|
+
},
|
|
148
|
+
showGrid: true
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
const AccessibilityHorizontalBarChart = /*#__PURE__*/memo(function AccessibilityHorizontalBarChart() {
|
|
153
|
+
const theme = useTheme();
|
|
154
|
+
const dataset = useMemo(() => [{
|
|
155
|
+
month: 'Jan',
|
|
156
|
+
rainfall: 21
|
|
157
|
+
}, {
|
|
158
|
+
month: 'Feb',
|
|
159
|
+
rainfall: 28
|
|
160
|
+
}, {
|
|
161
|
+
month: 'Mar',
|
|
162
|
+
rainfall: 41
|
|
163
|
+
}, {
|
|
164
|
+
month: 'Apr',
|
|
165
|
+
rainfall: 73
|
|
166
|
+
}, {
|
|
167
|
+
month: 'May',
|
|
168
|
+
rainfall: 99
|
|
169
|
+
}, {
|
|
170
|
+
month: 'June',
|
|
171
|
+
rainfall: 144
|
|
172
|
+
}, {
|
|
173
|
+
month: 'July',
|
|
174
|
+
rainfall: 319
|
|
175
|
+
}, {
|
|
176
|
+
month: 'Aug',
|
|
177
|
+
rainfall: 249
|
|
178
|
+
}, {
|
|
179
|
+
month: 'Sept',
|
|
180
|
+
rainfall: 131
|
|
181
|
+
}, {
|
|
182
|
+
month: 'Oct',
|
|
183
|
+
rainfall: 55
|
|
184
|
+
}, {
|
|
185
|
+
month: 'Nov',
|
|
186
|
+
rainfall: 48
|
|
187
|
+
}, {
|
|
188
|
+
month: 'Dec',
|
|
189
|
+
rainfall: 25
|
|
190
|
+
}], []);
|
|
191
|
+
const getScrubberAccessibilityLabel = useCallback(index => dataset[index].month + ": " + dataset[index].rainfall + "mm rainfall", [dataset]);
|
|
192
|
+
return /*#__PURE__*/_jsx(BarChart, {
|
|
193
|
+
enableScrubbing: true,
|
|
194
|
+
showXAxis: true,
|
|
195
|
+
showYAxis: true,
|
|
196
|
+
accessibilityLabel: "Horizontal bar chart showing Seoul rainfall by month. " + dataset.length + " months. Swipe to navigate.",
|
|
197
|
+
borderRadius: 2,
|
|
198
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
199
|
+
height: 400,
|
|
200
|
+
inset: {
|
|
201
|
+
top: 16,
|
|
202
|
+
right: 16,
|
|
203
|
+
bottom: 0,
|
|
204
|
+
left: 0
|
|
205
|
+
},
|
|
206
|
+
layout: "horizontal",
|
|
207
|
+
series: [{
|
|
208
|
+
id: 'seoul',
|
|
209
|
+
label: 'Seoul rainfall',
|
|
210
|
+
data: dataset.map(d => d.rainfall),
|
|
211
|
+
color: theme.color.accentBoldBlue
|
|
212
|
+
}],
|
|
213
|
+
xAxis: {
|
|
214
|
+
label: 'rainfall (mm)',
|
|
215
|
+
GridLineComponent: props => /*#__PURE__*/_jsx(SolidLine, _extends({}, props, {
|
|
216
|
+
strokeWidth: 1
|
|
217
|
+
})),
|
|
218
|
+
showGrid: true,
|
|
219
|
+
showLine: true,
|
|
220
|
+
showTickMarks: true
|
|
221
|
+
},
|
|
222
|
+
yAxis: {
|
|
223
|
+
position: 'left',
|
|
224
|
+
data: dataset.map(d => d.month),
|
|
225
|
+
showLine: true,
|
|
226
|
+
showTickMarks: true,
|
|
227
|
+
bandTickMarkPlacement: 'edges'
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
const ServiceAvailability = /*#__PURE__*/memo(function ServiceAvailability() {
|
|
232
|
+
const theme = useTheme();
|
|
233
|
+
const availabilityEvents = useMemo(() => [{
|
|
234
|
+
date: new Date('2022-01-01'),
|
|
235
|
+
availability: 79
|
|
236
|
+
}, {
|
|
237
|
+
date: new Date('2022-01-03'),
|
|
238
|
+
availability: 81
|
|
239
|
+
}, {
|
|
240
|
+
date: new Date('2022-01-04'),
|
|
241
|
+
availability: 82
|
|
242
|
+
}, {
|
|
243
|
+
date: new Date('2022-01-06'),
|
|
244
|
+
availability: 91
|
|
245
|
+
}, {
|
|
246
|
+
date: new Date('2022-01-07'),
|
|
247
|
+
availability: 92
|
|
248
|
+
}, {
|
|
249
|
+
date: new Date('2022-01-10'),
|
|
250
|
+
availability: 86
|
|
251
|
+
}], []);
|
|
252
|
+
const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + availabilityEvents[index].availability + "% availability on " + availabilityEvents[index].date.toLocaleDateString(), [availabilityEvents]);
|
|
253
|
+
return /*#__PURE__*/_jsxs(CartesianChart, {
|
|
254
|
+
enableScrubbing: true,
|
|
255
|
+
accessibilityLabel: "Service availability chart with " + availabilityEvents.length + " data points. Swipe to navigate.",
|
|
256
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
257
|
+
height: 200,
|
|
258
|
+
scrubberAccessibilityLabelStep: 1,
|
|
259
|
+
series: [{
|
|
260
|
+
id: 'availability',
|
|
261
|
+
data: availabilityEvents.map(event => event.availability),
|
|
262
|
+
gradient: {
|
|
263
|
+
stops: _ref => {
|
|
264
|
+
let {
|
|
265
|
+
min,
|
|
266
|
+
max
|
|
267
|
+
} = _ref;
|
|
268
|
+
return [{
|
|
269
|
+
offset: min,
|
|
270
|
+
color: theme.color.fgNegative
|
|
271
|
+
}, {
|
|
272
|
+
offset: 85,
|
|
273
|
+
color: theme.color.fgNegative
|
|
274
|
+
}, {
|
|
275
|
+
offset: 85,
|
|
276
|
+
color: theme.color.fgWarning
|
|
277
|
+
}, {
|
|
278
|
+
offset: 90,
|
|
279
|
+
color: theme.color.fgWarning
|
|
280
|
+
}, {
|
|
281
|
+
offset: 90,
|
|
282
|
+
color: theme.color.fgPositive
|
|
283
|
+
}, {
|
|
284
|
+
offset: max,
|
|
285
|
+
color: theme.color.fgPositive
|
|
286
|
+
}];
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}],
|
|
290
|
+
xAxis: {
|
|
291
|
+
data: availabilityEvents.map(event => event.date.getTime())
|
|
292
|
+
},
|
|
293
|
+
yAxis: {
|
|
294
|
+
domain: _ref2 => {
|
|
295
|
+
let {
|
|
296
|
+
min,
|
|
297
|
+
max
|
|
298
|
+
} = _ref2;
|
|
299
|
+
return {
|
|
300
|
+
min: Math.max(min - 2, 0),
|
|
301
|
+
max: Math.min(max + 2, 100)
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
children: [/*#__PURE__*/_jsx(XAxis, {
|
|
306
|
+
showGrid: true,
|
|
307
|
+
showLine: true,
|
|
308
|
+
showTickMarks: true,
|
|
309
|
+
tickLabelFormatter: value => new Date(value).toLocaleDateString()
|
|
310
|
+
}), /*#__PURE__*/_jsx(YAxis, {
|
|
311
|
+
showGrid: true,
|
|
312
|
+
showLine: true,
|
|
313
|
+
showTickMarks: true,
|
|
314
|
+
position: "left",
|
|
315
|
+
tickLabelFormatter: value => value + "%"
|
|
316
|
+
}), /*#__PURE__*/_jsx(Line, {
|
|
317
|
+
curve: "stepAfter",
|
|
318
|
+
points: props => _extends({}, props, {
|
|
319
|
+
fill: theme.color.bg,
|
|
320
|
+
stroke: props.fill
|
|
321
|
+
}),
|
|
322
|
+
seriesId: "availability"
|
|
323
|
+
}), /*#__PURE__*/_jsx(Scrubber, {
|
|
324
|
+
hideOverlay: true
|
|
325
|
+
})]
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
const BasicPricesWithManyPoints = /*#__PURE__*/memo(function BasicPricesWithManyPoints() {
|
|
329
|
+
const theme = useTheme();
|
|
330
|
+
const data = useMemo(() => [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58, 10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58], []);
|
|
331
|
+
const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + data[index], [data]);
|
|
332
|
+
return /*#__PURE__*/_jsx(LineChart, {
|
|
333
|
+
enableScrubbing: true,
|
|
334
|
+
showArea: true,
|
|
335
|
+
accessibilityLabel: "Line chart with " + data.length + " data points. Swipe to navigate.",
|
|
336
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
337
|
+
height: 200,
|
|
338
|
+
scrubberAccessibilityLabelStep: 1,
|
|
339
|
+
series: [{
|
|
340
|
+
id: 'prices',
|
|
341
|
+
data,
|
|
342
|
+
color: theme.color.accentBoldBlue
|
|
343
|
+
}],
|
|
344
|
+
children: /*#__PURE__*/_jsx(Scrubber, {
|
|
345
|
+
hideOverlay: true
|
|
346
|
+
})
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
const PositiveAndNegativeCashFlow = /*#__PURE__*/memo(function PositiveAndNegativeCashFlow() {
|
|
350
|
+
const theme = useTheme();
|
|
351
|
+
const categories = useMemo(() => Array.from({
|
|
352
|
+
length: 31
|
|
353
|
+
}, (_, i) => "3/" + (i + 1)), []);
|
|
354
|
+
const gains = useMemo(() => [5, 0, 6, 18, 0, 5, 12, 0, 12, 22, 28, 18, 0, 12, 6, 0, 0, 24, 0, 0, 4, 0, 18, 0, 0, 14, 10, 16, 0, 0, 0], []);
|
|
355
|
+
const losses = useMemo(() => [-4, 0, -8, -12, -6, 0, 0, 0, -18, 0, -12, 0, -9, -6, 0, 0, 0, 0, -22, -8, 0, 0, -10, -14, 0, 0, 0, 0, 0, -12, -10], []);
|
|
356
|
+
const series = useMemo(() => [{
|
|
357
|
+
id: 'gains',
|
|
358
|
+
data: gains,
|
|
359
|
+
color: theme.color.fgPositive,
|
|
360
|
+
stackId: 'bars'
|
|
361
|
+
}, {
|
|
362
|
+
id: 'losses',
|
|
363
|
+
data: losses,
|
|
364
|
+
color: theme.color.fgNegative,
|
|
365
|
+
stackId: 'bars'
|
|
366
|
+
}], [gains, losses, theme.color.fgNegative, theme.color.fgPositive]);
|
|
367
|
+
const getScrubberAccessibilityLabel = useCallback(index => {
|
|
368
|
+
const net = gains[index] + losses[index];
|
|
369
|
+
const netStr = net >= 0 ? "+$" + net + "M" : "-$" + Math.abs(net) + "M";
|
|
370
|
+
return categories[index] + ": " + netStr;
|
|
371
|
+
}, [categories, gains, losses]);
|
|
372
|
+
return /*#__PURE__*/_jsxs(CartesianChart, {
|
|
373
|
+
enableScrubbing: true,
|
|
374
|
+
accessibilityLabel: "Cash flow chart: " + categories.length + " days with gains and losses. Swipe to navigate.",
|
|
375
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
376
|
+
height: 280,
|
|
377
|
+
inset: 32,
|
|
378
|
+
series: series,
|
|
379
|
+
xAxis: {
|
|
380
|
+
data: categories,
|
|
381
|
+
scaleType: 'band'
|
|
382
|
+
},
|
|
383
|
+
children: [/*#__PURE__*/_jsx(XAxis, {}), /*#__PURE__*/_jsx(YAxis, {
|
|
384
|
+
showGrid: true,
|
|
385
|
+
GridLineComponent: ThinSolidLine,
|
|
386
|
+
tickLabelFormatter: value => "$" + value + "M"
|
|
387
|
+
}), /*#__PURE__*/_jsx(BarPlot, {}), /*#__PURE__*/_jsx(ReferenceLine, {
|
|
388
|
+
LineComponent: SolidLine,
|
|
389
|
+
dataY: 0
|
|
390
|
+
})]
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
const LegendPosition = /*#__PURE__*/memo(function LegendPosition() {
|
|
394
|
+
const theme = useTheme();
|
|
395
|
+
const categories = useMemo(() => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], []);
|
|
396
|
+
const revenueData = useMemo(() => [455, 520, 380, 455, 285, 235], []);
|
|
397
|
+
const profitMarginData = useMemo(() => [23, 20, 16, 38, 12, 9], []);
|
|
398
|
+
const getScrubberAccessibilityLabel = useCallback(index => categories[index] + ": Revenue $" + revenueData[index] + "k, Profit Margin " + profitMarginData[index] + "%", [categories, profitMarginData, revenueData]);
|
|
399
|
+
return /*#__PURE__*/_jsxs(CartesianChart, {
|
|
400
|
+
enableScrubbing: true,
|
|
401
|
+
accessibilityLabel: "Bar chart showing Revenue and Profit Margin by month. January through June. Swipe to navigate.",
|
|
402
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
403
|
+
height: 200,
|
|
404
|
+
inset: {
|
|
405
|
+
bottom: 8,
|
|
406
|
+
left: 0,
|
|
407
|
+
right: 0,
|
|
408
|
+
top: 8
|
|
409
|
+
},
|
|
410
|
+
legend: /*#__PURE__*/_jsx(Legend, {
|
|
411
|
+
accessibilityLabel: "Chart legend: Revenue and Profit Margin",
|
|
412
|
+
justifyContent: "flex-end"
|
|
413
|
+
}),
|
|
414
|
+
legendPosition: "bottom",
|
|
415
|
+
series: [{
|
|
416
|
+
id: 'revenue',
|
|
417
|
+
label: 'Revenue',
|
|
418
|
+
data: revenueData,
|
|
419
|
+
yAxisId: 'revenue',
|
|
420
|
+
color: "rgb(" + theme.spectrum.yellow40 + ")",
|
|
421
|
+
legendShape: 'squircle'
|
|
422
|
+
}, {
|
|
423
|
+
id: 'profitMargin',
|
|
424
|
+
label: 'Profit Margin',
|
|
425
|
+
data: profitMarginData,
|
|
426
|
+
yAxisId: 'profitMargin',
|
|
427
|
+
color: theme.color.fgPositive,
|
|
428
|
+
legendShape: 'squircle'
|
|
429
|
+
}],
|
|
430
|
+
xAxis: {
|
|
431
|
+
data: categories,
|
|
432
|
+
scaleType: 'band',
|
|
433
|
+
range: _ref3 => {
|
|
434
|
+
let {
|
|
435
|
+
min,
|
|
436
|
+
max
|
|
437
|
+
} = _ref3;
|
|
438
|
+
return {
|
|
439
|
+
min,
|
|
440
|
+
max: max - 128
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
yAxis: [{
|
|
445
|
+
id: 'revenue',
|
|
446
|
+
domain: {
|
|
447
|
+
min: 0
|
|
448
|
+
}
|
|
449
|
+
}, {
|
|
450
|
+
id: 'profitMargin',
|
|
451
|
+
domain: {
|
|
452
|
+
max: 100,
|
|
453
|
+
min: 0
|
|
454
|
+
}
|
|
455
|
+
}],
|
|
456
|
+
children: [/*#__PURE__*/_jsx(XAxis, {
|
|
457
|
+
showLine: true,
|
|
458
|
+
showTickMarks: true
|
|
459
|
+
}), /*#__PURE__*/_jsx(YAxis, {
|
|
460
|
+
showGrid: true,
|
|
461
|
+
showLine: true,
|
|
462
|
+
showTickMarks: true,
|
|
463
|
+
axisId: "revenue",
|
|
464
|
+
position: "left",
|
|
465
|
+
requestedTickCount: 5,
|
|
466
|
+
tickLabelFormatter: value => "$" + value + "k",
|
|
467
|
+
width: 60
|
|
468
|
+
}), /*#__PURE__*/_jsx(YAxis, {
|
|
469
|
+
showLine: true,
|
|
470
|
+
showTickMarks: true,
|
|
471
|
+
axisId: "profitMargin",
|
|
472
|
+
position: "right",
|
|
473
|
+
requestedTickCount: 5,
|
|
474
|
+
tickLabelFormatter: value => value + "%"
|
|
475
|
+
}), /*#__PURE__*/_jsx(BarPlot, {})]
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
const AssetPriceWithDottedArea = /*#__PURE__*/memo(function AssetPriceWithDottedArea() {
|
|
479
|
+
const theme = useTheme();
|
|
480
|
+
const fontMgr = useMemo(() => Skia.TypefaceFontProvider.Make(), []);
|
|
481
|
+
const tabs = useMemo(() => [{
|
|
482
|
+
id: 'hour',
|
|
483
|
+
label: '1H'
|
|
484
|
+
}, {
|
|
485
|
+
id: 'day',
|
|
486
|
+
label: '1D'
|
|
487
|
+
}, {
|
|
488
|
+
id: 'week',
|
|
489
|
+
label: '1W'
|
|
490
|
+
}, {
|
|
491
|
+
id: 'month',
|
|
492
|
+
label: '1M'
|
|
493
|
+
}, {
|
|
494
|
+
id: 'year',
|
|
495
|
+
label: '1Y'
|
|
496
|
+
}, {
|
|
497
|
+
id: 'all',
|
|
498
|
+
label: 'All'
|
|
499
|
+
}], []);
|
|
500
|
+
const [timePeriod, setTimePeriod] = useState(tabs[0]);
|
|
501
|
+
const sparklineTimePeriodData = useMemo(() => sparklineInteractiveData[timePeriod.id], [timePeriod]);
|
|
502
|
+
const sparklineTimePeriodDataValues = useMemo(() => sparklineTimePeriodData.map(d => d.value), [sparklineTimePeriodData]);
|
|
503
|
+
const sparklineTimePeriodDataTimestamps = useMemo(() => sparklineTimePeriodData.map(d => d.date), [sparklineTimePeriodData]);
|
|
504
|
+
const currentPrice = sparklineTimePeriodDataValues[sparklineTimePeriodDataValues.length - 1];
|
|
505
|
+
const priceFormatter = useMemo(() => new Intl.NumberFormat('en-US', {
|
|
506
|
+
style: 'currency',
|
|
507
|
+
currency: 'USD'
|
|
508
|
+
}), []);
|
|
509
|
+
const formatPrice = useCallback(price => priceFormatter.format(price), [priceFormatter]);
|
|
510
|
+
const formatDate = useCallback(date => {
|
|
511
|
+
const dayOfWeek = date.toLocaleDateString('en-US', {
|
|
512
|
+
weekday: 'short'
|
|
513
|
+
});
|
|
514
|
+
const monthDay = date.toLocaleDateString('en-US', {
|
|
515
|
+
month: 'short',
|
|
516
|
+
day: 'numeric'
|
|
517
|
+
});
|
|
518
|
+
const time = date.toLocaleTimeString('en-US', {
|
|
519
|
+
hour: 'numeric',
|
|
520
|
+
minute: '2-digit',
|
|
521
|
+
hour12: true
|
|
522
|
+
});
|
|
523
|
+
return dayOfWeek + ", " + monthDay + ", " + time;
|
|
524
|
+
}, []);
|
|
525
|
+
const chartAccessibilityLabel = useMemo(() => "Bitcoin price chart for " + timePeriod.label + " period. Current price: " + formatPrice(currentPrice) + ".", [currentPrice, formatPrice, timePeriod.label]);
|
|
526
|
+
const getScrubberAccessibilityLabel = useCallback(index => {
|
|
527
|
+
const price = formatPrice(sparklineTimePeriodDataValues[index]);
|
|
528
|
+
const date = formatDate(sparklineTimePeriodDataTimestamps[index]);
|
|
529
|
+
return price + " " + date;
|
|
530
|
+
}, [formatDate, formatPrice, sparklineTimePeriodDataTimestamps, sparklineTimePeriodDataValues]);
|
|
531
|
+
const BTCTab = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref4, ref) => {
|
|
532
|
+
let {
|
|
533
|
+
label
|
|
534
|
+
} = _ref4,
|
|
535
|
+
props = _objectWithoutPropertiesLoose(_ref4, _excluded);
|
|
536
|
+
const {
|
|
537
|
+
activeTab
|
|
538
|
+
} = useTabsContext();
|
|
539
|
+
const isActive = (activeTab == null ? void 0 : activeTab.id) === props.id;
|
|
540
|
+
return /*#__PURE__*/_jsx(SegmentedTab, _extends({
|
|
541
|
+
ref: ref,
|
|
542
|
+
label: /*#__PURE__*/_jsx(Text, {
|
|
543
|
+
font: "label1",
|
|
544
|
+
style: {
|
|
545
|
+
color: isActive ? assets.btc.color : undefined
|
|
546
|
+
},
|
|
547
|
+
children: label
|
|
548
|
+
})
|
|
549
|
+
}, props));
|
|
550
|
+
}));
|
|
551
|
+
const BTCActiveIndicator = /*#__PURE__*/memo(_ref5 => {
|
|
552
|
+
let {
|
|
553
|
+
style
|
|
554
|
+
} = _ref5,
|
|
555
|
+
props = _objectWithoutPropertiesLoose(_ref5, _excluded2);
|
|
556
|
+
return /*#__PURE__*/_jsx(PeriodSelectorActiveIndicator, _extends({}, props, {
|
|
557
|
+
style: [style, {
|
|
558
|
+
backgroundColor: assets.btc.color + "1A"
|
|
559
|
+
}]
|
|
560
|
+
}));
|
|
561
|
+
});
|
|
562
|
+
const onPeriodChange = useCallback(period => setTimePeriod(period || tabs[0]), [tabs]);
|
|
563
|
+
return /*#__PURE__*/_jsxs(VStack, {
|
|
564
|
+
gap: 2,
|
|
565
|
+
children: [/*#__PURE__*/_jsx(SectionHeader, {
|
|
566
|
+
balance: /*#__PURE__*/_jsx(Text, {
|
|
567
|
+
font: "title2",
|
|
568
|
+
children: formatPrice(currentPrice)
|
|
569
|
+
}),
|
|
570
|
+
end: /*#__PURE__*/_jsx(VStack, {
|
|
571
|
+
justifyContent: "center",
|
|
572
|
+
children: /*#__PURE__*/_jsx(RemoteImage, {
|
|
573
|
+
shape: "circle",
|
|
574
|
+
size: "xl",
|
|
575
|
+
source: assets.btc.imageUrl
|
|
576
|
+
})
|
|
577
|
+
}),
|
|
578
|
+
title: /*#__PURE__*/_jsx(Text, {
|
|
579
|
+
font: "title1",
|
|
580
|
+
children: "Bitcoin"
|
|
581
|
+
})
|
|
582
|
+
}), /*#__PURE__*/_jsx(LineChart, {
|
|
583
|
+
enableScrubbing: true,
|
|
584
|
+
showArea: true,
|
|
585
|
+
accessibilityLabel: chartAccessibilityLabel,
|
|
586
|
+
areaType: "dotted",
|
|
587
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
588
|
+
height: 200,
|
|
589
|
+
inset: {
|
|
590
|
+
top: 52
|
|
591
|
+
},
|
|
592
|
+
series: [{
|
|
593
|
+
id: 'btc',
|
|
594
|
+
data: sparklineTimePeriodDataValues,
|
|
595
|
+
color: assets.btc.color
|
|
596
|
+
}],
|
|
597
|
+
children: /*#__PURE__*/_jsx(Scrubber, {
|
|
598
|
+
hideOverlay: true,
|
|
599
|
+
idlePulse: true,
|
|
600
|
+
labelElevated: true,
|
|
601
|
+
label: d => {
|
|
602
|
+
const date = formatDate(sparklineTimePeriodDataTimestamps[d]);
|
|
603
|
+
const price = formatPrice(sparklineTimePeriodDataValues[d]);
|
|
604
|
+
const regularStyle = {
|
|
605
|
+
fontFamilies: ['Inter'],
|
|
606
|
+
fontSize: 14,
|
|
607
|
+
fontStyle: {
|
|
608
|
+
weight: FontWeight.Normal
|
|
609
|
+
},
|
|
610
|
+
color: Skia.Color(theme.color.fgMuted)
|
|
611
|
+
};
|
|
612
|
+
const boldStyle = _extends({}, regularStyle, {
|
|
613
|
+
fontStyle: {
|
|
614
|
+
weight: FontWeight.Bold
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
const builder = Skia.ParagraphBuilder.Make({
|
|
618
|
+
textAlign: TextAlign.Left
|
|
619
|
+
}, fontMgr);
|
|
620
|
+
builder.pushStyle(boldStyle);
|
|
621
|
+
builder.addText(price);
|
|
622
|
+
builder.pushStyle(regularStyle);
|
|
623
|
+
builder.addText(" " + date);
|
|
624
|
+
const para = builder.build();
|
|
625
|
+
para.layout(512);
|
|
626
|
+
return para;
|
|
627
|
+
}
|
|
628
|
+
})
|
|
629
|
+
}), /*#__PURE__*/_jsx(PeriodSelector, {
|
|
630
|
+
TabComponent: BTCTab,
|
|
631
|
+
TabsActiveIndicatorComponent: BTCActiveIndicator,
|
|
632
|
+
activeTab: timePeriod,
|
|
633
|
+
onChange: onPeriodChange,
|
|
634
|
+
tabs: tabs
|
|
635
|
+
})]
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
function ExampleNavigator() {
|
|
639
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
640
|
+
const examples = useMemo(() => [{
|
|
641
|
+
title: 'Basic Line Chart',
|
|
642
|
+
component: /*#__PURE__*/_jsx(BasicLineChart, {})
|
|
643
|
+
}, {
|
|
644
|
+
title: 'Data Format (Uneven X)',
|
|
645
|
+
component: /*#__PURE__*/_jsx(DataFormatLineChart, {})
|
|
646
|
+
}, {
|
|
647
|
+
title: 'Bar Chart',
|
|
648
|
+
component: /*#__PURE__*/_jsx(AccessibilityBarChart, {})
|
|
649
|
+
}, {
|
|
650
|
+
title: 'Horizontal Bar Chart',
|
|
651
|
+
component: /*#__PURE__*/_jsx(AccessibilityHorizontalBarChart, {})
|
|
652
|
+
}, {
|
|
653
|
+
title: 'Service Availability',
|
|
654
|
+
component: /*#__PURE__*/_jsx(ServiceAvailability, {})
|
|
655
|
+
}, {
|
|
656
|
+
title: 'Basic Prices (28 pts, step 1)',
|
|
657
|
+
component: /*#__PURE__*/_jsx(BasicPricesWithManyPoints, {})
|
|
658
|
+
}, {
|
|
659
|
+
title: 'Positive/Negative Cash Flow',
|
|
660
|
+
component: /*#__PURE__*/_jsx(PositiveAndNegativeCashFlow, {})
|
|
661
|
+
}, {
|
|
662
|
+
title: 'Legend Position',
|
|
663
|
+
component: /*#__PURE__*/_jsx(LegendPosition, {})
|
|
664
|
+
}, {
|
|
665
|
+
title: 'Bitcoin Price (Dotted Area)',
|
|
666
|
+
component: /*#__PURE__*/_jsx(AssetPriceWithDottedArea, {})
|
|
667
|
+
}], []);
|
|
668
|
+
const currentExample = examples[currentIndex];
|
|
669
|
+
const handlePrevious = useCallback(() => {
|
|
670
|
+
setCurrentIndex(prev => (prev - 1 + examples.length) % examples.length);
|
|
671
|
+
}, [examples.length]);
|
|
672
|
+
const handleNext = useCallback(() => {
|
|
673
|
+
setCurrentIndex(prev => (prev + 1 + examples.length) % examples.length);
|
|
674
|
+
}, [examples.length]);
|
|
675
|
+
return /*#__PURE__*/_jsx(ExampleScreen, {
|
|
676
|
+
paddingX: 0,
|
|
677
|
+
children: /*#__PURE__*/_jsxs(VStack, {
|
|
678
|
+
gap: 4,
|
|
679
|
+
children: [/*#__PURE__*/_jsxs(HStack, {
|
|
680
|
+
alignItems: "center",
|
|
681
|
+
justifyContent: "space-between",
|
|
682
|
+
padding: 2,
|
|
683
|
+
children: [/*#__PURE__*/_jsx(IconButton, {
|
|
684
|
+
accessibilityHint: "Navigate to previous example",
|
|
685
|
+
accessibilityLabel: "Previous",
|
|
686
|
+
name: "arrowLeft",
|
|
687
|
+
onPress: handlePrevious,
|
|
688
|
+
variant: "secondary"
|
|
689
|
+
}), /*#__PURE__*/_jsxs(VStack, {
|
|
690
|
+
alignItems: "center",
|
|
691
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
692
|
+
font: "title3",
|
|
693
|
+
children: currentExample.title
|
|
694
|
+
}), /*#__PURE__*/_jsxs(Text, {
|
|
695
|
+
color: "fgMuted",
|
|
696
|
+
font: "label1",
|
|
697
|
+
children: [currentIndex + 1, " / ", examples.length]
|
|
698
|
+
})]
|
|
699
|
+
}), /*#__PURE__*/_jsx(IconButton, {
|
|
700
|
+
accessibilityHint: "Navigate to next example",
|
|
701
|
+
accessibilityLabel: "Next",
|
|
702
|
+
name: "arrowRight",
|
|
703
|
+
onPress: handleNext,
|
|
704
|
+
variant: "secondary"
|
|
705
|
+
})]
|
|
706
|
+
}), /*#__PURE__*/_jsxs(VStack, {
|
|
707
|
+
gap: 2,
|
|
708
|
+
padding: 2,
|
|
709
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
710
|
+
color: "fgMuted",
|
|
711
|
+
font: "label2",
|
|
712
|
+
children: "Swipe to navigate chart segments."
|
|
713
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
714
|
+
padding: 1,
|
|
715
|
+
children: currentExample.component
|
|
716
|
+
})]
|
|
717
|
+
})]
|
|
718
|
+
})
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
export default ExampleNavigator;
|