Skip to content

Commit

Permalink
feat(pie): restore feature parity for slices
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed Dec 18, 2020
1 parent ccb1656 commit 5dbbe0c
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 168 deletions.
21 changes: 0 additions & 21 deletions packages/arcs/src/arcInterpolator.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/arcs/src/index.ts
@@ -1,4 +1,3 @@
export * from './motion'
export * from './types'
export * from './useAnimatedArc'
export * from './useArcGenerator'
export * from './useArcsTransition'
115 changes: 115 additions & 0 deletions packages/arcs/src/motion.ts
@@ -0,0 +1,115 @@
import { to, SpringValue, useSpring, useTransition } from 'react-spring'
import { useMotionConfig } from '@nivo/core'
import { Arc, ArcGenerator, DatumWithArc } from './types'

/**
* Directly animating paths for arcs leads to sub-optimal results
* as the interpolation is gonna be linear while we deal with polar coordinates,
* this interpolator is gonna generate proper arc transitions.
* It should be used with the `useAnimatedArc` or `useArcsTransition` hooks.
*/
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,
})
}
)

/**
* This hook can be used to animate a single arc,
* if you want to animate a group of arcs,
* please have a look at the `useArcsTransition` hook.
*/
export const useAnimatedArc = (datumWithArc: { arc: Arc }, arcGenerator: ArcGenerator) => {
const { animate, config: springConfig } = useMotionConfig()

const animatedValues = useSpring({
startAngle: datumWithArc.arc.startAngle,
endAngle: datumWithArc.arc.endAngle,
innerRadius: datumWithArc.arc.innerRadius,
outerRadius: datumWithArc.arc.outerRadius,
config: springConfig,
immediate: !animate,
})

return {
...animatedValues,
path: interpolateArc(
animatedValues.startAngle,
animatedValues.endAngle,
animatedValues.innerRadius,
animatedValues.outerRadius,
arcGenerator
),
}
}

/**
* This hook can be used to animate a group of arcs,
* if you want to animate a single arc,
* please have a look at the `useAnimatedArc` hook.
*/
export const useArcsTransition = <Datum extends DatumWithArc>(data: Datum[]) => {
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,
}
}
28 changes: 0 additions & 28 deletions packages/arcs/src/useAnimatedArc.ts

This file was deleted.

58 changes: 0 additions & 58 deletions packages/arcs/src/useArcsTransition.ts

This file was deleted.

23 changes: 12 additions & 11 deletions packages/pie/src/Pie.tsx
Expand Up @@ -5,11 +5,9 @@ import {
SvgWrapper,
// @ts-ignore
bindDefs,
useTheme,
useDimensions,
} from '@nivo/core'
import { useInheritedColor, InheritedColorConfig } from '@nivo/colors'
import { PieSlice } from './PieSlice'
import { InheritedColorConfig } from '@nivo/colors'
import { RadialLabels } from './RadialLabels'
import { SliceLabels } from './SliceLabels'
import PieLegends from './PieLegends'
Expand Down Expand Up @@ -42,9 +40,7 @@ const Pie = <RawDatum,>({

// border
borderWidth = defaultProps.borderWidth,
borderColor: _borderColor = defaultProps.borderColor as InheritedColorConfig<
ComputedDatum<RawDatum>
>,
borderColor = defaultProps.borderColor as InheritedColorConfig<ComputedDatum<RawDatum>>,

// radial labels
radialLabel = defaultProps.radialLabel,
Expand Down Expand Up @@ -80,8 +76,6 @@ const Pie = <RawDatum,>({
legends = defaultProps.legends,
role = defaultProps.role,
}: PieSvgProps<RawDatum>) => {
const theme = useTheme()

const { outerWidth, outerHeight, margin, innerWidth, innerHeight } = useDimensions(
width,
height,
Expand Down Expand Up @@ -117,8 +111,6 @@ const Pie = <RawDatum,>({
cornerRadius,
})

const borderColor = useInheritedColor<ComputedDatum<RawDatum>>(_borderColor, theme)

const boundDefs = bindDefs(defs, dataWithArc, fill)

const layerById: Record<PieLayerId, ReactNode> = {
Expand All @@ -130,11 +122,20 @@ const Pie = <RawDatum,>({

if (layers.includes('slices')) {
layerById.slices = (
<Slices
<Slices<RawDatum>
key="slices"
center={[centerX, centerY]}
data={dataWithArc}
arcGenerator={arcGenerator}
borderWidth={borderWidth}
borderColor={borderColor}
isInteractive={isInteractive}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseMove={onMouseMove}
onMouseLeave={onMouseLeave}
setActiveId={setActiveId}
tooltip={tooltip}
/>
)
}
Expand Down
22 changes: 9 additions & 13 deletions packages/pie/src/PieSlice.tsx → packages/pie/src/Slice.tsx
@@ -1,16 +1,14 @@
import React, { createElement, useCallback } from 'react'
import { animated } from 'react-spring'
import { animated, Interpolation } from 'react-spring'
import { useTooltip } from '@nivo/tooltip'
import { useAnimatedArc, ArcGenerator } from '@nivo/arcs'
import { ComputedDatum, CompletePieSvgProps } from './types'

interface PieSliceProps<RawDatum> {
interface SliceProps<RawDatum> {
datum: ComputedDatum<RawDatum>
arcGenerator: ArcGenerator
path?: string
borderWidth: CompletePieSvgProps<RawDatum>['borderWidth']
path: string | Interpolation<string>
borderWidth: number
borderColor: string
isInteractive: CompletePieSvgProps<RawDatum>['isInteractive']
isInteractive: boolean
tooltip: CompletePieSvgProps<RawDatum>['tooltip']
onClick: CompletePieSvgProps<RawDatum>['onClick']
onMouseEnter: CompletePieSvgProps<RawDatum>['onMouseEnter']
Expand All @@ -19,9 +17,9 @@ interface PieSliceProps<RawDatum> {
setActiveId: (id: null | string | number) => void
}

export const PieSlice = <RawDatum,>({
export const Slice = <RawDatum,>({
datum,
arcGenerator,
path,
borderWidth,
borderColor,
isInteractive,
Expand All @@ -31,7 +29,7 @@ export const PieSlice = <RawDatum,>({
onMouseLeave,
tooltip,
setActiveId,
}: PieSliceProps<RawDatum>) => {
}: SliceProps<RawDatum>) => {
const { showTooltipFromEvent, hideTooltip } = useTooltip()

const handleTooltip = useCallback(
Expand Down Expand Up @@ -72,11 +70,9 @@ export const PieSlice = <RawDatum,>({
[onClick, datum]
)

const animatedArc = useAnimatedArc(datum, arcGenerator)

return (
<animated.path
d={animatedArc.path}
d={path}
fill={datum.fill || datum.color}
strokeWidth={borderWidth}
stroke={borderColor}
Expand Down

0 comments on commit 5dbbe0c

Please sign in to comment.