Skip to content

Commit

Permalink
feat(pie): use generic ArcsLayer from the arcs package
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed Dec 18, 2020
1 parent 6c30f05 commit b14ffcd
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 137 deletions.
60 changes: 60 additions & 0 deletions packages/arcs/src/ArcShape.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { useCallback } from 'react'
import { SpringValue, Interpolation, animated } from 'react-spring'
import { DatumWithArcAndColor } from './types'

export type ArcMouseHandler<Datum extends DatumWithArcAndColor> = (
datum: Datum,
event: React.MouseEvent<SVGPathElement>
) => void

export interface ArcShapeProps<Datum extends DatumWithArcAndColor> {
data: Datum
style: {
opacity: SpringValue<number>
color: SpringValue<string>
borderWidth: number
borderColor: SpringValue<string>
path: Interpolation<string>
}
onClick?: ArcMouseHandler<Datum>
onMouseEnter?: ArcMouseHandler<Datum>
onMouseMove?: ArcMouseHandler<Datum>
onMouseLeave?: ArcMouseHandler<Datum>
}

/**
* A simple arc component to be used typically with an `ArcsLayer`.
*
* Please note that the component accepts `SpringValue`s instead of
* regular values to support animations.
*/
export const ArcShape = <Datum extends DatumWithArcAndColor>({
data,
style,
onClick,
onMouseEnter,
onMouseMove,
onMouseLeave,
}: ArcShapeProps<Datum>) => {
const handleClick = useCallback(event => onClick?.(data, event), [onClick, data])

const handleMouseEnter = useCallback(event => onMouseEnter?.(data, event), [onMouseEnter, data])

const handleMouseMove = useCallback(event => onMouseMove?.(data, event), [onMouseMove, data])

const handleMouseLeave = useCallback(event => onMouseLeave?.(data, event), [onMouseLeave, data])

return (
<animated.path
d={style.path}
opacity={style.opacity}
// fill={datum.fill || color}
fill={style.color}
stroke={style.borderColor}
onClick={onClick ? handleClick : undefined}
onMouseEnter={onMouseEnter ? handleMouseEnter : undefined}
onMouseMove={onMouseMove ? handleMouseMove : undefined}
onMouseLeave={onMouseLeave ? handleMouseLeave : undefined}
/>
)
}
93 changes: 93 additions & 0 deletions packages/arcs/src/ArcsLayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { createElement } from 'react'
import { useTheme } from '@nivo/core'
import { InheritedColorConfig, useInheritedColor } from '@nivo/colors'
import { DatumWithArcAndColor, ArcGenerator } from './types'
import { useArcsTransition } from './useArcsTransition'
import { ArcTransitionMode } from './arcTransitionMode'
import { ArcMouseHandler, ArcShape, ArcShapeProps } from './ArcShape'

type ArcComponent<Datum extends DatumWithArcAndColor> = (props: ArcShapeProps<Datum>) => JSX.Element

interface ArcsLayerProps<Datum extends DatumWithArcAndColor> {
center: [number, number]
data: Datum[]
arcGenerator: ArcGenerator
borderWidth: number
borderColor: InheritedColorConfig<Datum>
onClick?: ArcMouseHandler<Datum>
onMouseEnter?: ArcMouseHandler<Datum>
onMouseMove?: ArcMouseHandler<Datum>
onMouseLeave?: ArcMouseHandler<Datum>
transitionMode: ArcTransitionMode
component?: ArcComponent<Datum>
}

export const ArcsLayer = <Datum extends DatumWithArcAndColor>({
center,
data,
arcGenerator,
borderWidth,
borderColor,
onClick,
onMouseEnter,
onMouseMove,
onMouseLeave,
transitionMode,
component = ArcShape,
}: ArcsLayerProps<Datum>) => {
const theme = useTheme()
const getBorderColor = useInheritedColor<Datum>(borderColor, theme)

const { transition, interpolate } = useArcsTransition<
Datum,
{
opacity: number
color: string
borderColor: string
}
>(data, transitionMode, {
enter: datum => ({
opacity: 0,
color: datum.color,
borderColor: getBorderColor(datum),
}),
update: datum => ({
opacity: 1,
color: datum.color,
borderColor: getBorderColor(datum),
}),
leave: datum => ({
opacity: 0,
color: datum.color,
borderColor: getBorderColor(datum),
}),
})

const Arc: ArcComponent<Datum> = component

return (
<g transform={`translate(${center[0]},${center[1]})`}>
{transition((transitionProps, datum) => {
return createElement(Arc, {
key: datum.id,
data: datum,
style: {
...transitionProps,
borderWidth,
path: interpolate(
transitionProps.startAngle,
transitionProps.endAngle,
transitionProps.innerRadius,
transitionProps.outerRadius,
arcGenerator
),
},
onClick,
onMouseEnter,
onMouseMove,
onMouseLeave,
})
})}
</g>
)
}
2 changes: 2 additions & 0 deletions packages/arcs/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './ArcShape'
export * from './ArcsLayer'
export * from './arcTransitionMode'
export * from './boundingBox'
export * from './canvas'
Expand Down
90 changes: 0 additions & 90 deletions packages/pie/src/Slice.tsx

This file was deleted.

99 changes: 52 additions & 47 deletions packages/pie/src/Slices.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import React from 'react'
import { Interpolation } from 'react-spring'
import { useTheme } from '@nivo/core'
import { useInheritedColor } from '@nivo/colors'
import { ArcGenerator, useArcsTransition } from '@nivo/arcs'
import React, { createElement, useMemo } from 'react'
import { ArcGenerator, ArcsLayer } from '@nivo/arcs'
import { useTooltip } from '@nivo/tooltip'
import { ComputedDatum, CompletePieSvgProps } from './types'
import { Slice } from './Slice'

interface SlicesProps<RawDatum> {
center: [number, number]
Expand Down Expand Up @@ -37,49 +34,57 @@ export const Slices = <RawDatum,>({
tooltip,
transitionMode,
}: SlicesProps<RawDatum>) => {
const theme = useTheme()
const getBorderColor = useInheritedColor<ComputedDatum<RawDatum>>(borderColor, theme)
const { transition, interpolate } = useArcsTransition<
ComputedDatum<RawDatum>,
{
color: string
const { showTooltipFromEvent, hideTooltip } = useTooltip()

const handleClick = useMemo(() => {
if (!isInteractive) return undefined

return (datum: ComputedDatum<RawDatum>, event: any) => {
onClick?.(datum, event)
}
}, [isInteractive, onClick])

const handleMouseEnter = useMemo(() => {
if (!isInteractive) return undefined

return (datum: ComputedDatum<RawDatum>, event: any) => {
showTooltipFromEvent(createElement(tooltip, { datum }), event)
setActiveId(datum.id)
onMouseEnter?.(datum, event)
}
}, [isInteractive, showTooltipFromEvent, setActiveId, onMouseEnter])

const handleMouseMove = useMemo(() => {
if (!isInteractive) return undefined

return (datum: ComputedDatum<RawDatum>, event: any) => {
showTooltipFromEvent(createElement(tooltip, { datum }), event)
onMouseMove?.(datum, event)
}
}, [isInteractive, showTooltipFromEvent, onMouseMove])

const handleMouseLeave = useMemo(() => {
if (!isInteractive) return undefined

return (datum: ComputedDatum<RawDatum>, event: any) => {
hideTooltip()
setActiveId(null)
onMouseLeave?.(datum, event)
}
>(data, transitionMode, {
enter: datum => ({ color: datum.color }),
update: datum => ({ color: datum.color }),
leave: datum => ({ color: datum.color }),
})
}, [isInteractive, hideTooltip, setActiveId, onMouseLeave])

return (
<g transform={`translate(${center[0]},${center[1]})`}>
{transition((transitionProps, datum) => {
return (
<Slice<RawDatum>
key={datum.id}
datum={datum}
path={
interpolate(
transitionProps.startAngle,
transitionProps.endAngle,
transitionProps.innerRadius,
transitionProps.outerRadius,
arcGenerator
) as Interpolation<string>
}
color={transitionProps.color}
opacity={transitionProps.progress}
borderWidth={borderWidth}
borderColor={getBorderColor(datum)}
isInteractive={isInteractive}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseMove={onMouseMove}
onMouseLeave={onMouseLeave}
setActiveId={setActiveId}
tooltip={tooltip}
/>
)
})}
</g>
<ArcsLayer<ComputedDatum<RawDatum>>
center={center}
data={data}
arcGenerator={arcGenerator}
borderWidth={borderWidth}
borderColor={borderColor}
transitionMode={transitionMode}
onClick={handleClick}
onMouseEnter={handleMouseEnter}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
/>
)
}

0 comments on commit b14ffcd

Please sign in to comment.