@coinbase/cds-mobile-visualization 3.4.0-beta.10 → 3.4.0-beta.12
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/dts/chart/axis/Axis.d.ts +19 -41
- package/dts/chart/axis/Axis.d.ts.map +1 -1
- package/dts/chart/axis/XAxis.d.ts.map +1 -1
- package/dts/chart/axis/YAxis.d.ts.map +1 -1
- package/dts/chart/line/Line.d.ts +13 -11
- package/dts/chart/line/Line.d.ts.map +1 -1
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -1
- package/dts/chart/utils/axis.d.ts +25 -1
- package/dts/chart/utils/axis.d.ts.map +1 -1
- package/dts/chart/utils/point.d.ts +17 -12
- package/dts/chart/utils/point.d.ts.map +1 -1
- package/dts/chart/utils/scale.d.ts +11 -0
- package/dts/chart/utils/scale.d.ts.map +1 -1
- package/esm/chart/axis/Axis.js +5 -41
- package/esm/chart/axis/XAxis.js +102 -27
- package/esm/chart/axis/YAxis.js +100 -23
- package/esm/chart/axis/__stories__/Axis.stories.js +259 -0
- package/esm/chart/bar/__stories__/BarChart.stories.js +39 -0
- package/esm/chart/scrubber/DefaultScrubberBeacon.js +21 -21
- package/esm/chart/utils/axis.js +45 -29
- package/esm/chart/utils/point.js +64 -21
- package/esm/chart/utils/scale.js +13 -2
- package/package.json +5 -5
package/esm/chart/utils/axis.js
CHANGED
|
@@ -3,10 +3,41 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
|
|
|
3
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
4
|
import { useCallback, useMemo, useState } from 'react';
|
|
5
5
|
import { getChartDomain, getChartRange, isValidBounds } from './chart';
|
|
6
|
+
import { getPointOnScale } from './point';
|
|
6
7
|
import { getCategoricalScale, getNumericScale, isCategoricalScale, isNumericScale } from './scale';
|
|
7
8
|
export const defaultAxisId = 'DEFAULT_AXIS_ID';
|
|
8
9
|
export const defaultAxisScaleType = 'linear';
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Position options for band scale axis elements (grid lines, tick marks, labels).
|
|
13
|
+
*
|
|
14
|
+
* - `'start'` - At the start of each step (before bar padding)
|
|
15
|
+
* - `'middle'` - At the center of each band
|
|
16
|
+
* - `'end'` - At the end of each step (after bar padding)
|
|
17
|
+
* - `'edges'` - At start of each tick, plus end for the last tick (encloses the chart)
|
|
18
|
+
*
|
|
19
|
+
* @note These properties only apply when using a band scale (`scaleType: 'band'`).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Converts an AxisBandPlacement to the corresponding PointAnchor for use with getPointOnScale.
|
|
24
|
+
*
|
|
25
|
+
* @param placement - The axis placement value
|
|
26
|
+
* @returns The corresponding PointAnchor for scale calculations
|
|
27
|
+
*/
|
|
28
|
+
export const toPointAnchor = placement => {
|
|
29
|
+
switch (placement) {
|
|
30
|
+
case 'edges': // edges uses stepStart for each tick, stepEnd handled separately
|
|
31
|
+
case 'start':
|
|
32
|
+
return 'stepStart';
|
|
33
|
+
case 'end':
|
|
34
|
+
return 'stepEnd';
|
|
35
|
+
case 'middle':
|
|
36
|
+
default:
|
|
37
|
+
return 'middle';
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
10
41
|
/**
|
|
11
42
|
* Axis configuration with computed bounds
|
|
12
43
|
*/
|
|
@@ -457,6 +488,7 @@ const generateEvenlyDistributedTicks = (scale, tickInterval, possibleTickValues,
|
|
|
457
488
|
* // Returns tick positions centered in each selected band
|
|
458
489
|
*/
|
|
459
490
|
export const getAxisTicksData = _ref4 => {
|
|
491
|
+
var _options$anchor;
|
|
460
492
|
let {
|
|
461
493
|
ticks,
|
|
462
494
|
scaleFunction,
|
|
@@ -466,53 +498,37 @@ export const getAxisTicksData = _ref4 => {
|
|
|
466
498
|
tickInterval,
|
|
467
499
|
options
|
|
468
500
|
} = _ref4;
|
|
501
|
+
const anchor = (_options$anchor = options == null ? void 0 : options.anchor) != null ? _options$anchor : 'middle';
|
|
502
|
+
|
|
469
503
|
// Handle band scales
|
|
470
504
|
if (isCategoricalScale(scaleFunction)) {
|
|
505
|
+
const bandScale = scaleFunction;
|
|
506
|
+
|
|
471
507
|
// If explicit ticks are provided as array, use them
|
|
472
508
|
if (Array.isArray(ticks)) {
|
|
473
|
-
return ticks.filter(index => index >= 0 && index < categories.length).map(index => {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
if (position === undefined) return null;
|
|
478
|
-
return {
|
|
479
|
-
tick: index,
|
|
480
|
-
position: position + ((_bandwidth = scaleFunction.bandwidth == null ? void 0 : scaleFunction.bandwidth()) != null ? _bandwidth : 0) / 2
|
|
481
|
-
};
|
|
482
|
-
}).filter(Boolean);
|
|
509
|
+
return ticks.filter(index => index >= 0 && index < categories.length).map(index => ({
|
|
510
|
+
tick: index,
|
|
511
|
+
position: getPointOnScale(index, bandScale, anchor)
|
|
512
|
+
}));
|
|
483
513
|
}
|
|
484
514
|
|
|
485
515
|
// If a tick function is provided, use it to filter
|
|
486
516
|
if (typeof ticks === 'function') {
|
|
487
517
|
return categories.map((category, index) => {
|
|
488
|
-
var _bandwidth2;
|
|
489
518
|
if (!ticks(index)) return null;
|
|
490
|
-
|
|
491
|
-
// Band scales expect numeric indices, not category strings
|
|
492
|
-
const position = scaleFunction(index);
|
|
493
|
-
if (position === undefined) return null;
|
|
494
519
|
return {
|
|
495
520
|
tick: index,
|
|
496
|
-
position:
|
|
521
|
+
position: getPointOnScale(index, bandScale, anchor)
|
|
497
522
|
};
|
|
498
523
|
}).filter(Boolean);
|
|
499
524
|
}
|
|
500
|
-
if (typeof ticks === 'boolean' && !ticks) {
|
|
501
|
-
return [];
|
|
502
|
-
}
|
|
503
525
|
|
|
504
526
|
// For band scales without explicit ticks, show all categories
|
|
505
527
|
// requestedTickCount is ignored for categorical scales - use ticks parameter to control visibility
|
|
506
|
-
return categories.map((
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
if (position === undefined) return null;
|
|
511
|
-
return {
|
|
512
|
-
tick: index,
|
|
513
|
-
position: position + ((_bandwidth3 = scaleFunction.bandwidth == null ? void 0 : scaleFunction.bandwidth()) != null ? _bandwidth3 : 0) / 2
|
|
514
|
-
};
|
|
515
|
-
}).filter(Boolean);
|
|
528
|
+
return categories.map((_, index) => ({
|
|
529
|
+
tick: index,
|
|
530
|
+
position: getPointOnScale(index, bandScale, anchor)
|
|
531
|
+
}));
|
|
516
532
|
}
|
|
517
533
|
|
|
518
534
|
// Handle numeric scales
|
package/esm/chart/utils/point.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applySerializableScale, isCategoricalScale, isLogScale, isNumericScale } from './scale';
|
|
1
|
+
import { applyBandScale, applySerializableScale, isCategoricalScale, isLogScale, isNumericScale } from './scale';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Position a label should be placed relative to the point
|
|
@@ -10,19 +10,38 @@ import { applySerializableScale, isCategoricalScale, isLogScale, isNumericScale
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Get a point from a data value and a scale.
|
|
13
|
-
*
|
|
14
|
-
* @
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
17
|
-
* @returns
|
|
13
|
+
*
|
|
14
|
+
* @param dataValue - The data value to convert to a pixel position.
|
|
15
|
+
* @param scale - The scale function.
|
|
16
|
+
* @param anchor (@default 'middle') - For band scales, where to anchor the point within the band.
|
|
17
|
+
* @returns The pixel value (@default 0 if data value is not defined in scale).
|
|
18
18
|
*/
|
|
19
|
-
export const getPointOnScale = (dataValue, scale)
|
|
20
|
-
var
|
|
19
|
+
export const getPointOnScale = function (dataValue, scale, anchor) {
|
|
20
|
+
var _scale;
|
|
21
|
+
if (anchor === void 0) {
|
|
22
|
+
anchor = 'middle';
|
|
23
|
+
}
|
|
21
24
|
if (isCategoricalScale(scale)) {
|
|
22
|
-
var
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
25
|
+
var _bandScale$bandwidth, _bandScale$step;
|
|
26
|
+
const bandScale = scale;
|
|
27
|
+
const bandStart = bandScale(dataValue);
|
|
28
|
+
if (bandStart === undefined) return 0;
|
|
29
|
+
const bandwidth = (_bandScale$bandwidth = bandScale.bandwidth == null ? void 0 : bandScale.bandwidth()) != null ? _bandScale$bandwidth : 0;
|
|
30
|
+
const step = (_bandScale$step = bandScale.step == null ? void 0 : bandScale.step()) != null ? _bandScale$step : bandwidth;
|
|
31
|
+
const paddingOffset = (step - bandwidth) / 2;
|
|
32
|
+
const stepStart = bandStart - paddingOffset;
|
|
33
|
+
switch (anchor) {
|
|
34
|
+
case 'stepStart':
|
|
35
|
+
return stepStart;
|
|
36
|
+
case 'bandStart':
|
|
37
|
+
return bandStart;
|
|
38
|
+
case 'middle':
|
|
39
|
+
return bandStart + bandwidth / 2;
|
|
40
|
+
case 'bandEnd':
|
|
41
|
+
return bandStart + bandwidth;
|
|
42
|
+
case 'stepEnd':
|
|
43
|
+
return stepStart + step;
|
|
44
|
+
}
|
|
26
45
|
}
|
|
27
46
|
|
|
28
47
|
// For log scales, ensure the value is positive
|
|
@@ -30,23 +49,47 @@ export const getPointOnScale = (dataValue, scale) => {
|
|
|
30
49
|
if (isLogScale(scale) && dataValue <= 0) {
|
|
31
50
|
adjustedValue = 0.001; // Use a small positive value for log scales
|
|
32
51
|
}
|
|
33
|
-
return (
|
|
52
|
+
return (_scale = scale(adjustedValue)) != null ? _scale : 0;
|
|
34
53
|
};
|
|
35
54
|
|
|
36
55
|
/**
|
|
37
56
|
* Get a point from a data value and a serializable scale (worklet-compatible).
|
|
38
|
-
*
|
|
39
|
-
* @
|
|
40
|
-
* @param
|
|
41
|
-
* @param
|
|
42
|
-
* @returns
|
|
57
|
+
*
|
|
58
|
+
* @param dataValue - The data value to convert to a pixel position.
|
|
59
|
+
* @param scale - The serializable scale function.
|
|
60
|
+
* @param anchor (@default 'middle') - For band scales, where to anchor the point within the band.
|
|
61
|
+
* @returns The pixel value (@default 0 if data value is not defined in scale).
|
|
43
62
|
*/
|
|
44
|
-
export function getPointOnSerializableScale(dataValue, scale) {
|
|
63
|
+
export function getPointOnSerializableScale(dataValue, scale, anchor) {
|
|
45
64
|
'worklet';
|
|
46
65
|
|
|
66
|
+
// Handle band scales with the specified position
|
|
67
|
+
if (anchor === void 0) {
|
|
68
|
+
anchor = 'middle';
|
|
69
|
+
}
|
|
47
70
|
if (scale.type === 'band') {
|
|
48
|
-
const
|
|
49
|
-
|
|
71
|
+
const bandScale = scale;
|
|
72
|
+
const [domainMin, domainMax] = bandScale.domain;
|
|
73
|
+
const index = dataValue - domainMin;
|
|
74
|
+
const n = domainMax - domainMin + 1;
|
|
75
|
+
if (index < 0 || index >= n) {
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
const bandStart = applyBandScale(dataValue, bandScale);
|
|
79
|
+
const paddingOffset = (bandScale.step - bandScale.bandwidth) / 2;
|
|
80
|
+
const stepStart = bandStart - paddingOffset;
|
|
81
|
+
switch (anchor) {
|
|
82
|
+
case 'stepStart':
|
|
83
|
+
return stepStart;
|
|
84
|
+
case 'bandStart':
|
|
85
|
+
return bandStart;
|
|
86
|
+
case 'middle':
|
|
87
|
+
return bandStart + bandScale.bandwidth / 2;
|
|
88
|
+
case 'bandEnd':
|
|
89
|
+
return bandStart + bandScale.bandwidth;
|
|
90
|
+
case 'stepEnd':
|
|
91
|
+
return stepStart + bandScale.step;
|
|
92
|
+
}
|
|
50
93
|
}
|
|
51
94
|
|
|
52
95
|
// For log scales, ensure the value is positive
|
package/esm/chart/utils/scale.js
CHANGED
|
@@ -53,10 +53,21 @@ export const getCategoricalScale = _ref2 => {
|
|
|
53
53
|
const domainArray = Array.from({
|
|
54
54
|
length: domain.max - domain.min + 1
|
|
55
55
|
}, (_, i) => i);
|
|
56
|
-
const scale = scaleBand().domain(domainArray).range([range.min, range.max]).padding(padding);
|
|
56
|
+
const scale = scaleBand().domain(domainArray).range([range.min, range.max]).paddingInner(padding).paddingOuter(padding / 2);
|
|
57
57
|
return scale;
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Anchor position for points on a scale. Currently used only for band scales.
|
|
62
|
+
*
|
|
63
|
+
* For band scales, this determines where within the band to position a point:
|
|
64
|
+
* - `'stepStart'` - At the start of the step
|
|
65
|
+
* - `'bandStart'` - At the start of the band
|
|
66
|
+
* - `'middle'` - At the center of the band
|
|
67
|
+
* - `'bandEnd'` - At the end of the band
|
|
68
|
+
* - `'stepEnd'` - At the end of the step
|
|
69
|
+
*/
|
|
70
|
+
|
|
60
71
|
/**
|
|
61
72
|
* Convert a D3 scale to a serializable scale configuration that can be used in worklets
|
|
62
73
|
*/
|
|
@@ -176,7 +187,7 @@ export function applyBandScale(value, scale) {
|
|
|
176
187
|
if (index < 0 || index >= n) {
|
|
177
188
|
return r0;
|
|
178
189
|
}
|
|
179
|
-
const paddingOffset = step - scale.bandwidth;
|
|
190
|
+
const paddingOffset = (step - scale.bandwidth) / 2;
|
|
180
191
|
const bandStart = r0 + step * index + paddingOffset;
|
|
181
192
|
return bandStart;
|
|
182
193
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coinbase/cds-mobile-visualization",
|
|
3
|
-
"version": "3.4.0-beta.
|
|
3
|
+
"version": "3.4.0-beta.12",
|
|
4
4
|
"description": "Coinbase Design System - Mobile Visualization Native",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"CHANGELOG"
|
|
37
37
|
],
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@coinbase/cds-common": "^8.
|
|
39
|
+
"@coinbase/cds-common": "^8.36.2",
|
|
40
40
|
"@coinbase/cds-lottie-files": "^3.3.4",
|
|
41
|
-
"@coinbase/cds-mobile": "^8.
|
|
41
|
+
"@coinbase/cds-mobile": "^8.36.2",
|
|
42
42
|
"@coinbase/cds-utils": "^2.3.5",
|
|
43
43
|
"@shopify/react-native-skia": "^1.12.4 || ^2.0.0",
|
|
44
44
|
"react": "^18.3.1",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"@babel/preset-env": "^7.28.0",
|
|
58
58
|
"@babel/preset-react": "^7.27.1",
|
|
59
59
|
"@babel/preset-typescript": "^7.27.1",
|
|
60
|
-
"@coinbase/cds-common": "^8.
|
|
60
|
+
"@coinbase/cds-common": "^8.36.2",
|
|
61
61
|
"@coinbase/cds-lottie-files": "^3.3.4",
|
|
62
|
-
"@coinbase/cds-mobile": "^8.
|
|
62
|
+
"@coinbase/cds-mobile": "^8.36.2",
|
|
63
63
|
"@coinbase/cds-utils": "^2.3.5",
|
|
64
64
|
"@figma/code-connect": "^1.3.4",
|
|
65
65
|
"@shopify/react-native-skia": "1.12.4",
|