Skip to content

Commit

Permalink
feat(swarmplot): migrate to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc authored and wyze committed Jun 22, 2021
1 parent 8228f8b commit a7f56ed
Show file tree
Hide file tree
Showing 31 changed files with 1,549 additions and 1,311 deletions.
8 changes: 4 additions & 4 deletions packages/swarmplot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@
"@nivo/voronoi": "0.70.1",
"d3-force": "^2.0.1",
"d3-scale": "^3.2.3",
"lodash": "^4.17.21",
"react-motion": "^0.5.2"
"lodash": "^4.17.21"
},
"devDependencies": {
"@nivo/core": "0.70.1"
"@nivo/core": "0.70.1",
"@types/d3-force": "^2.1.0",
"@types/d3-scale": "^3.2.2"
},
"peerDependencies": {
"@nivo/core": "0.70.1",
"prop-types": ">= 15.5.10 < 16.0.0",
"react": ">= 16.8.4 < 18.0.0"
},
"publishConfig": {
Expand Down
108 changes: 0 additions & 108 deletions packages/swarmplot/src/AnimatedSwarmPlotNodes.js

This file was deleted.

38 changes: 38 additions & 0 deletions packages/swarmplot/src/CircleSvg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react'
import { animated } from 'react-spring'
import { CircleProps } from './types'
// import { useNodeMouseHandlers } from './hooks'

export const CircleSvg = <RawDatum,>({
node,
style,
}: // onMouseEnter,
// onMouseMove,
// onMouseLeave,
// onClick,
CircleProps<RawDatum>) => {
// const handlers = {}
/*useNodeMouseHandlers<RawDatum>(node, {
onMouseEnter,
onMouseMove,
onMouseLeave,
onClick,
})*/

return (
<animated.circle
key={node.id}
cx={style.x}
cy={style.y}
r={style.radius}
fill={style.color}
stroke={style.borderColor}
strokeWidth={style.borderWidth}
opacity={style.opacity}
// onMouseEnter={handlers.onMouseEnter}
// onMouseMove={handlers.onMouseMove}
// onMouseLeave={handlers.onMouseLeave}
// onClick={handlers.onClick}
/>
)
}
152 changes: 152 additions & 0 deletions packages/swarmplot/src/Circles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import React, { createElement, useMemo, MouseEvent } from 'react'
import { useTransition, to, SpringValue } from 'react-spring'
import { useMotionConfig, useTheme } from '@nivo/core'
import { useInheritedColor } from '@nivo/colors'
import { useTooltip } from '@nivo/tooltip'
import { ComputedDatum, CircleComponent, MouseHandlers, SwarmPlotCommonProps } from './types'

/**
* A negative radius value is invalid for an SVG circle,
* this custom interpolation makes sure it's either
* positive or zero.
*/
export const interpolateRadius = (radiusValue: SpringValue<number>) =>
to([radiusValue], radius => Math.max(0, radius))

type CirclesProps<RawDatum> = {
nodes: ComputedDatum<RawDatum>[]
borderWidth: SwarmPlotCommonProps<RawDatum>['borderWidth']
borderColor: SwarmPlotCommonProps<RawDatum>['borderColor']
component: CircleComponent<RawDatum>
isInteractive: SwarmPlotCommonProps<RawDatum>['isInteractive']
tooltip: SwarmPlotCommonProps<RawDatum>['tooltip']
} & MouseHandlers<RawDatum>

const getTransitionPhases = <RawDatum,>(
getBorderColor: (node: ComputedDatum<RawDatum>) => string
) => ({
enter: (node: ComputedDatum<RawDatum>) => ({
x: node.x,
y: node.y,
radius: 0,
color: node.color,
borderColor: getBorderColor(node),
opacity: 0,
}),
update: (node: ComputedDatum<RawDatum>) => ({
x: node.x,
y: node.y,
radius: node.size / 2,
color: node.color,
borderColor: getBorderColor(node),
opacity: 1,
}),
leave: (node: ComputedDatum<RawDatum>) => ({
x: node.x,
y: node.y,
radius: 0,
color: node.color,
borderColor: getBorderColor(node),
opacity: 0,
}),
})

export const Circles = <RawDatum,>({
nodes,
borderWidth,
borderColor,
component,
isInteractive,
onMouseEnter,
onMouseMove,
onMouseLeave,
onClick,
tooltip,
}: CirclesProps<RawDatum>) => {
const { showTooltipFromEvent, hideTooltip } = useTooltip()

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

return (node: ComputedDatum<RawDatum>, event: MouseEvent) => {
showTooltipFromEvent(createElement(tooltip, node), event)
onMouseEnter?.(node, event)
}
}, [isInteractive, showTooltipFromEvent, tooltip, onMouseEnter])

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

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

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

return (node: ComputedDatum<RawDatum>, event: MouseEvent) => {
hideTooltip()
onMouseLeave?.(node, event)
}
}, [isInteractive, hideTooltip, onMouseLeave])

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

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

const { animate, config: springConfig } = useMotionConfig()

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

const transitionPhases = useMemo(() => getTransitionPhases<RawDatum>(getBorderColor), [
getBorderColor,
])

const transition = useTransition<
ComputedDatum<RawDatum>,
{
x: number
y: number
radius: number
color: string
borderColor: string
opacity: number
}
>(nodes, {
key: node => node.id,
initial: transitionPhases.update,
from: transitionPhases.enter,
enter: transitionPhases.update,
update: transitionPhases.update,
leave: transitionPhases.leave,
config: springConfig,
immediate: !animate,
})

return (
<>
{transition((transitionProps, node) => {
return React.createElement(component, {
key: node.id,
node,
style: {
...transitionProps,
radius: interpolateRadius(transitionProps.radius),
borderWidth,
},
onMouseEnter: handleMouseEnter,
onMouseMove: handleMouseMove,
onMouseLeave: handleMouseLeave,
onClick: handleClick,
})
})}
</>
)
}
11 changes: 0 additions & 11 deletions packages/swarmplot/src/ResponsiveSwarmPlot.js

This file was deleted.

17 changes: 17 additions & 0 deletions packages/swarmplot/src/ResponsiveSwarmPlot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react'
import { ResponsiveWrapper } from '@nivo/core'
import { SwarmPlotSvgProps } from './types'
import { SwarmPlot } from './SwarmPlot'

type ResponsiveCirclePackingProps<RawDatum> = Partial<
Omit<SwarmPlotSvgProps<RawDatum>, 'data' | 'groups' | 'width' | 'height'>
> &
Pick<SwarmPlotSvgProps<RawDatum>, 'data' | 'groups'>

export const ResponsiveSwarmPlot = <RawDatum,>(props: ResponsiveCirclePackingProps<RawDatum>) => (
<ResponsiveWrapper>
{({ width, height }: { width: number; height: number }) => (
<SwarmPlot<RawDatum> width={width} height={height} {...props} />
)}
</ResponsiveWrapper>
)
11 changes: 0 additions & 11 deletions packages/swarmplot/src/ResponsiveSwarmPlotCanvas.js

This file was deleted.

19 changes: 19 additions & 0 deletions packages/swarmplot/src/ResponsiveSwarmPlotCanvas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'
import { ResponsiveWrapper } from '@nivo/core'
import { SwarmPlotCanvasProps } from './types'
import { SwarmPlotCanvas } from './SwarmPlotCanvas'

type ResponsiveSwarmPlotCanvasProps<RawDatum> = Partial<
Omit<SwarmPlotCanvasProps<RawDatum>, 'data' | 'groups' | 'width' | 'height'>
> &
Pick<SwarmPlotCanvasProps<RawDatum>, 'data' | 'groups'>

export const ResponsiveSwarmPlotCanvas = <RawDatum,>(
props: ResponsiveSwarmPlotCanvasProps<RawDatum>
) => (
<ResponsiveWrapper>
{({ width, height }: { width: number; height: number }) => (
<SwarmPlotCanvas<RawDatum> width={width} height={height} {...props} />
)}
</ResponsiveWrapper>
)
Loading

0 comments on commit a7f56ed

Please sign in to comment.