From 0b3bdb0bc8bca177851d876446f79754026fcdb6 Mon Sep 17 00:00:00 2001 From: Adam Berro <89929613+adamberro@users.noreply.github.com> Date: Sat, 6 Nov 2021 18:11:56 -0700 Subject: [PATCH] feat(radar): add support for patterns and gradients (#1807) * add defs and fill props * add story * add defs to website * run make fmt * fix lint issue * update interface * add ts-ignore for import like rest of packages * export type * rename story * add story to website --- packages/radar/src/Radar.tsx | 8 +++++ packages/radar/src/RadarLayer.tsx | 5 +++- packages/radar/src/hooks.ts | 28 +++++++++++++++++- packages/radar/src/props.ts | 3 ++ packages/radar/src/types.ts | 10 ++++++- packages/radar/stories/radar.stories.tsx | 34 +++++++++++++++++++++- website/src/data/components/radar/meta.yml | 2 ++ website/src/data/components/radar/props.ts | 8 ++++- 8 files changed, 93 insertions(+), 5 deletions(-) diff --git a/packages/radar/src/Radar.tsx b/packages/radar/src/Radar.tsx index c84ce74488..39c07ffec9 100644 --- a/packages/radar/src/Radar.tsx +++ b/packages/radar/src/Radar.tsx @@ -50,6 +50,8 @@ const InnerRadar = >({ ariaLabel, ariaLabelledBy, ariaDescribedBy, + defs = svgDefaultProps.defs, + fill = svgDefaultProps.fill, }: InnerRadarProps) => { const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions( width, @@ -62,6 +64,8 @@ const InnerRadar = >({ indices, formatValue, colorByKey, + fillByKey, + boundDefs, radius, radiusScale, centerX, @@ -81,6 +85,8 @@ const InnerRadar = >({ height: innerHeight, colors, legends, + defs, + fill, }) const layerById: Record = { @@ -116,6 +122,7 @@ const InnerRadar = >({ data={data} item={key} colorByKey={colorByKey} + fillByKey={fillByKey} radiusScale={radiusScale} angleStep={angleStep} curveFactory={curveFactory} @@ -187,6 +194,7 @@ const InnerRadar = >({ return ( > { data: D[] item: string colorByKey: Record + fillByKey: Record radiusScale: ScaleLinear angleStep: number curveFactory: CurveFactory @@ -23,6 +24,7 @@ export const RadarLayer = >({ data, item: key, colorByKey, + fillByKey, radiusScale, angleStep, curveFactory, @@ -49,12 +51,13 @@ export const RadarLayer = >({ config: springConfig, immediate: !animate, }) + const fill = fillByKey[key] ?? animatedProps.fill return ( >({ height, colors = svgDefaultProps.colors, legends, + defs, + fill, }: { data: RadarDataProps['data'] keys: RadarDataProps['keys'] @@ -33,6 +42,8 @@ export const useRadar = >({ height: number colors: RadarCommonProps['colors'] legends: RadarCommonProps['legends'] + defs: RadarSvgProps['defs'] + fill: RadarSvgProps['fill'] }) => { const getIndex = usePropertyAccessor(indexBy) const indices = useMemo(() => data.map(getIndex), [data, getIndex]) @@ -48,6 +59,19 @@ export const useRadar = >({ [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>((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)], @@ -107,6 +131,8 @@ export const useRadar = >({ indices, formatValue, colorByKey, + fillByKey, + boundDefs, radius, radiusScale, centerX, diff --git a/packages/radar/src/props.ts b/packages/radar/src/props.ts index cb30dee331..84d888fd7f 100644 --- a/packages/radar/src/props.ts +++ b/packages/radar/src/props.ts @@ -38,4 +38,7 @@ export const svgDefaultProps = { animate: true, motionConfig: 'gentle' as const, + + defs: [], + fill: [], } diff --git a/packages/radar/src/types.ts b/packages/radar/src/types.ts index 4215cd55a2..eb6bbe7180 100644 --- a/packages/radar/src/types.ts +++ b/packages/radar/src/types.ts @@ -10,6 +10,7 @@ import { ValueFormat, ClosedCurveFactoryId, DotsItemSymbolComponent, + SvgDefsAndFill, } from '@nivo/core' import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors' import { LegendProps } from '@nivo/legends' @@ -131,9 +132,16 @@ export interface RadarCommonProps> { ariaDescribedBy: AriaAttributes['aria-describedby'] } +export interface RadarSvgFillMatcherDatum> { + color: string + data: RadarDataProps['data'] + key: string +} + export type RadarSvgProps> = Partial> & RadarDataProps & Dimensions & - ModernMotionProps + ModernMotionProps & + SvgDefsAndFill> export type BoundLegendProps = Required> & Omit diff --git a/packages/radar/stories/radar.stories.tsx b/packages/radar/stories/radar.stories.tsx index 5e910ded1c..48856eaac9 100644 --- a/packages/radar/stories/radar.stories.tsx +++ b/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' @@ -163,3 +163,35 @@ export const CustomLegendLabel = () => ( ]} /> ) + +export const WithPatterns = () => ( + node.key === commonProperties.keys[0], + id: 'dots', + }, + { + match: node => node.key === commonProperties.keys[1], + id: 'squares', + }, + ]} + /> +) diff --git a/website/src/data/components/radar/meta.yml b/website/src/data/components/radar/meta.yml index fd1f4eb4b0..eca79284b7 100644 --- a/website/src/data/components/radar/meta.yml +++ b/website/src/data/components/radar/meta.yml @@ -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, diff --git a/website/src/data/components/radar/props.ts b/website/src/data/components/radar/props.ts index bd25e2d2a3..30f43fa3a9 100644 --- a/website/src/data/components/radar/props.ts +++ b/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[] = [ @@ -210,6 +215,7 @@ const props: ChartProperty[] = [ defaultValue: svgDefaultProps.borderColor, controlType: 'inheritedColor', }, + ...defsProperties('Style', ['svg']), { key: 'gridLevels', group: 'Grid',