Skip to content

Commit

Permalink
feat(pie): add transitions for arcs
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed Dec 18, 2020
1 parent afc6b8c commit ccb1656
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 37 deletions.
21 changes: 21 additions & 0 deletions packages/arcs/src/arcInterpolator.ts
@@ -0,0 +1,21 @@
import { to, SpringValue } from 'react-spring'
import { ArcGenerator } from './types'

export const interpolateArc = (
startAngleValue: SpringValue<number>,
endAngleValue: SpringValue<number>,
innerRadiusValue: SpringValue<number>,
outerRadiusValue: SpringValue<number>,
arcGenerator: ArcGenerator
) =>
to(
[startAngleValue, endAngleValue, innerRadiusValue, outerRadiusValue],
(startAngle, endAngle, innerRadius, outerRadius) => {
return arcGenerator({
startAngle,
endAngle,
innerRadius,
outerRadius,
})
}
)
1 change: 1 addition & 0 deletions packages/arcs/src/index.ts
@@ -1,3 +1,4 @@
export * from './types'
export * from './useAnimatedArc'
export * from './useArcGenerator'
export * from './useArcsTransition'
1 change: 1 addition & 0 deletions packages/arcs/src/types.ts
Expand Up @@ -12,6 +12,7 @@ export interface Arc {
}

export interface DatumWithArc {
id: string | number
arc: Arc
}

Expand Down
23 changes: 8 additions & 15 deletions packages/arcs/src/useAnimatedArc.ts
@@ -1,6 +1,7 @@
import { to, useSpring } from 'react-spring'
import { useSpring } from 'react-spring'
import { useMotionConfig } from '@nivo/core'
import { Arc, ArcGenerator } from './types'
import { interpolateArc } from './arcInterpolator'

export const useAnimatedArc = (datumWithArc: { arc: Arc }, arcGenerator: ArcGenerator) => {
const { animate, config: springConfig } = useMotionConfig()
Expand All @@ -16,20 +17,12 @@ export const useAnimatedArc = (datumWithArc: { arc: Arc }, arcGenerator: ArcGene

return {
...animatedValues,
path: to(
[
animatedValues.startAngle,
animatedValues.endAngle,
animatedValues.innerRadius,
animatedValues.outerRadius,
],
(startAngle, endAngle, innerRadius, outerRadius) =>
arcGenerator({
startAngle,
endAngle,
innerRadius,
outerRadius,
})
path: interpolateArc(
animatedValues.startAngle,
animatedValues.endAngle,
animatedValues.innerRadius,
animatedValues.outerRadius,
arcGenerator
),
}
}
58 changes: 58 additions & 0 deletions packages/arcs/src/useArcsTransition.ts
@@ -0,0 +1,58 @@
import { useTransition } from 'react-spring'
import { useMotionConfig } from '@nivo/core'
import { DatumWithArc } from './types'
import { interpolateArc } from './arcInterpolator'

export const useArcsTransition = <Datum extends DatumWithArc>(data: Datum[]) => {
console.log(data)
const { animate, config: springConfig } = useMotionConfig()

const transition = useTransition<
Datum,
{
startAngle: number
endAngle: number
innerRadius: number
outerRadius: number
}
>(data, {
key: datum => datum.id,
initial: datum => ({
startAngle: datum.arc.startAngle,
endAngle: datum.arc.endAngle,
innerRadius: datum.arc.innerRadius,
outerRadius: datum.arc.outerRadius,
}),
from: datum => ({
startAngle: datum.arc.startAngle + (datum.arc.endAngle - datum.arc.startAngle) / 2,
endAngle: datum.arc.startAngle + (datum.arc.endAngle - datum.arc.startAngle) / 2,
innerRadius: datum.arc.innerRadius,
outerRadius: datum.arc.outerRadius,
}),
enter: datum => ({
startAngle: datum.arc.startAngle,
endAngle: datum.arc.endAngle,
innerRadius: datum.arc.innerRadius,
outerRadius: datum.arc.outerRadius,
}),
update: datum => ({
startAngle: datum.arc.startAngle,
endAngle: datum.arc.endAngle,
innerRadius: datum.arc.innerRadius,
outerRadius: datum.arc.outerRadius,
}),
leave: datum => ({
startAngle: datum.arc.startAngle + (datum.arc.endAngle - datum.arc.startAngle) / 2,
endAngle: datum.arc.startAngle + (datum.arc.endAngle - datum.arc.startAngle) / 2,
innerRadius: datum.arc.innerRadius,
outerRadius: datum.arc.outerRadius,
}),
config: springConfig,
immediate: !animate,
})

return {
transition,
interpolate: interpolateArc,
}
}
25 changes: 7 additions & 18 deletions packages/pie/src/Pie.tsx
Expand Up @@ -16,6 +16,7 @@ import PieLegends from './PieLegends'
import { useNormalizedData, usePieFromBox, usePieLayerContext } from './hooks'
import { ComputedDatum, PieLayer, PieSvgProps, PieLayerId } from './types'
import { defaultProps } from './props'
import { Slices } from './Slices'

const Pie = <RawDatum,>({
data,
Expand Down Expand Up @@ -129,24 +130,12 @@ const Pie = <RawDatum,>({

if (layers.includes('slices')) {
layerById.slices = (
<g key="slices" transform={`translate(${centerX},${centerY})`}>
{dataWithArc.map(datumWithArc => (
<PieSlice<RawDatum>
key={datumWithArc.id}
datum={datumWithArc}
arcGenerator={arcGenerator}
borderWidth={borderWidth}
borderColor={borderColor(datumWithArc)}
tooltip={tooltip}
isInteractive={isInteractive}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseMove={onMouseMove}
onMouseLeave={onMouseLeave}
setActiveId={setActiveId}
/>
))}
</g>
<Slices
key="slices"
center={[centerX, centerY]}
data={dataWithArc}
arcGenerator={arcGenerator}
/>
)
}

Expand Down
57 changes: 57 additions & 0 deletions packages/pie/src/Slices.tsx
@@ -0,0 +1,57 @@
import React from 'react'
import { animated } from 'react-spring'
import { ArcGenerator, useArcsTransition } from '@nivo/arcs'
import { ComputedDatum } from './types'

/*
<g key="slices" transform={`translate(${centerX},${centerY})`}>
{dataWithArc.map(datumWithArc => (
<PieSlice<RawDatum>
key={datumWithArc.id}
datum={datumWithArc}
arcGenerator={arcGenerator}
borderWidth={borderWidth}
borderColor={borderColor(datumWithArc)}
tooltip={tooltip}
isInteractive={isInteractive}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseMove={onMouseMove}
onMouseLeave={onMouseLeave}
setActiveId={setActiveId}
/>
))}
</g>
)
*/

interface SlicesProps<RawDatum> {
center: [number, number]
data: ComputedDatum<RawDatum>[]
arcGenerator: ArcGenerator
}

export const Slices = <RawDatum,>({ center, data, arcGenerator }: SlicesProps<RawDatum>) => {
const { transition, interpolate } = useArcsTransition<ComputedDatum<RawDatum>>(data)

return (
<g transform={`translate(${center[0]},${center[1]})`}>
{transition((transitionProps, datum) => {
console.log(transitionProps, datum)
return (
<animated.path
key={datum.id}
fill={datum.color}
d={interpolate(
transitionProps.startAngle,
transitionProps.endAngle,
transitionProps.innerRadius,
transitionProps.outerRadius,
arcGenerator
)}
/>
)
})}
</g>
)
}
7 changes: 3 additions & 4 deletions packages/pie/src/types.ts
@@ -1,9 +1,8 @@
import * as React from 'react'
import { Arc as ArcGenerator } from 'd3-shape'
import { Box, Dimensions, Theme, SvgDefsAndFill } from '@nivo/core'
import { OrdinalColorScaleConfig, InheritedColorConfig } from '@nivo/colors'
import { LegendProps } from '@nivo/legends'
import { Arc } from '@nivo/arcs'
import { Arc, ArcGenerator } from '@nivo/arcs'

export type DatumId = string | number
export type DatumValue = number
Expand Down Expand Up @@ -59,15 +58,15 @@ export type MouseEventHandler<RawDatum, ElementType = HTMLCanvasElement> = (
event: React.MouseEvent<ElementType>
) => void

export type PieLayerId = 'slices' | 'radialLabels' | 'sliceLabels' | 'legends'
export type PieLayerId = 'radialLabels' | 'slices' | 'sliceLabels' | 'legends'

export interface PieCustomLayerProps<RawDatum> {
dataWithArc: ComputedDatum<RawDatum>[]
centerX: number
centerY: number
radius: number
innerRadius: number
arcGenerator: ArcGenerator<any, Arc>
arcGenerator: ArcGenerator
}

export type PieCustomLayer<RawDatum> = React.FC<PieCustomLayerProps<RawDatum>>
Expand Down

0 comments on commit ccb1656

Please sign in to comment.