Skip to content

Commit

Permalink
feat(radial-bar): add support for labels
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed Sep 11, 2021
1 parent 5ec257f commit e6bab88
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 24 deletions.
24 changes: 23 additions & 1 deletion packages/radial-bar/src/RadialBar.tsx
@@ -1,6 +1,7 @@
import { createElement, Fragment, ReactNode } from 'react'
import { Container, useDimensions, SvgWrapper } from '@nivo/core'
import { RadialBarLayerId, RadialBarSvgProps } from './types'
import { ArcLabelsLayer } from '@nivo/arcs'
import { RadialBarLayerId, RadialBarSvgProps, ComputedBar } from './types'
import { svgDefaultProps } from './props'
import { useRadialBar } from './hooks'
import { RadialBarArcs } from './RadialBarArcs'
Expand All @@ -21,6 +22,11 @@ const InnerRadialBar = ({
layers = svgDefaultProps.layers,
colors = svgDefaultProps.colors,
cornerRadius = svgDefaultProps.cornerRadius,
enableLabels = svgDefaultProps.enableLabels,
label = svgDefaultProps.label,
labelsSkipAngle = svgDefaultProps.labelsSkipAngle,
labelsRadiusOffset = svgDefaultProps.labelsRadiusOffset,
labelsTextColor = svgDefaultProps.labelsTextColor,
isInteractive = svgDefaultProps.isInteractive,
tooltip = svgDefaultProps.tooltip,
onClick,
Expand Down Expand Up @@ -52,6 +58,7 @@ const InnerRadialBar = ({
const layerById: Record<RadialBarLayerId, ReactNode> = {
grid: null,
bars: null,
labels: null,
legends: null,
}

Expand Down Expand Up @@ -84,6 +91,21 @@ const InnerRadialBar = ({
)
}

if (layers.includes('labels') && enableLabels) {
layerById.labels = (
<ArcLabelsLayer<ComputedBar>
key="labels"
center={center}
data={bars}
label={label}
radiusOffset={labelsRadiusOffset}
skipAngle={labelsSkipAngle}
textColor={labelsTextColor}
transitionMode={transitionMode}
/>
)
}

return (
<SvgWrapper
width={outerWidth}
Expand Down
17 changes: 6 additions & 11 deletions packages/radial-bar/src/hooks.ts
Expand Up @@ -5,12 +5,7 @@ import { degreesToRadians } from '@nivo/core'
import { Arc } from '@nivo/arcs'
import { useOrdinalColorScale } from '@nivo/colors'
import { svgDefaultProps } from './props'
import {
ComputedBar,
RadialBarCommonProps,
RadialBarDataProps,
RadialBarSerie,
} from './types'
import { ComputedBar, RadialBarCommonProps, RadialBarDataProps, RadialBarSerie } from './types'

interface RadialBarGroup {
id: string
Expand Down Expand Up @@ -86,15 +81,15 @@ export const useRadialBar = ({
scaleBand()
.domain(serieIds)
.range([outerRadius - 100, outerRadius])
.padding(0.4),
.padding(0.2),
[serieIds, outerRadius]
)

const arcGenerator = useMemo(
() =>
d3Arc<Arc>()
.startAngle(d => degreesToRadians(d.startAngle))
.endAngle(d => degreesToRadians(d.endAngle))
.startAngle(d => d.startAngle)
.endAngle(d => d.endAngle)
.innerRadius(d => d.innerRadius)
.outerRadius(d => d.outerRadius)
.cornerRadius(cornerRadius),
Expand All @@ -121,8 +116,8 @@ export const useRadialBar = ({
color: '',
stackedValue,
arc: {
startAngle: valueScale(currentValue),
endAngle: valueScale(stackedValue),
startAngle: degreesToRadians(valueScale(currentValue)),
endAngle: degreesToRadians(valueScale(stackedValue)),
innerRadius,
outerRadius,
},
Expand Down
8 changes: 7 additions & 1 deletion packages/radial-bar/src/props.ts
Expand Up @@ -2,14 +2,20 @@ import { RadialBarLayerId } from './types'
import { RadialBarTooltip } from './RadialBarTooltip'

export const svgDefaultProps = {
layers: ['grid', 'bars', 'legends'] as RadialBarLayerId[],
layers: ['grid', 'bars', 'labels', 'legends'] as RadialBarLayerId[],

startAngle: 0,
endAngle: 270,

colors: { scheme: 'nivo' as const },
cornerRadius: 0,

enableLabels: true,
label: 'value',
labelsSkipAngle: 10,
labelsRadiusOffset: 0.5,
labelsTextColor: { theme: 'labels.text.fill' },

isInteractive: true,
tooltip: RadialBarTooltip,

Expand Down
14 changes: 10 additions & 4 deletions packages/radial-bar/src/types.ts
@@ -1,6 +1,6 @@
import { AriaAttributes, FunctionComponent, MouseEvent } from 'react'
import { Theme, Box, Dimensions, ModernMotionProps } from '@nivo/core'
import { Arc, ArcTransitionMode } from '@nivo/arcs'
import { Theme, Box, Dimensions, ModernMotionProps, PropertyAccessor } from '@nivo/core'
import { Arc, ArcLabelsProps, ArcTransitionMode } from '@nivo/arcs'
import { OrdinalColorScaleConfig } from '@nivo/colors'

export interface RadialBarDatum {
Expand Down Expand Up @@ -28,14 +28,14 @@ export interface RadialBarDataProps {
data: RadialBarSerie[]
}

export type RadialBarLayerId = 'grid' | 'bars' | 'legends'
export type RadialBarLayerId = 'grid' | 'bars' | 'labels' | 'legends'

export interface RadialBarTooltipProps {
bar: ComputedBar
}
export type RadialBarTooltipComponent = FunctionComponent<RadialBarTooltipProps>

export interface RadialBarCommonProps {
export type RadialBarCommonProps = {
margin: Box

theme: Theme
Expand All @@ -47,6 +47,12 @@ export interface RadialBarCommonProps {
startAngle: number
endAngle: number

enableLabels: boolean
label: PropertyAccessor<ComputedBar, string>
labelsSkipAngle: ArcLabelsProps<ComputedBar>['arcLabelsSkipAngle']
labelsRadiusOffset: ArcLabelsProps<ComputedBar>['arcLabelsRadiusOffset']
labelsTextColor: ArcLabelsProps<ComputedBar>['arcLabelsTextColor']

isInteractive: boolean
tooltip: RadialBarTooltipComponent
onClick: (bar: ComputedBar, event: MouseEvent) => void
Expand Down
4 changes: 2 additions & 2 deletions website/src/data/components/pie/props.ts
Expand Up @@ -521,7 +521,7 @@ const props: ChartProperty[] = [
{
key: 'activeInnerRadiusOffset',
flavors: ['svg', 'canvas'],
help: `Skip label if corresponding slice's angle is lower than provided value.`,
help: `Extends active slice inner radius.`,
type: 'number',
required: false,
defaultValue: defaultProps.activeInnerRadiusOffset,
Expand All @@ -536,7 +536,7 @@ const props: ChartProperty[] = [
{
key: 'activeOuterRadiusOffset',
flavors: ['svg', 'canvas'],
help: `Skip label if corresponding slice's angle is lower than provided value.`,
help: `Extends active slice outer radius.`,
type: 'number',
required: false,
defaultValue: defaultProps.activeOuterRadiusOffset,
Expand Down
3 changes: 2 additions & 1 deletion website/src/data/components/radial-bar/meta.yml
Expand Up @@ -11,7 +11,8 @@ RadialBar:
- isomorphic
stories: []
description: |
Generates a radial bar chart from an array of data.
A radial bar chart.
Note that margin object does not take grid labels into account,
so you should adjust it to leave enough room for it.
Expand Down
78 changes: 74 additions & 4 deletions website/src/data/components/radial-bar/props.ts
@@ -1,5 +1,4 @@
import { svgDefaultProps } from '@nivo/radial-bar'
import { defaultProps } from '@nivo/pie'
import { arcTransitionModes } from '@nivo/arcs'
import { themeProperty, motionProperties, groupProperties } from '../../../lib/componentProperties'
import { ChartProperty } from '../../../types'
Expand Down Expand Up @@ -188,9 +187,82 @@ const props: ChartProperty[] = [
step: 1,
},
},
{
key: 'enableLabels',
group: 'Labels',
type: 'boolean',
required: false,
help: 'Enable/disable labels.',
flavors: ['svg'],
defaultValue: svgDefaultProps.enableLabels,
controlType: 'switch',
},
{
key: 'label',
group: 'Labels',
type: 'string | (bar: ComputedBar) => string',
required: false,
help:
'Defines how to get label text, can be a string (used to access current bar property) or a function which will receive the actual bar data.',
flavors: ['svg'],
defaultValue: svgDefaultProps.label,
controlType: 'choices',
controlOptions: {
choices: ['category', 'groupId', 'value', 'formattedValue'].map(choice => ({
label: choice,
value: choice,
})),
},
},
{
key: 'labelsSkipAngle',
group: 'Labels',
type: 'number',
required: false,
help: `Skip label if corresponding arc's angle is lower than provided value.`,
flavors: ['svg'],
defaultValue: svgDefaultProps.labelsSkipAngle,
controlType: 'range',
controlOptions: {
unit: '°',
min: 0,
max: 45,
step: 1,
},
},
{
key: 'labelsRadiusOffset',
group: 'Labels',
type: 'number',
required: false,
help: `
Define the radius to use to determine the label position, starting from inner radius,
this is expressed as a ratio. Centered at 0.5 by default.
`,
flavors: ['svg'],
defaultValue: svgDefaultProps.labelsRadiusOffset,
controlType: 'range',
controlOptions: {
min: 0,
max: 2,
step: 0.05,
},
},
{
key: 'labelsTextColor',
group: 'Labels',
help: 'Defines how to compute label text color.',
type: 'string | object | Function',
required: false,
flavors: ['svg'],
defaultValue: svgDefaultProps.labelsTextColor,
controlType: 'inheritedColor',
},
{
key: 'layers',
group: 'Customization',
type: '(RadialBarLayerId | RadialBarCustomLayer)[]',
required: false,
help: 'Defines the order of layers and add custom layers.',
description: `
You can also use this to insert extra layers
Expand All @@ -199,8 +271,6 @@ const props: ChartProperty[] = [
The layer function which will receive the chart's
context & computed data and must return a valid SVG element.
`,
required: false,
type: '(RadarLayerId | FunctionComponent<RadarCustomLayerProps>)[]',
flavors: ['svg'],
defaultValue: svgDefaultProps.layers,
},
Expand Down Expand Up @@ -293,7 +363,7 @@ const props: ChartProperty[] = [
help: 'Define how transitions behave.',
type: 'string',
required: false,
defaultValue: defaultProps.transitionMode,
defaultValue: svgDefaultProps.transitionMode,
controlType: 'choices',
group: 'Motion',
controlOptions: {
Expand Down
6 changes: 6 additions & 0 deletions website/src/pages/radial-bar/index.tsx
Expand Up @@ -29,6 +29,12 @@ const initialProperties: UnmappedRadarProps = {
colors: svgDefaultProps.colors,
cornerRadius: 2,

enableLabels: svgDefaultProps.enableLabels,
label: svgDefaultProps.label,
labelsSkipAngle: svgDefaultProps.labelsSkipAngle,
labelsRadiusOffset: svgDefaultProps.labelsRadiusOffset,
labelsTextColor: svgDefaultProps.labelsTextColor,

animate: true,
motionConfig: 'gentle' as const,
transitionMode: 'pushOut' as const,
Expand Down

0 comments on commit e6bab88

Please sign in to comment.