@automattic/charts 4.14.0 → 4.15.0
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 +10 -0
- package/TOKENS.md +1 -1
- package/dist/index.cjs +1249 -325
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +31 -0
- package/dist/index.d.cts +41 -7
- package/dist/index.d.ts +41 -7
- package/dist/index.js +964 -325
- package/dist/index.js.map +1 -1
- package/package.json +9 -8
- package/src/charts/area-chart/area-chart.tsx +29 -20
- package/src/charts/area-chart/types.ts +3 -1
- package/src/charts/bar-chart/bar-chart.module.scss +38 -0
- package/src/charts/bar-chart/bar-chart.tsx +159 -56
- package/src/charts/bar-chart/private/band-tooltip.tsx +40 -5
- package/src/charts/bar-chart/private/bar-layer.tsx +66 -13
- package/src/charts/bar-chart/private/category.ts +25 -0
- package/src/charts/bar-chart/private/comparison-bars-geometry.ts +13 -1
- package/src/charts/bar-chart/private/index.ts +3 -1
- package/src/charts/bar-chart/private/selected-bar-ring.tsx +17 -6
- package/src/charts/bar-chart/private/stack-layout.ts +99 -0
- package/src/charts/bar-chart/private/stacked-bar-series.tsx +145 -0
- package/src/charts/bar-chart/private/test/stack-layout.test.ts +81 -0
- package/src/charts/bar-chart/private/test/value-domain.test.ts +10 -0
- package/src/charts/bar-chart/private/use-bar-chart-options.ts +35 -11
- package/src/charts/bar-chart/private/{use-overlap-slots.ts → use-bar-slots.ts} +36 -38
- package/src/charts/bar-chart/private/use-bar-stops.ts +19 -19
- package/src/charts/bar-chart/private/value-domain.ts +10 -8
- package/src/charts/bar-chart/test/bar-chart-stacked.test.tsx +546 -0
- package/src/charts/bar-chart/test/bar-chart.test.tsx +75 -0
- package/src/charts/bar-chart/test/use-bar-legend-items.test.tsx +18 -0
- package/src/charts/bar-chart/types.ts +3 -1
- package/src/charts/bar-chart/use-bar-colors.ts +12 -0
- package/src/charts/bar-chart/use-bar-legend-items.ts +4 -2
- package/src/charts/bar-list-chart/bar-list-chart.tsx +2 -0
- package/src/charts/line-chart/line-chart.tsx +55 -26
- package/src/charts/line-chart/test/line-chart.test.tsx +86 -0
- package/src/charts/line-chart/types.ts +3 -1
- package/src/charts/private/test/compact-when-short.test.tsx +170 -0
- package/src/charts/private/test/tick-decimals.test.tsx +95 -0
- package/src/charts/private/tick-decimals.tsx +132 -0
- package/src/charts/private/use-compact-when-short.ts +18 -0
- package/src/providers/chart-context/themes.ts +4 -0
- package/src/types.ts +35 -2
- package/src/charts/private/test/whole-number-ticks.test.tsx +0 -57
- package/src/charts/private/whole-number-ticks.tsx +0 -79
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { DataContext } from '@visx/xychart';
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
import { isReading } from './readings';
|
|
4
|
+
import type { SeriesData } from '../../types';
|
|
5
|
+
import type { ReactNode } from 'react';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Whether every reading in the series is a whole number.
|
|
9
|
+
*
|
|
10
|
+
* @param series - The series visx renders.
|
|
11
|
+
* @return True when at least one reading exists and none has a fraction.
|
|
12
|
+
*/
|
|
13
|
+
export const hasOnlyWholeNumbers = ( series: SeriesData[] ): boolean => {
|
|
14
|
+
let sawReading = false;
|
|
15
|
+
for ( const { data } of series ) {
|
|
16
|
+
for ( const point of data ) {
|
|
17
|
+
const value = point?.value;
|
|
18
|
+
if ( ! isReading( value ) ) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if ( ! Number.isInteger( value ) ) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
sawReading = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return sawReading;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Float error in tick * 10^decimals grows with the value, e.g. 0.07 * 100 = 7.000000000000001.
|
|
31
|
+
const EPSILON = 1e-12;
|
|
32
|
+
const tolerance = ( scaled: number ): number => EPSILON * Math.max( 1, Math.abs( scaled ) );
|
|
33
|
+
|
|
34
|
+
const isValidDecimals = ( decimals: number | undefined ): decimals is number =>
|
|
35
|
+
Number.isInteger( decimals ) && ( decimals as number ) >= 0;
|
|
36
|
+
|
|
37
|
+
const isOnDecimals = ( value: number, decimals: number ): boolean => {
|
|
38
|
+
const scaled = value * 10 ** decimals;
|
|
39
|
+
return Math.abs( scaled - Math.round( scaled ) ) < tolerance( scaled );
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The scale's ticks with those finer than `decimals` places dropped.
|
|
44
|
+
*
|
|
45
|
+
* d3 steps by 1, 2 or 5 times a power of ten, so every multiple of 10^-decimals inside the domain is one of its ticks.
|
|
46
|
+
*
|
|
47
|
+
* @param scale - The value scale visx built.
|
|
48
|
+
* @param count - Ticks to ask the scale for; undefined uses the scale's own default, as visx does.
|
|
49
|
+
* @param decimals - Decimal places a tick may carry; 0 keeps whole numbers.
|
|
50
|
+
* @return The kept ticks, or undefined when visx's own ticks need no change.
|
|
51
|
+
*/
|
|
52
|
+
export const getTickDecimalValues = (
|
|
53
|
+
scale: unknown,
|
|
54
|
+
count?: number,
|
|
55
|
+
decimals = 0
|
|
56
|
+
): number[] | undefined => {
|
|
57
|
+
const ticks = ( scale as { ticks?: ( count?: number ) => unknown[] } )?.ticks?.( count );
|
|
58
|
+
if ( ! ticks?.every( ( tick ): tick is number => typeof tick === 'number' ) ) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const kept = ticks.filter( tick => isOnDecimals( tick, decimals ) );
|
|
62
|
+
return kept.length > 1 && kept.length < ticks.length ? kept : undefined;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A value domain widened to the nearest `decimals` steps when fewer than two fit inside it, so the axis shows at least two ticks.
|
|
67
|
+
*
|
|
68
|
+
* @param domain - The domain the chart would scale to.
|
|
69
|
+
* @param decimals - The axis's `tickDecimals`.
|
|
70
|
+
* @return The widened domain, or undefined when `domain` needs no change.
|
|
71
|
+
*/
|
|
72
|
+
export const getTickDecimalsDomain = (
|
|
73
|
+
domain: [ number, number ] | null | undefined,
|
|
74
|
+
decimals: number | undefined
|
|
75
|
+
): [ number, number ] | undefined => {
|
|
76
|
+
if ( ! domain || ! isValidDecimals( decimals ) ) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const scale = 10 ** decimals;
|
|
80
|
+
const low = domain[ 0 ] * scale;
|
|
81
|
+
const high = domain[ 1 ] * scale;
|
|
82
|
+
if ( Math.floor( high + tolerance( high ) ) - Math.ceil( low - tolerance( low ) ) >= 1 ) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
const floor = Math.floor( low + tolerance( low ) );
|
|
86
|
+
// Keeps one step when float noise rounds both ends to the same value.
|
|
87
|
+
const ceil = Math.max( Math.ceil( high - tolerance( high ) ), floor + 1 );
|
|
88
|
+
return [ floor / scale, ceil / scale ];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The decimals a value axis's ticks are held to: 0 for whole-number data, else the caller's `tickDecimals`.
|
|
93
|
+
*
|
|
94
|
+
* @param hasWholeNumberValues - Whether every plotted value is a whole number.
|
|
95
|
+
* @param tickDecimals - The axis's `tickDecimals`.
|
|
96
|
+
* @return Decimal places, or undefined to keep visx's ticks.
|
|
97
|
+
*/
|
|
98
|
+
export const getTickDecimals = (
|
|
99
|
+
hasWholeNumberValues: boolean,
|
|
100
|
+
tickDecimals: number | undefined
|
|
101
|
+
): number | undefined => {
|
|
102
|
+
if ( hasWholeNumberValues ) {
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
return isValidDecimals( tickDecimals ) ? tickDecimals : undefined;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
type TickDecimalsProps = {
|
|
109
|
+
axis: 'x' | 'y';
|
|
110
|
+
numTicks?: number;
|
|
111
|
+
decimals: number | undefined;
|
|
112
|
+
children: ( tickValues: number[] | undefined ) => ReactNode;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Hands its children the chart's value-scale ticks, held to `decimals` places.
|
|
117
|
+
*
|
|
118
|
+
* @param props - Component props.
|
|
119
|
+
* @param props.axis - Which scale carries the values.
|
|
120
|
+
* @param props.numTicks - Ticks to ask the scale for.
|
|
121
|
+
* @param props.decimals - Decimal places a tick may carry, or undefined to keep visx's ticks.
|
|
122
|
+
* @param props.children - Renders the axis and grid with the tick values.
|
|
123
|
+
* @return The rendered children.
|
|
124
|
+
*/
|
|
125
|
+
export const TickDecimals = ( { axis, numTicks, decimals, children }: TickDecimalsProps ) => {
|
|
126
|
+
const { xScale, yScale } = useContext( DataContext );
|
|
127
|
+
const tickValues =
|
|
128
|
+
decimals === undefined
|
|
129
|
+
? undefined
|
|
130
|
+
: getTickDecimalValues( axis === 'x' ? xScale : yScale, numTicks, decimals );
|
|
131
|
+
return <>{ children( tickValues ) }</>;
|
|
132
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useGlobalChartsTheme } from '../../providers';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Whether a `compactWhenShort` chart is compact, and the margin it then defaults to.
|
|
5
|
+
*
|
|
6
|
+
* Reads the height the chart was given, not the measured plot area: that grows once the legend
|
|
7
|
+
* is hidden and would flip the chart straight back. A zero height is unmeasured, not short.
|
|
8
|
+
*
|
|
9
|
+
* @param enabled - The chart's `compactWhenShort` prop.
|
|
10
|
+
* @param height - The height the chart was given.
|
|
11
|
+
* @return Whether the chart is compact, and the compact margin when it is.
|
|
12
|
+
*/
|
|
13
|
+
export const useCompactWhenShort = ( enabled: boolean, height: number | undefined ) => {
|
|
14
|
+
const { compactWhenShort } = useGlobalChartsTheme();
|
|
15
|
+
const isCompact = enabled && ( height ?? 0 ) > 0 && height < compactWhenShort.below;
|
|
16
|
+
|
|
17
|
+
return { isCompact, compactMargin: isCompact ? compactWhenShort.margin : undefined };
|
|
18
|
+
};
|
|
@@ -56,6 +56,10 @@ const defaultTheme: CompleteChartTheme = {
|
|
|
56
56
|
margin: { top: 2, right: 2, bottom: 2, left: 2 },
|
|
57
57
|
strokeWidth: 1.5,
|
|
58
58
|
},
|
|
59
|
+
compactWhenShort: {
|
|
60
|
+
below: 140,
|
|
61
|
+
margin: { top: 2, right: 2, bottom: 2, left: 2 },
|
|
62
|
+
},
|
|
59
63
|
// The compact 11px square / 2px gap is the contribution-graph rhythm, which has no WPDS dimension.
|
|
60
64
|
heatmapChart: {
|
|
61
65
|
compactCellGap: 2,
|
package/src/types.ts
CHANGED
|
@@ -317,9 +317,9 @@ export type BarStyles = {
|
|
|
317
317
|
};
|
|
318
318
|
|
|
319
319
|
/**
|
|
320
|
-
* How a bar chart places its series in a category. `grouped` puts each primary series in a slot of its own; `overlap` puts every primary in one slot and every comparison in a second, and overlaps the `group`s within each slot.
|
|
320
|
+
* How a bar chart places its series in a category. `grouped` puts each primary series in a slot of its own; `overlap` puts every primary in one slot and every comparison in a second, and overlaps the `group`s within each slot; `stacked` stacks every primary in one bar, the first series at the bottom.
|
|
321
321
|
*/
|
|
322
|
-
export type BarChartLayout = 'grouped' | 'overlap';
|
|
322
|
+
export type BarChartLayout = 'grouped' | 'overlap' | 'stacked';
|
|
323
323
|
|
|
324
324
|
export type MultipleDataPointsDate = {
|
|
325
325
|
label: string;
|
|
@@ -437,6 +437,18 @@ export type ChartTheme = {
|
|
|
437
437
|
/** Stroke width for the sparkline line */
|
|
438
438
|
strokeWidth?: number;
|
|
439
439
|
};
|
|
440
|
+
/** Compact mode for `compactWhenShort` line, area and bar charts */
|
|
441
|
+
compactWhenShort?: {
|
|
442
|
+
/** Height (px) below which the chart turns compact */
|
|
443
|
+
below?: number;
|
|
444
|
+
/** Margin the chart defaults to while compact */
|
|
445
|
+
margin?: {
|
|
446
|
+
top?: number;
|
|
447
|
+
right?: number;
|
|
448
|
+
bottom?: number;
|
|
449
|
+
left?: number;
|
|
450
|
+
};
|
|
451
|
+
};
|
|
440
452
|
/**
|
|
441
453
|
* HeatmapChart settings. Cell gap, radius, value size and the selection ring come from
|
|
442
454
|
* WPDS tokens in CSS, so only the compact sizing lives here.
|
|
@@ -467,6 +479,9 @@ export type CompleteChartTheme = Required< ChartTheme > & {
|
|
|
467
479
|
sparkline: Required< NonNullable< ChartTheme[ 'sparkline' ] > > & {
|
|
468
480
|
margin: Required< NonNullable< ChartTheme[ 'sparkline' ] >[ 'margin' ] >;
|
|
469
481
|
};
|
|
482
|
+
compactWhenShort: Required< NonNullable< ChartTheme[ 'compactWhenShort' ] > > & {
|
|
483
|
+
margin: Required< NonNullable< ChartTheme[ 'compactWhenShort' ] >[ 'margin' ] >;
|
|
484
|
+
};
|
|
470
485
|
heatmapChart: Required< NonNullable< ChartTheme[ 'heatmapChart' ] > >;
|
|
471
486
|
};
|
|
472
487
|
|
|
@@ -520,6 +535,12 @@ export type AxisOptions = {
|
|
|
520
535
|
* so callers can force a specific axis (e.g. integer-only steps on a sparse chart).
|
|
521
536
|
*/
|
|
522
537
|
tickValues?: ScaleInput< AxisScale >[];
|
|
538
|
+
/**
|
|
539
|
+
* Most decimal places a value-axis tick may carry, so labels rounded to that precision never repeat;
|
|
540
|
+
* an axis holding fewer than two steps widens to the nearest ones. Whole-number data always uses 0.
|
|
541
|
+
* Ignored on a log scale, or when `tickValues` or the value scale's `domain` is set. Line and bar charts only.
|
|
542
|
+
*/
|
|
543
|
+
tickDecimals?: number;
|
|
523
544
|
axisClassName?: string;
|
|
524
545
|
axisLineClassName?: string;
|
|
525
546
|
labelClassName?: string;
|
|
@@ -709,6 +730,18 @@ export interface SeriesVisibilityProps {
|
|
|
709
730
|
defaultHiddenSeries?: readonly string[];
|
|
710
731
|
}
|
|
711
732
|
|
|
733
|
+
/**
|
|
734
|
+
* Compact mode for cartesian charts placed in short containers.
|
|
735
|
+
*/
|
|
736
|
+
export interface CompactWhenShortProps {
|
|
737
|
+
/**
|
|
738
|
+
* Drop the axes, grid and legend, and default to `theme.compactWhenShort.margin`, while the
|
|
739
|
+
* chart is shorter than `theme.compactWhenShort.below`. Series hidden through the legend stay
|
|
740
|
+
* hidden until the chart is tall again. Horizontal bar charts ignore it.
|
|
741
|
+
*/
|
|
742
|
+
compactWhenShort?: boolean;
|
|
743
|
+
}
|
|
744
|
+
|
|
712
745
|
/**
|
|
713
746
|
* Base properties shared across all chart components
|
|
714
747
|
*/
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { createScale } from '@visx/scale';
|
|
2
|
-
import { getWholeNumberTickValues, hasOnlyWholeNumbers } from '../whole-number-ticks';
|
|
3
|
-
import type { SeriesData } from '../../../types';
|
|
4
|
-
|
|
5
|
-
const linear = ( domain: [ number, number ] ) =>
|
|
6
|
-
createScale( { type: 'linear', domain, range: [ 100, 0 ] } );
|
|
7
|
-
|
|
8
|
-
const series = ( ...values: Array< number | null > ): SeriesData => ( {
|
|
9
|
-
label: 'A',
|
|
10
|
-
data: values.map( ( value, i ) => ( { date: new Date( 2024, i, 1 ), value } ) ),
|
|
11
|
-
} );
|
|
12
|
-
|
|
13
|
-
describe( 'getWholeNumberTickValues', () => {
|
|
14
|
-
it( 'keeps only the whole ticks of a range smaller than the tick count', () => {
|
|
15
|
-
expect( getWholeNumberTickValues( linear( [ 0, 1 ] ), 4 ) ).toEqual( [ 0, 1 ] );
|
|
16
|
-
expect( getWholeNumberTickValues( linear( [ 0, 2 ] ), 4 ) ).toEqual( [ 0, 1, 2 ] );
|
|
17
|
-
} );
|
|
18
|
-
|
|
19
|
-
it( 'leaves a scale whose ticks are already whole to visx', () => {
|
|
20
|
-
expect( getWholeNumberTickValues( linear( [ 0, 1000 ] ), 4 ) ).toBeUndefined();
|
|
21
|
-
} );
|
|
22
|
-
|
|
23
|
-
it( 'leaves non-numeric scales to visx', () => {
|
|
24
|
-
const band = createScale( { type: 'band', domain: [ 'a', 'b' ], range: [ 0, 100 ] } );
|
|
25
|
-
const time = createScale( {
|
|
26
|
-
type: 'time',
|
|
27
|
-
domain: [ new Date( 2024, 0, 1 ), new Date( 2024, 0, 2 ) ],
|
|
28
|
-
range: [ 0, 100 ],
|
|
29
|
-
} );
|
|
30
|
-
expect( getWholeNumberTickValues( band, 4 ) ).toBeUndefined();
|
|
31
|
-
expect( getWholeNumberTickValues( time, 4 ) ).toBeUndefined();
|
|
32
|
-
expect( getWholeNumberTickValues( undefined, 4 ) ).toBeUndefined();
|
|
33
|
-
} );
|
|
34
|
-
|
|
35
|
-
it( 'leaves a range with no whole tick to visx', () => {
|
|
36
|
-
expect( getWholeNumberTickValues( linear( [ 0.2, 0.8 ] ), 4 ) ).toBeUndefined();
|
|
37
|
-
} );
|
|
38
|
-
|
|
39
|
-
it( 'leaves a range with only one whole tick to visx', () => {
|
|
40
|
-
expect( getWholeNumberTickValues( linear( [ 0, 0.8 ] ), 4 ) ).toBeUndefined();
|
|
41
|
-
} );
|
|
42
|
-
} );
|
|
43
|
-
|
|
44
|
-
describe( 'hasOnlyWholeNumbers', () => {
|
|
45
|
-
it( 'is true when every reading is whole, skipping missing ones', () => {
|
|
46
|
-
expect( hasOnlyWholeNumbers( [ series( 0, 1, null, 3 ) ] ) ).toBe( true );
|
|
47
|
-
} );
|
|
48
|
-
|
|
49
|
-
it( 'is false when any reading has a fraction', () => {
|
|
50
|
-
expect( hasOnlyWholeNumbers( [ series( 0, 1 ), series( 0.5 ) ] ) ).toBe( false );
|
|
51
|
-
} );
|
|
52
|
-
|
|
53
|
-
it( 'is false when there is no reading at all', () => {
|
|
54
|
-
expect( hasOnlyWholeNumbers( [ series( null, null ) ] ) ).toBe( false );
|
|
55
|
-
expect( hasOnlyWholeNumbers( [] ) ).toBe( false );
|
|
56
|
-
} );
|
|
57
|
-
} );
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { DataContext } from '@visx/xychart';
|
|
2
|
-
import { useContext } from 'react';
|
|
3
|
-
import { isReading } from './readings';
|
|
4
|
-
import type { SeriesData } from '../../types';
|
|
5
|
-
import type { ReactNode } from 'react';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Whether every reading in the series is a whole number.
|
|
9
|
-
*
|
|
10
|
-
* @param series - The series visx renders.
|
|
11
|
-
* @return True when at least one reading exists and none has a fraction.
|
|
12
|
-
*/
|
|
13
|
-
export const hasOnlyWholeNumbers = ( series: SeriesData[] ): boolean => {
|
|
14
|
-
let sawReading = false;
|
|
15
|
-
for ( const { data } of series ) {
|
|
16
|
-
for ( const point of data ) {
|
|
17
|
-
const value = point?.value;
|
|
18
|
-
if ( ! isReading( value ) ) {
|
|
19
|
-
continue;
|
|
20
|
-
}
|
|
21
|
-
if ( ! Number.isInteger( value ) ) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
sawReading = true;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return sawReading;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The scale's ticks with the fractional ones dropped.
|
|
32
|
-
*
|
|
33
|
-
* d3 steps by 1, 2 or 5 times a power of ten, so every whole number inside the domain is one of its ticks.
|
|
34
|
-
*
|
|
35
|
-
* @param scale - The value scale visx built.
|
|
36
|
-
* @param count - Ticks to ask the scale for; undefined uses the scale's own default, as visx does.
|
|
37
|
-
* @return Whole-number ticks, or undefined when visx's own ticks need no change.
|
|
38
|
-
*/
|
|
39
|
-
export const getWholeNumberTickValues = (
|
|
40
|
-
scale: unknown,
|
|
41
|
-
count?: number
|
|
42
|
-
): number[] | undefined => {
|
|
43
|
-
const ticks = ( scale as { ticks?: ( count?: number ) => unknown[] } )?.ticks?.( count );
|
|
44
|
-
if ( ! ticks?.every( ( tick ): tick is number => typeof tick === 'number' ) ) {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
const whole = ticks.filter( tick => Number.isInteger( tick ) );
|
|
48
|
-
return whole.length > 1 && whole.length < ticks.length ? whole : undefined;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
type WholeNumberTicksProps = {
|
|
52
|
-
axis: 'x' | 'y';
|
|
53
|
-
numTicks?: number;
|
|
54
|
-
enabled: boolean;
|
|
55
|
-
children: ( tickValues: number[] | undefined ) => ReactNode;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Hands its children the whole-number ticks of the chart's value scale.
|
|
60
|
-
*
|
|
61
|
-
* @param props - Component props.
|
|
62
|
-
* @param props.axis - Which scale carries the values.
|
|
63
|
-
* @param props.numTicks - Ticks to ask the scale for.
|
|
64
|
-
* @param props.enabled - Whether the plotted values are all whole numbers and the caller pinned neither the ticks nor the value domain.
|
|
65
|
-
* @param props.children - Renders the axis and grid with the tick values.
|
|
66
|
-
* @return The rendered children.
|
|
67
|
-
*/
|
|
68
|
-
export const WholeNumberTicks = ( {
|
|
69
|
-
axis,
|
|
70
|
-
numTicks,
|
|
71
|
-
enabled,
|
|
72
|
-
children,
|
|
73
|
-
}: WholeNumberTicksProps ) => {
|
|
74
|
-
const { xScale, yScale } = useContext( DataContext );
|
|
75
|
-
const tickValues = enabled
|
|
76
|
-
? getWholeNumberTickValues( axis === 'x' ? xScale : yScale, numTicks )
|
|
77
|
-
: undefined;
|
|
78
|
-
return <>{ children( tickValues ) }</>;
|
|
79
|
-
};
|