Skip to content

Commit 883f848

Browse files
committedSep 11, 2021
feat(radial-bar): support custom datum via generic
1 parent aa9ea04 commit 883f848

File tree

8 files changed

+82
-77
lines changed

8 files changed

+82
-77
lines changed
 

‎packages/radial-bar/src/RadialBar.tsx

+11-11
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ import { createElement, Fragment, ReactNode } from 'react'
22
import { Container, useDimensions, SvgWrapper, clampArc } from '@nivo/core'
33
import { ArcLabelsLayer } from '@nivo/arcs'
44
import { BoxLegendSvg } from '@nivo/legends'
5-
import { RadialBarLayerId, RadialBarSvgProps, ComputedBar } from './types'
5+
import { RadialBarLayerId, RadialBarSvgProps, ComputedBar, RadialBarDatum } from './types'
66
import { svgDefaultProps } from './props'
77
import { useRadialBar } from './hooks'
88
import { RadialBarArcs } from './RadialBarArcs'
99
import { PolarGrid } from './polar_grid'
1010
import { RadialBarTracks } from './RadialBarTracks'
1111
import { RadialAxis } from './radial_axis'
1212

13-
type InnerRadialBarProps = Omit<
14-
RadialBarSvgProps,
13+
type InnerRadialBarProps<D extends RadialBarDatum = RadialBarDatum> = Omit<
14+
RadialBarSvgProps<D>,
1515
'animate' | 'motionConfig' | 'renderWrapper' | 'theme'
1616
>
1717

18-
const InnerRadialBar = ({
18+
const InnerRadialBar = <D extends RadialBarDatum>({
1919
data,
2020
valueFormat,
2121
startAngle: originalStartAngle = svgDefaultProps.startAngle,
@@ -53,7 +53,7 @@ const InnerRadialBar = ({
5353
ariaLabel,
5454
ariaLabelledBy,
5555
ariaDescribedBy,
56-
}: InnerRadialBarProps) => {
56+
}: InnerRadialBarProps<D>) => {
5757
const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(
5858
width,
5959
height,
@@ -71,7 +71,7 @@ const InnerRadialBar = ({
7171
tracks,
7272
legendData,
7373
customLayerProps,
74-
} = useRadialBar({
74+
} = useRadialBar<D>({
7575
data,
7676
valueFormat,
7777
startAngle,
@@ -141,7 +141,7 @@ const InnerRadialBar = ({
141141

142142
if (layers.includes('bars')) {
143143
layerById.bars = (
144-
<RadialBarArcs
144+
<RadialBarArcs<D>
145145
key="bars"
146146
center={center}
147147
bars={bars}
@@ -161,7 +161,7 @@ const InnerRadialBar = ({
161161

162162
if (layers.includes('labels') && enableLabels) {
163163
layerById.labels = (
164-
<ArcLabelsLayer<ComputedBar>
164+
<ArcLabelsLayer<ComputedBar<D>>
165165
key="labels"
166166
center={center}
167167
data={bars}
@@ -211,14 +211,14 @@ const InnerRadialBar = ({
211211
)
212212
}
213213

214-
export const RadialBar = ({
214+
export const RadialBar = <D extends RadialBarDatum = RadialBarDatum>({
215215
isInteractive = svgDefaultProps.isInteractive,
216216
animate = svgDefaultProps.animate,
217217
motionConfig = svgDefaultProps.motionConfig,
218218
theme,
219219
renderWrapper,
220220
...otherProps
221-
}: RadialBarSvgProps) => (
221+
}: RadialBarSvgProps<D>) => (
222222
<Container
223223
{...{
224224
animate,
@@ -228,6 +228,6 @@ export const RadialBar = ({
228228
theme,
229229
}}
230230
>
231-
<InnerRadialBar isInteractive={isInteractive} {...otherProps} />
231+
<InnerRadialBar<D> isInteractive={isInteractive} {...otherProps} />
232232
</Container>
233233
)

‎packages/radial-bar/src/RadialBarArcs.tsx

+19-19
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
import { createElement, MouseEvent, useCallback } from 'react'
22
import { ArcsLayer, ArcGenerator } from '@nivo/arcs'
33
import { useTooltip } from '@nivo/tooltip'
4-
import { ComputedBar, RadialBarCommonProps } from './types'
4+
import { ComputedBar, RadialBarCommonProps, RadialBarDatum } from './types'
55

6-
interface RadialBarArcsProps {
6+
interface RadialBarArcsProps<D extends RadialBarDatum> {
77
center: [number, number]
8-
bars: ComputedBar[]
9-
borderWidth: RadialBarCommonProps['borderWidth']
10-
borderColor: RadialBarCommonProps['borderColor']
8+
bars: ComputedBar<D>[]
9+
borderWidth: RadialBarCommonProps<D>['borderWidth']
10+
borderColor: RadialBarCommonProps<D>['borderColor']
1111
arcGenerator: ArcGenerator
12-
isInteractive: RadialBarCommonProps['isInteractive']
13-
tooltip: RadialBarCommonProps['tooltip']
14-
onClick?: RadialBarCommonProps['onClick']
15-
onMouseEnter?: RadialBarCommonProps['onMouseEnter']
16-
onMouseMove?: RadialBarCommonProps['onMouseMove']
17-
onMouseLeave?: RadialBarCommonProps['onMouseLeave']
18-
transitionMode: RadialBarCommonProps['transitionMode']
12+
isInteractive: RadialBarCommonProps<D>['isInteractive']
13+
tooltip: RadialBarCommonProps<D>['tooltip']
14+
onClick?: RadialBarCommonProps<D>['onClick']
15+
onMouseEnter?: RadialBarCommonProps<D>['onMouseEnter']
16+
onMouseMove?: RadialBarCommonProps<D>['onMouseMove']
17+
onMouseLeave?: RadialBarCommonProps<D>['onMouseLeave']
18+
transitionMode: RadialBarCommonProps<D>['transitionMode']
1919
}
2020

21-
export const RadialBarArcs = ({
21+
export const RadialBarArcs = <D extends RadialBarDatum>({
2222
center,
2323
bars,
2424
borderWidth,
@@ -31,42 +31,42 @@ export const RadialBarArcs = ({
3131
onMouseMove,
3232
onMouseLeave,
3333
transitionMode,
34-
}: RadialBarArcsProps) => {
34+
}: RadialBarArcsProps<D>) => {
3535
const { showTooltipFromEvent, hideTooltip } = useTooltip()
3636

3737
const handleClick = useCallback(
38-
(bar: ComputedBar, event: MouseEvent) => {
38+
(bar: ComputedBar<D>, event: MouseEvent) => {
3939
onClick?.(bar, event)
4040
},
4141
[onClick]
4242
)
4343

4444
const handleMouseEnter = useCallback(
45-
(bar: ComputedBar, event: MouseEvent) => {
45+
(bar: ComputedBar<D>, event: MouseEvent) => {
4646
showTooltipFromEvent(createElement(tooltip, { bar }), event)
4747
onMouseEnter?.(bar, event)
4848
},
4949
[showTooltipFromEvent, tooltip, onMouseEnter]
5050
)
5151

5252
const handleMouseMove = useCallback(
53-
(bar: ComputedBar, event: MouseEvent) => {
53+
(bar: ComputedBar<D>, event: MouseEvent) => {
5454
showTooltipFromEvent(createElement(tooltip, { bar }), event)
5555
onMouseMove?.(bar, event)
5656
},
5757
[showTooltipFromEvent, tooltip, onMouseMove]
5858
)
5959

6060
const handleMouseLeave = useCallback(
61-
(bar: ComputedBar, event: MouseEvent) => {
61+
(bar: ComputedBar<D>, event: MouseEvent) => {
6262
hideTooltip()
6363
onMouseLeave?.(bar, event)
6464
},
6565
[hideTooltip, onMouseLeave]
6666
)
6767

6868
return (
69-
<ArcsLayer<ComputedBar>
69+
<ArcsLayer<ComputedBar<D>>
7070
center={center}
7171
data={bars}
7272
arcGenerator={arcGenerator}

‎packages/radial-bar/src/RadialBarTooltip.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BasicTooltip } from '@nivo/tooltip'
2-
import { RadialBarTooltipProps } from './types'
2+
import { RadialBarDatum, RadialBarTooltipProps } from './types'
33

4-
export const RadialBarTooltip = ({ bar }: RadialBarTooltipProps) => {
4+
export const RadialBarTooltip = <D extends RadialBarDatum>({ bar }: RadialBarTooltipProps<D>) => {
55
return (
66
<BasicTooltip
77
enableChip
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { ResponsiveWrapper } from '@nivo/core'
2-
import { RadialBarSvgProps } from './types'
2+
import { RadialBarDatum, RadialBarSvgProps } from './types'
33
import { RadialBar } from './RadialBar'
44

5-
export const ResponsiveRadialBar = (props: Omit<RadialBarSvgProps, 'height' | 'width'>) => (
5+
export const ResponsiveRadialBar = <D extends RadialBarDatum = RadialBarDatum>(
6+
props: Omit<RadialBarSvgProps<D>, 'height' | 'width'>
7+
) => (
68
<ResponsiveWrapper>
7-
{({ width, height }) => <RadialBar width={width} height={height} {...props} />}
9+
{({ width, height }) => <RadialBar<D> width={width} height={height} {...props} />}
810
</ResponsiveWrapper>
911
)

‎packages/radial-bar/src/hooks.ts

+17-17
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@ import {
99
ComputedBar,
1010
RadialBarCommonProps,
1111
RadialBarDataProps,
12-
RadialBarSerie,
1312
RadialBarCustomLayerProps,
1413
RadialBarTrackDatum,
14+
RadialBarDatum,
1515
} from './types'
1616

17-
interface RadialBarGroup {
17+
interface RadialBarGroup<D extends RadialBarDatum> {
1818
id: string
1919
total: number
20-
data: RadialBarSerie['data']
20+
data: D[]
2121
}
2222

23-
export const useRadialBar = ({
23+
export const useRadialBar = <D extends RadialBarDatum = RadialBarDatum>({
2424
data,
2525
valueFormat,
2626
startAngle = commonDefaultProps.startAngle,
@@ -33,25 +33,25 @@ export const useRadialBar = ({
3333
colors = commonDefaultProps.colors,
3434
tracksColor = commonDefaultProps.tracksColor,
3535
}: {
36-
data: RadialBarDataProps['data']
37-
valueFormat?: RadialBarCommonProps['valueFormat']
38-
startAngle: RadialBarCommonProps['startAngle']
39-
padding: RadialBarCommonProps['padding']
40-
padAngle: RadialBarCommonProps['padAngle']
41-
cornerRadius: RadialBarCommonProps['cornerRadius']
42-
endAngle: RadialBarCommonProps['endAngle']
36+
data: RadialBarDataProps<D>['data']
37+
valueFormat?: RadialBarCommonProps<D>['valueFormat']
38+
startAngle: RadialBarCommonProps<D>['startAngle']
39+
padding: RadialBarCommonProps<D>['padding']
40+
padAngle: RadialBarCommonProps<D>['padAngle']
41+
cornerRadius: RadialBarCommonProps<D>['cornerRadius']
42+
endAngle: RadialBarCommonProps<D>['endAngle']
4343
width: number
4444
height: number
45-
colors: RadialBarCommonProps['colors']
46-
tracksColor: RadialBarCommonProps['tracksColor']
45+
colors: RadialBarCommonProps<D>['colors']
46+
tracksColor: RadialBarCommonProps<D>['tracksColor']
4747
}) => {
4848
// using a hook, not because it's costly to compute, but because this is used as
4949
// a dependency for other hooks, and otherwise a new array would be created all
5050
// the time, forcing recomputing everything.
5151
const center: [number, number] = useMemo(() => [width / 2, height / 2], [width, height])
5252
const outerRadius = Math.min(...center)
5353

54-
const getColor = useOrdinalColorScale<ComputedBar>(colors, 'category')
54+
const getColor = useOrdinalColorScale<ComputedBar<D>>(colors, 'category')
5555

5656
// the way categories are being extracted is a bit fragile, because it's extracted from the data,
5757
// so if the first group doesn't contain the first expected category for example, then the order
@@ -61,7 +61,7 @@ export const useRadialBar = ({
6161
const result: {
6262
serieIds: string[]
6363
categories: string[]
64-
groups: RadialBarGroup[]
64+
groups: RadialBarGroup<D>[]
6565
maxValue: number
6666
} = {
6767
serieIds: [],
@@ -122,7 +122,7 @@ export const useRadialBar = ({
122122
const formatValue = useValueFormatter<number>(valueFormat)
123123

124124
const bars = useMemo(() => {
125-
const innerBars: ComputedBar[] = []
125+
const innerBars: ComputedBar<D>[] = []
126126

127127
groups.forEach(group => {
128128
let currentValue = 0
@@ -132,7 +132,7 @@ export const useRadialBar = ({
132132
group.data.forEach(datum => {
133133
const stackedValue = currentValue + datum.y
134134

135-
const computedDatum: ComputedBar = {
135+
const computedDatum: ComputedBar<D> = {
136136
id: `${group.id}.${datum.x}`,
137137
data: datum,
138138
groupId: group.id,

‎packages/radial-bar/src/polar_grid/RadialGrid.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useMotionConfig, useTheme } from '@nivo/core'
55

66
interface PolarGridProps {
77
scale: ScaleLinear<number, number>
8+
ticks?: number | number[]
89
innerRadius: number
910
outerRadius: number
1011
}

‎packages/radial-bar/src/types.ts

+25-23
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ export interface RadialBarDatum {
1818
y: number
1919
}
2020

21-
export interface RadialBarSerie {
21+
export interface RadialBarSerie<D extends RadialBarDatum = RadialBarDatum> {
2222
id: string
23-
data: RadialBarDatum[]
23+
data: D[]
2424
}
2525

26-
export interface ComputedBar {
26+
export interface ComputedBar<D extends RadialBarDatum = RadialBarDatum> {
2727
id: string
28-
data: RadialBarDatum
28+
data: D
2929
groupId: string
3030
category: string
3131
value: number
@@ -35,24 +35,24 @@ export interface ComputedBar {
3535
arc: Arc
3636
}
3737

38-
export interface RadialBarDataProps {
39-
data: RadialBarSerie[]
38+
export interface RadialBarDataProps<D extends RadialBarDatum = RadialBarDatum> {
39+
data: RadialBarSerie<D>[]
4040
}
4141

4242
export type RadialBarLayerId = 'grid' | 'tracks' | 'bars' | 'labels' | 'legends'
4343

44-
export interface RadialBarCustomLayerProps {
44+
export interface RadialBarCustomLayerProps<D extends RadialBarDatum = RadialBarDatum> {
4545
center: [number, number]
4646
outerRadius: number
47-
bars: ComputedBar[]
47+
bars: ComputedBar<D>[]
4848
arcGenerator: ArcGenerator
4949
radiusScale: ScaleBand<string>
5050
valueScale: ScaleLinear<number, number>
5151
}
5252
export type RadialBarCustomLayer = FunctionComponent<RadialBarCustomLayerProps>
5353

54-
export interface RadialBarTooltipProps {
55-
bar: ComputedBar
54+
export interface RadialBarTooltipProps<D extends RadialBarDatum = RadialBarDatum> {
55+
bar: ComputedBar<D>
5656
}
5757
export type RadialBarTooltipComponent = FunctionComponent<RadialBarTooltipProps>
5858

@@ -62,15 +62,15 @@ export interface RadialBarTrackDatum {
6262
arc: Arc
6363
}
6464

65-
export type RadialBarCommonProps = {
65+
export type RadialBarCommonProps<D extends RadialBarDatum = RadialBarDatum> = {
6666
valueFormat: ValueFormat<number>
6767

6868
margin: Box
6969

7070
theme: Theme
71-
colors: OrdinalColorScaleConfig<Omit<ComputedBar, 'color'>>
71+
colors: OrdinalColorScaleConfig<Omit<ComputedBar<D>, 'color'>>
7272
borderWidth: number
73-
borderColor: InheritedColorConfig<ComputedBar>
73+
borderColor: InheritedColorConfig<ComputedBar<D>>
7474
padAngle: number
7575
cornerRadius: number
7676

@@ -90,17 +90,17 @@ export type RadialBarCommonProps = {
9090
radialAxisEnd: RadialAxisConfig | null
9191

9292
enableLabels: boolean
93-
label: PropertyAccessor<ComputedBar, string>
94-
labelsSkipAngle: ArcLabelsProps<ComputedBar>['arcLabelsSkipAngle']
95-
labelsRadiusOffset: ArcLabelsProps<ComputedBar>['arcLabelsRadiusOffset']
96-
labelsTextColor: ArcLabelsProps<ComputedBar>['arcLabelsTextColor']
93+
label: PropertyAccessor<ComputedBar<D>, string>
94+
labelsSkipAngle: ArcLabelsProps<ComputedBar<D>>['arcLabelsSkipAngle']
95+
labelsRadiusOffset: ArcLabelsProps<ComputedBar<D>>['arcLabelsRadiusOffset']
96+
labelsTextColor: ArcLabelsProps<ComputedBar<D>>['arcLabelsTextColor']
9797

9898
isInteractive: boolean
9999
tooltip: RadialBarTooltipComponent
100-
onClick: (bar: ComputedBar, event: MouseEvent) => void
101-
onMouseEnter: (bar: ComputedBar, event: MouseEvent) => void
102-
onMouseMove: (bar: ComputedBar, event: MouseEvent) => void
103-
onMouseLeave: (bar: ComputedBar, event: MouseEvent) => void
100+
onClick: (bar: ComputedBar<D>, event: MouseEvent) => void
101+
onMouseEnter: (bar: ComputedBar<D>, event: MouseEvent) => void
102+
onMouseMove: (bar: ComputedBar<D>, event: MouseEvent) => void
103+
onMouseLeave: (bar: ComputedBar<D>, event: MouseEvent) => void
104104

105105
legends: LegendProps[]
106106

@@ -114,7 +114,9 @@ export type RadialBarCommonProps = {
114114
ariaDescribedBy: AriaAttributes['aria-describedby']
115115
}
116116

117-
export type RadialBarSvgProps = Partial<RadialBarCommonProps> &
118-
RadialBarDataProps &
117+
export type RadialBarSvgProps<D extends RadialBarDatum = RadialBarDatum> = Partial<
118+
RadialBarCommonProps<D>
119+
> &
120+
RadialBarDataProps<D> &
119121
Dimensions &
120122
ModernMotionProps

‎website/src/pages/radial-bar/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import mapper from '../../data/components/radar/mapper'
66
import { groups } from '../../data/components/radial-bar/props'
77

88
type MappedRadarProps = Omit<RadialBarSvgProps, 'data' | 'width' | 'height'>
9-
type UnmappedRadarProps = Omit<RadialBarSvgProps, 'valueFormat'> & {
9+
type UnmappedRadarProps = Omit<MappedRadarProps, 'valueFormat'> & {
1010
valueFormat: {
1111
format: string
1212
enabled: boolean
@@ -18,7 +18,7 @@ const initialProperties: UnmappedRadarProps = {
1818

1919
startAngle: svgDefaultProps.startAngle,
2020
endAngle: svgDefaultProps.endAngle,
21-
padding: svgDefaultProps.padding,
21+
padding: 0.4,
2222
padAngle: svgDefaultProps.padAngle,
2323
cornerRadius: 2,
2424

0 commit comments

Comments
 (0)
Please sign in to comment.