Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(radar): add support for patterns and gradients #1807

Merged
merged 10 commits into from Nov 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/radar/src/Radar.tsx
Expand Up @@ -50,6 +50,8 @@ const InnerRadar = <D extends Record<string, unknown>>({
ariaLabel,
ariaLabelledBy,
ariaDescribedBy,
defs = svgDefaultProps.defs,
fill = svgDefaultProps.fill,
}: InnerRadarProps<D>) => {
const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(
width,
Expand All @@ -62,6 +64,8 @@ const InnerRadar = <D extends Record<string, unknown>>({
indices,
formatValue,
colorByKey,
fillByKey,
boundDefs,
radius,
radiusScale,
centerX,
Expand All @@ -81,6 +85,8 @@ const InnerRadar = <D extends Record<string, unknown>>({
height: innerHeight,
colors,
legends,
defs,
fill,
})

const layerById: Record<RadarLayerId, ReactNode> = {
Expand Down Expand Up @@ -116,6 +122,7 @@ const InnerRadar = <D extends Record<string, unknown>>({
data={data}
item={key}
colorByKey={colorByKey}
fillByKey={fillByKey}
radiusScale={radiusScale}
angleStep={angleStep}
curveFactory={curveFactory}
Expand Down Expand Up @@ -187,6 +194,7 @@ const InnerRadar = <D extends Record<string, unknown>>({

return (
<SvgWrapper
defs={boundDefs}
width={outerWidth}
height={outerHeight}
margin={margin}
Expand Down
5 changes: 4 additions & 1 deletion packages/radar/src/RadarLayer.tsx
Expand Up @@ -10,6 +10,7 @@ interface RadarLayerProps<D extends Record<string, unknown>> {
data: D[]
item: string
colorByKey: Record<string | number, string>
fillByKey: Record<string, string | null>
radiusScale: ScaleLinear<number, number>
angleStep: number
curveFactory: CurveFactory
Expand All @@ -23,6 +24,7 @@ export const RadarLayer = <D extends Record<string, unknown>>({
data,
item: key,
colorByKey,
fillByKey,
radiusScale,
angleStep,
curveFactory,
Expand All @@ -49,12 +51,13 @@ export const RadarLayer = <D extends Record<string, unknown>>({
config: springConfig,
immediate: !animate,
})
const fill = fillByKey[key] ?? animatedProps.fill

return (
<animated.path
key={key}
d={animatedPath}
fill={animatedProps.fill}
fill={fill}
fillOpacity={fillOpacity}
stroke={animatedProps.stroke}
strokeWidth={borderWidth}
Expand Down
28 changes: 27 additions & 1 deletion packages/radar/src/hooks.ts
@@ -1,13 +1,20 @@
import { useMemo } from 'react'
import { scaleLinear } from 'd3-scale'
import { useCurveInterpolation, usePropertyAccessor, useValueFormatter } from '@nivo/core'
import {
// @ts-ignore
bindDefs,
useCurveInterpolation,
usePropertyAccessor,
useValueFormatter,
} from '@nivo/core'
import { useOrdinalColorScale } from '@nivo/colors'
import { svgDefaultProps } from './props'
import {
RadarColorMapping,
RadarCommonProps,
RadarDataProps,
RadarCustomLayerProps,
RadarSvgProps,
BoundLegendProps,
} from './types'

Expand All @@ -22,6 +29,8 @@ export const useRadar = <D extends Record<string, unknown>>({
height,
colors = svgDefaultProps.colors,
legends,
defs,
fill,
}: {
data: RadarDataProps<D>['data']
keys: RadarDataProps<D>['keys']
Expand All @@ -33,6 +42,8 @@ export const useRadar = <D extends Record<string, unknown>>({
height: number
colors: RadarCommonProps<D>['colors']
legends: RadarCommonProps<D>['legends']
defs: RadarSvgProps<D>['defs']
fill: RadarSvgProps<D>['fill']
}) => {
const getIndex = usePropertyAccessor<D, string>(indexBy)
const indices = useMemo(() => data.map(getIndex), [data, getIndex])
Expand All @@ -48,6 +59,19 @@ export const useRadar = <D extends Record<string, unknown>>({
[keys, getColor]
)

const { boundDefs, fillByKey } = useMemo(() => {
// expand keys into structure expected by bindDefs
const keyData = keys.map(k => ({ key: k, color: colorByKey[k], data, fill: null }))
const boundDefs = bindDefs(defs, keyData, fill)
const fillByKey = keyData.reduce<Record<string, string | null>>((mapping, keyDatum) => {
const { key: keyName, fill } = keyDatum
mapping[keyName] = fill
return mapping
}, {})

return { boundDefs, fillByKey }
}, [keys, data, defs, fill, colorByKey])

const { radius, radiusScale, centerX, centerY, angleStep } = useMemo(() => {
const allValues: number[] = data.reduce(
(acc: number[], d) => [...acc, ...keys.map(key => d[key] as number)],
Expand Down Expand Up @@ -107,6 +131,8 @@ export const useRadar = <D extends Record<string, unknown>>({
indices,
formatValue,
colorByKey,
fillByKey,
boundDefs,
radius,
radiusScale,
centerX,
Expand Down
3 changes: 3 additions & 0 deletions packages/radar/src/props.ts
Expand Up @@ -38,4 +38,7 @@ export const svgDefaultProps = {

animate: true,
motionConfig: 'gentle' as const,

defs: [],
fill: [],
}
10 changes: 9 additions & 1 deletion packages/radar/src/types.ts
Expand Up @@ -10,6 +10,7 @@ import {
ValueFormat,
ClosedCurveFactoryId,
DotsItemSymbolComponent,
SvgDefsAndFill,
} from '@nivo/core'
import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'
import { LegendProps } from '@nivo/legends'
Expand Down Expand Up @@ -131,9 +132,16 @@ export interface RadarCommonProps<D extends Record<string, unknown>> {
ariaDescribedBy: AriaAttributes['aria-describedby']
}

export interface RadarSvgFillMatcherDatum<D extends Record<string, unknown>> {
color: string
data: RadarDataProps<D>['data']
key: string
}

export type RadarSvgProps<D extends Record<string, unknown>> = Partial<RadarCommonProps<D>> &
RadarDataProps<D> &
Dimensions &
ModernMotionProps
ModernMotionProps &
SvgDefsAndFill<RadarSvgFillMatcherDatum<D>>

export type BoundLegendProps = Required<Pick<LegendProps, 'data'>> & Omit<LegendProps, 'data'>
34 changes: 33 additions & 1 deletion packages/radar/stories/radar.stories.tsx
@@ -1,7 +1,7 @@
import { Meta } from '@storybook/react'
import { withKnobs, select } from '@storybook/addon-knobs'
import { generateWinesTastes } from '@nivo/generators'
import { ClosedCurveFactoryId } from '@nivo/core'
import { ClosedCurveFactoryId, patternDotsDef, patternSquaresDef } from '@nivo/core'
// @ts-ignore
import { Radar, GridLabelProps } from '../src'

Expand Down Expand Up @@ -163,3 +163,35 @@ export const CustomLegendLabel = () => (
]}
/>
)

export const WithPatterns = () => (
<Radar
{...commonProperties}
defs={[
patternDotsDef('dots', {
background: '#fc0341',
color: 'inherit',
size: 4,
padding: 2,
stagger: true,
}),
patternSquaresDef('squares', {
background: '#4287f5',
color: 'inherit',
size: 6,
padding: 4,
stagger: false,
}),
]}
fill={[
{
match: node => node.key === commonProperties.keys[0],
id: 'dots',
},
{
match: node => node.key === commonProperties.keys[1],
id: 'squares',
},
]}
/>
)
2 changes: 2 additions & 0 deletions website/src/data/components/radar/meta.yml
Expand Up @@ -15,6 +15,8 @@ Radar:
link: radar--with-formatted-values
- label: Custom label component
link: radar--custom-label-component
- label: Adding patterns to radar layers
link: radar--with-patterns
description: |
Generates a radar chart from an array of data.
Note that margin object does not take grid labels into account,
Expand Down
8 changes: 7 additions & 1 deletion website/src/data/components/radar/props.ts
@@ -1,6 +1,11 @@
import { closedCurvePropKeys } from '@nivo/core'
import { svgDefaultProps } from '@nivo/radar'
import { themeProperty, motionProperties, groupProperties } from '../../../lib/componentProperties'
import {
themeProperty,
motionProperties,
groupProperties,
defsProperties,
} from '../../../lib/componentProperties'
import { ChartProperty } from '../../../types'

const props: ChartProperty[] = [
Expand Down Expand Up @@ -210,6 +215,7 @@ const props: ChartProperty[] = [
defaultValue: svgDefaultProps.borderColor,
controlType: 'inheritedColor',
},
...defsProperties('Style', ['svg']),
{
key: 'gridLevels',
group: 'Grid',
Expand Down