Skip to content

Commit ebf01a1

Browse files
committedJan 1, 2022
feat(chord): migrate arc transitions to react-spring
1 parent a992666 commit ebf01a1

File tree

5 files changed

+94
-99
lines changed

5 files changed

+94
-99
lines changed
 

‎packages/chord/src/Chord.tsx

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { createElement, Fragment, ReactNode } from 'react'
2-
import { Container, SvgWrapper, useDimensions, useTheme } from '@nivo/core'
3-
import { useInheritedColor } from '@nivo/colors'
2+
import { Container, SvgWrapper, useDimensions } from '@nivo/core'
43
import { BoxLegendSvg } from '@nivo/legends'
54
import { svgDefaultProps } from './defaults'
65
import { useChord, useChordSelection, useCustomLayerProps } from './hooks'
@@ -96,9 +95,6 @@ const InnerChord = ({
9695
ribbonHoverOthersOpacity,
9796
})
9897

99-
const theme = useTheme()
100-
const getArcBorderColor = useInheritedColor(arcBorderColor, theme)
101-
10298
const customLayerProps = useCustomLayerProps({
10399
center,
104100
radius,
@@ -152,7 +148,7 @@ const InnerChord = ({
152148
arcs={arcs}
153149
arcGenerator={arcGenerator}
154150
borderWidth={arcBorderWidth}
155-
getBorderColor={getArcBorderColor}
151+
borderColor={arcBorderColor}
156152
getOpacity={getArcOpacity}
157153
setCurrent={setCurrentArc}
158154
isInteractive={isInteractive}

‎packages/chord/src/ChordArc.tsx

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { createElement, memo, useMemo, MouseEvent } from 'react'
2+
import { SpringValues, animated } from '@react-spring/web'
23
import { useTooltip } from '@nivo/tooltip'
3-
import { ArcDatum, ArcGenerator, ChordCommonProps } from './types'
4+
import { ArcAnimatedProps, ArcDatum, ArcGenerator, ChordCommonProps } from './types'
5+
import { computeArcPath } from './compute'
46

57
interface ChordArcProps {
68
arc: ArcDatum
7-
startAngle: number
8-
endAngle: number
9+
animatedProps: SpringValues<ArcAnimatedProps>
910
arcGenerator: ArcGenerator
1011
borderWidth: number
11-
getBorderColor: (arc: ArcDatum) => string
12-
opacity: number
1312
setCurrent: (arc: ArcDatum | null) => void
1413
isInteractive: ChordCommonProps['isInteractive']
1514
onMouseEnter?: ChordCommonProps['onArcMouseEnter']
@@ -22,11 +21,8 @@ interface ChordArcProps {
2221
export const ChordArc = memo(
2322
({
2423
arc,
25-
startAngle,
26-
endAngle,
24+
animatedProps,
2725
borderWidth,
28-
getBorderColor,
29-
opacity,
3026
arcGenerator,
3127
setCurrent,
3228
isInteractive,
@@ -74,13 +70,16 @@ export const ChordArc = memo(
7470
}, [isInteractive, arc, onClick])
7571

7672
return (
77-
<path
78-
d={arcGenerator({ startAngle, endAngle }) || ''}
79-
fill={arc.color}
80-
fillOpacity={opacity}
73+
<animated.path
74+
d={computeArcPath({
75+
startAngle: animatedProps.startAngle,
76+
endAngle: animatedProps.endAngle,
77+
arcGenerator,
78+
})}
79+
fill={animatedProps.color}
80+
opacity={animatedProps.opacity}
8181
strokeWidth={borderWidth}
82-
stroke={getBorderColor(arc)}
83-
strokeOpacity={opacity}
82+
stroke={animatedProps.borderColor}
8483
onMouseEnter={handleMouseEnter}
8584
onMouseMove={handleMouseMove}
8685
onMouseLeave={handleMouseLeave}

‎packages/chord/src/ChordArcs.tsx

+61-78
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { memo } from 'react'
2-
import { TransitionMotion, spring } from 'react-motion'
3-
import { interpolateColor } from '@nivo/colors'
4-
import { useMotionConfig } from '@nivo/core'
2+
import { useTransition } from '@react-spring/web'
3+
import { useMotionConfig, useTheme } from '@nivo/core'
4+
import { useInheritedColor } from '@nivo/colors'
55
import { ChordArc } from './ChordArc'
6-
import { ArcDatum, ArcGenerator, ChordCommonProps } from './types'
6+
import { ArcDatum, ArcGenerator, ChordCommonProps, ArcAnimatedProps } from './types'
77

88
interface ChordArcsProps {
99
arcs: ArcDatum[]
1010
arcGenerator: ArcGenerator
1111
borderWidth: ChordCommonProps['arcBorderWidth']
12-
getBorderColor: (arc: ArcDatum) => string
12+
borderColor: ChordCommonProps['arcBorderColor']
1313
getOpacity: (arc: ArcDatum) => number
1414
setCurrent: (arc: ArcDatum | null) => void
1515
isInteractive: ChordCommonProps['isInteractive']
@@ -24,7 +24,7 @@ export const ChordArcs = memo(
2424
({
2525
arcs,
2626
borderWidth,
27-
getBorderColor,
27+
borderColor,
2828
getOpacity,
2929
arcGenerator,
3030
setCurrent,
@@ -35,82 +35,65 @@ export const ChordArcs = memo(
3535
onClick,
3636
tooltip,
3737
}: ChordArcsProps) => {
38-
const { animate, springConfig: _springConfig } = useMotionConfig()
38+
const { animate, config: springConfig } = useMotionConfig()
3939

40-
if (!animate) {
41-
return (
42-
<>
43-
{arcs.map(arc => {
44-
return (
45-
<ChordArc
46-
key={arc.id}
47-
arc={arc}
48-
arcGenerator={arcGenerator}
49-
startAngle={arc.startAngle}
50-
endAngle={arc.endAngle}
51-
opacity={getOpacity(arc)}
52-
borderWidth={borderWidth}
53-
getBorderColor={getBorderColor}
54-
isInteractive={isInteractive}
55-
setCurrent={setCurrent}
56-
onMouseEnter={onMouseEnter}
57-
onMouseMove={onMouseMove}
58-
onMouseLeave={onMouseLeave}
59-
onClick={onClick}
60-
tooltip={tooltip}
61-
/>
62-
)
63-
})}
64-
</>
65-
)
66-
}
40+
const theme = useTheme()
41+
const getBorderColor = useInheritedColor(borderColor, theme)
6742

68-
const springConfig = {
69-
..._springConfig,
70-
precision: 0.001,
71-
}
43+
const transition = useTransition<ArcDatum, ArcAnimatedProps>(arcs, {
44+
keys: arc => arc.id,
45+
initial: arc => ({
46+
startAngle: arc.startAngle,
47+
endAngle: arc.endAngle,
48+
color: arc.color,
49+
opacity: getOpacity(arc),
50+
borderColor: getBorderColor(arc),
51+
}),
52+
from: arc => ({
53+
startAngle: arc.startAngle,
54+
endAngle: arc.endAngle,
55+
color: arc.color,
56+
opacity: 0,
57+
borderColor: getBorderColor(arc),
58+
}),
59+
update: arc => ({
60+
startAngle: arc.startAngle,
61+
endAngle: arc.endAngle,
62+
color: arc.color,
63+
opacity: getOpacity(arc),
64+
borderColor: getBorderColor(arc),
65+
}),
66+
leave: arc => ({
67+
startAngle: arc.startAngle,
68+
endAngle: arc.endAngle,
69+
color: arc.color,
70+
opacity: 0,
71+
borderColor: getBorderColor(arc),
72+
}),
73+
expires: true,
74+
config: springConfig,
75+
immediate: !animate,
76+
})
7277

7378
return (
74-
<TransitionMotion
75-
styles={arcs.map(arc => {
76-
return {
77-
key: arc.id,
78-
data: arc,
79-
style: {
80-
startAngle: spring(arc.startAngle, springConfig),
81-
endAngle: spring(arc.endAngle, springConfig),
82-
opacity: spring(getOpacity(arc), springConfig),
83-
...interpolateColor(arc.color, springConfig),
84-
},
85-
}
86-
})}
87-
>
88-
{interpolatedStyles => (
89-
<>
90-
{interpolatedStyles.map(({ key, style, data: arc }) => {
91-
return (
92-
<ChordArc
93-
key={key}
94-
arc={arc}
95-
arcGenerator={arcGenerator}
96-
startAngle={style.startAngle}
97-
endAngle={style.endAngle}
98-
opacity={style.opacity}
99-
borderWidth={borderWidth}
100-
getBorderColor={getBorderColor}
101-
isInteractive={isInteractive}
102-
setCurrent={setCurrent}
103-
onMouseEnter={onMouseEnter}
104-
onMouseMove={onMouseMove}
105-
onMouseLeave={onMouseLeave}
106-
onClick={onClick}
107-
tooltip={tooltip}
108-
/>
109-
)
110-
})}
111-
</>
112-
)}
113-
</TransitionMotion>
79+
<>
80+
{transition((animatedProps, arc) => (
81+
<ChordArc
82+
key={arc.id}
83+
arc={arc}
84+
arcGenerator={arcGenerator}
85+
animatedProps={animatedProps}
86+
borderWidth={borderWidth}
87+
setCurrent={setCurrent}
88+
isInteractive={isInteractive}
89+
tooltip={tooltip}
90+
onMouseEnter={onMouseEnter}
91+
onMouseMove={onMouseMove}
92+
onMouseLeave={onMouseLeave}
93+
onClick={onClick}
94+
/>
95+
))}
96+
</>
11497
)
11598
}
11699
)

‎packages/chord/src/compute.ts

+9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
RibbonDatum,
1010
RibbonGenerator,
1111
ArcGenerator,
12+
ArcAnimatedProps,
1213
} from './types'
1314
import { OrdinalColorScale } from '@nivo/colors'
1415

@@ -109,6 +110,14 @@ export const computeChordArcsAndRibbons = ({
109110
return { arcs, ribbons }
110111
}
111112

113+
export const computeArcPath = ({
114+
startAngle,
115+
endAngle,
116+
arcGenerator,
117+
}: SpringValues<Pick<ArcAnimatedProps, 'startAngle' | 'endAngle'>> & {
118+
arcGenerator: ArcGenerator
119+
}) => to([startAngle, endAngle], (startAngle, endAngle) => arcGenerator({ startAngle, endAngle }))
120+
112121
export const computeRibbonPath = ({
113122
sourceStartAngle,
114123
sourceEndAngle,

‎packages/chord/src/types.ts

+8
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ export interface ArcDatum {
4141
color: string
4242
}
4343

44+
export interface ArcAnimatedProps {
45+
startAngle: number
46+
endAngle: number
47+
color: string
48+
opacity: number
49+
borderColor: string
50+
}
51+
4452
export interface RibbonDatum {
4553
id: string
4654
source: ArcDatum

0 commit comments

Comments
 (0)
Please sign in to comment.