diff --git a/packages/chord/src/Chord.tsx b/packages/chord/src/Chord.tsx index 47b8eab875..a0d38ac9f1 100644 --- a/packages/chord/src/Chord.tsx +++ b/packages/chord/src/Chord.tsx @@ -1,6 +1,5 @@ import { createElement, Fragment, ReactNode } from 'react' -import { Container, SvgWrapper, useDimensions, useTheme } from '@nivo/core' -import { useInheritedColor } from '@nivo/colors' +import { Container, SvgWrapper, useDimensions } from '@nivo/core' import { BoxLegendSvg } from '@nivo/legends' import { svgDefaultProps } from './defaults' import { useChord, useChordSelection, useCustomLayerProps } from './hooks' @@ -96,9 +95,6 @@ const InnerChord = ({ ribbonHoverOthersOpacity, }) - const theme = useTheme() - const getArcBorderColor = useInheritedColor(arcBorderColor, theme) - const customLayerProps = useCustomLayerProps({ center, radius, @@ -152,7 +148,7 @@ const InnerChord = ({ arcs={arcs} arcGenerator={arcGenerator} borderWidth={arcBorderWidth} - getBorderColor={getArcBorderColor} + borderColor={arcBorderColor} getOpacity={getArcOpacity} setCurrent={setCurrentArc} isInteractive={isInteractive} diff --git a/packages/chord/src/ChordArc.tsx b/packages/chord/src/ChordArc.tsx index 36064e9fbe..0d6b5092be 100644 --- a/packages/chord/src/ChordArc.tsx +++ b/packages/chord/src/ChordArc.tsx @@ -1,15 +1,14 @@ import { createElement, memo, useMemo, MouseEvent } from 'react' +import { SpringValues, animated } from '@react-spring/web' import { useTooltip } from '@nivo/tooltip' -import { ArcDatum, ArcGenerator, ChordCommonProps } from './types' +import { ArcAnimatedProps, ArcDatum, ArcGenerator, ChordCommonProps } from './types' +import { computeArcPath } from './compute' interface ChordArcProps { arc: ArcDatum - startAngle: number - endAngle: number + animatedProps: SpringValues arcGenerator: ArcGenerator borderWidth: number - getBorderColor: (arc: ArcDatum) => string - opacity: number setCurrent: (arc: ArcDatum | null) => void isInteractive: ChordCommonProps['isInteractive'] onMouseEnter?: ChordCommonProps['onArcMouseEnter'] @@ -22,11 +21,8 @@ interface ChordArcProps { export const ChordArc = memo( ({ arc, - startAngle, - endAngle, + animatedProps, borderWidth, - getBorderColor, - opacity, arcGenerator, setCurrent, isInteractive, @@ -74,13 +70,16 @@ export const ChordArc = memo( }, [isInteractive, arc, onClick]) return ( - string + borderColor: ChordCommonProps['arcBorderColor'] getOpacity: (arc: ArcDatum) => number setCurrent: (arc: ArcDatum | null) => void isInteractive: ChordCommonProps['isInteractive'] @@ -24,7 +24,7 @@ export const ChordArcs = memo( ({ arcs, borderWidth, - getBorderColor, + borderColor, getOpacity, arcGenerator, setCurrent, @@ -35,82 +35,65 @@ export const ChordArcs = memo( onClick, tooltip, }: ChordArcsProps) => { - const { animate, springConfig: _springConfig } = useMotionConfig() + const { animate, config: springConfig } = useMotionConfig() - if (!animate) { - return ( - <> - {arcs.map(arc => { - return ( - - ) - })} - - ) - } + const theme = useTheme() + const getBorderColor = useInheritedColor(borderColor, theme) - const springConfig = { - ..._springConfig, - precision: 0.001, - } + const transition = useTransition(arcs, { + keys: arc => arc.id, + initial: arc => ({ + startAngle: arc.startAngle, + endAngle: arc.endAngle, + color: arc.color, + opacity: getOpacity(arc), + borderColor: getBorderColor(arc), + }), + from: arc => ({ + startAngle: arc.startAngle, + endAngle: arc.endAngle, + color: arc.color, + opacity: 0, + borderColor: getBorderColor(arc), + }), + update: arc => ({ + startAngle: arc.startAngle, + endAngle: arc.endAngle, + color: arc.color, + opacity: getOpacity(arc), + borderColor: getBorderColor(arc), + }), + leave: arc => ({ + startAngle: arc.startAngle, + endAngle: arc.endAngle, + color: arc.color, + opacity: 0, + borderColor: getBorderColor(arc), + }), + expires: true, + config: springConfig, + immediate: !animate, + }) return ( - { - return { - key: arc.id, - data: arc, - style: { - startAngle: spring(arc.startAngle, springConfig), - endAngle: spring(arc.endAngle, springConfig), - opacity: spring(getOpacity(arc), springConfig), - ...interpolateColor(arc.color, springConfig), - }, - } - })} - > - {interpolatedStyles => ( - <> - {interpolatedStyles.map(({ key, style, data: arc }) => { - return ( - - ) - })} - - )} - + <> + {transition((animatedProps, arc) => ( + + ))} + ) } ) diff --git a/packages/chord/src/compute.ts b/packages/chord/src/compute.ts index f8466e0dff..25c93d8e28 100644 --- a/packages/chord/src/compute.ts +++ b/packages/chord/src/compute.ts @@ -9,6 +9,7 @@ import { RibbonDatum, RibbonGenerator, ArcGenerator, + ArcAnimatedProps, } from './types' import { OrdinalColorScale } from '@nivo/colors' @@ -109,6 +110,14 @@ export const computeChordArcsAndRibbons = ({ return { arcs, ribbons } } +export const computeArcPath = ({ + startAngle, + endAngle, + arcGenerator, +}: SpringValues> & { + arcGenerator: ArcGenerator +}) => to([startAngle, endAngle], (startAngle, endAngle) => arcGenerator({ startAngle, endAngle })) + export const computeRibbonPath = ({ sourceStartAngle, sourceEndAngle, diff --git a/packages/chord/src/types.ts b/packages/chord/src/types.ts index 2e00df60cb..eb04084c29 100644 --- a/packages/chord/src/types.ts +++ b/packages/chord/src/types.ts @@ -41,6 +41,14 @@ export interface ArcDatum { color: string } +export interface ArcAnimatedProps { + startAngle: number + endAngle: number + color: string + opacity: number + borderColor: string +} + export interface RibbonDatum { id: string source: ArcDatum