Skip to content

Commit

Permalink
feat(funnel): add support for current part
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed Jun 17, 2020
1 parent 826c08f commit a69780f
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 9 deletions.
12 changes: 11 additions & 1 deletion packages/funnel/src/Funnel.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const Funnel = props => {
layers,

isInteractive,
currentPartSizeExtension,
onMouseEnter,
onMouseMove,
onMouseLeave,
Expand All @@ -63,7 +64,14 @@ const Funnel = props => {
const theme = useTheme()
const { animate } = useMotionConfig()

const { areaGenerator, borderGenerator, parts, beforeSeparators, afterSeparators } = useFunnel({
const {
areaGenerator,
borderGenerator,
parts,
beforeSeparators,
afterSeparators,
setCurrentPartId,
} = useFunnel({
data,
width: innerWidth,
height: innerHeight,
Expand All @@ -82,6 +90,7 @@ const Funnel = props => {
beforeSeparatorOffset,
afterSeparatorLength,
afterSeparatorOffset,
currentPartSizeExtension,
})

const layerById = {
Expand All @@ -99,6 +108,7 @@ const Funnel = props => {
areaGenerator={areaGenerator}
borderGenerator={borderGenerator}
enableLabel={enableLabel}
setCurrentPartId={setCurrentPartId}
/>
),
labels: null,
Expand Down
10 changes: 8 additions & 2 deletions packages/funnel/src/Part.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import React from 'react'
import PropTypes from 'prop-types'
import { useSpring, animated, config } from 'react-spring'

export const Part = ({ part, areaGenerator, borderGenerator }) => {
export const Part = ({ part, areaGenerator, borderGenerator, setCurrentPartId }) => {
const animatedProps = useSpring({
areaPath: areaGenerator(part.areaPoints),
areaColor: part.color,
borderPath: borderGenerator(part.borderPoints),
borderColor: part.borderColor,
config: config.molasses,
config: config.wobbly,
})

return (
Expand All @@ -34,6 +34,12 @@ export const Part = ({ part, areaGenerator, borderGenerator }) => {
d={animatedProps.areaPath}
fill={animatedProps.areaColor}
fillOpacity={part.fillOpacity}
onMouseEnter={() => {
setCurrentPartId(part.data.id)
}}
onMouseLeave={() => {
setCurrentPartId(null)
}}
/>
</>
)
Expand Down
3 changes: 2 additions & 1 deletion packages/funnel/src/Parts.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
import React from 'react'
import { Part } from './Part'

export const Parts = ({ parts, areaGenerator, borderGenerator }) =>
export const Parts = ({ parts, areaGenerator, borderGenerator, setCurrentPartId }) =>
parts.map(part => (
<Part
key={part.data.id}
part={part}
areaGenerator={areaGenerator}
borderGenerator={borderGenerator}
setCurrentPartId={setCurrentPartId}
/>
))
27 changes: 24 additions & 3 deletions packages/funnel/src/hooks.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo } from 'react'
import { useMemo, useState, useCallback } from 'react'
import { line, area, curveBasis, curveLinear } from 'd3-shape'
import { scaleLinear } from 'd3-scale'
import { useInheritedColor, useOrdinalColorScale } from '@nivo/colors'
Expand Down Expand Up @@ -173,6 +173,7 @@ export const useFunnel = ({
beforeSeparatorOffset = defaults.beforeSeparatorOffset,
afterSeparatorLength = defaults.afterSeparatorLength,
afterSeparatorOffset = defaults.afterSeparatorOffset,
currentPartSizeExtension = defaults.currentPartSizeExtension,
}) => {
const theme = useTheme()
const getColor = useOrdinalColorScale(colors, 'id')
Expand Down Expand Up @@ -210,8 +211,12 @@ export const useFunnel = ({
[data, direction, innerWidth, innerHeight, spacing]
)

const [currentPartId, setCurrentPartId] = useState(null)

const parts = useMemo(() => {
const enhancedParts = data.map((datum, index) => {
const isCurrent = datum.id === currentPartId

let partWidth
let partHeight
let y0, x0
Expand Down Expand Up @@ -242,6 +247,7 @@ export const useFunnel = ({
borderWidth,
borderOpacity,
formattedValue: formatValue(datum.value),
isCurrent,
x,
x0,
x1,
Expand Down Expand Up @@ -271,8 +277,14 @@ export const useFunnel = ({
part.points.push({ x: nextPart.x1, y: part.y1 })
part.points.push({ x: nextPart.x0, y: part.y1 })
} else {
part.points.push({ x: part.x1, y: part.y1 })
part.points.push({ x: part.x0, y: part.y1 })
part.points.push({ x: part.points[1].x, y: part.y1 })
part.points.push({ x: part.points[0].x, y: part.y1 })
}
if (part.isCurrent === true) {
part.points[0].x -= currentPartSizeExtension
part.points[1].x += currentPartSizeExtension
part.points[2].x += currentPartSizeExtension
part.points[3].x -= currentPartSizeExtension
}

part.areaPoints = [
Expand Down Expand Up @@ -319,6 +331,12 @@ export const useFunnel = ({
part.points.push({ x: part.x1, y: part.y1 })
}
part.points.push({ x: part.x0, y: part.y1 })
if (part.isCurrent === true) {
part.points[0].y -= currentPartSizeExtension
part.points[1].y -= currentPartSizeExtension
part.points[2].y += currentPartSizeExtension
part.points[3].y += currentPartSizeExtension
}

part.areaPoints = [
{
Expand Down Expand Up @@ -372,6 +390,7 @@ export const useFunnel = ({
formatValue,
getBorderColor,
getLabelColor,
currentPartId,
])

const [beforeSeparators, afterSeparators] = useMemo(
Expand Down Expand Up @@ -406,5 +425,7 @@ export const useFunnel = ({
borderGenerator,
beforeSeparators,
afterSeparators,
setCurrentPartId,
currentPartId,
}
}
2 changes: 2 additions & 0 deletions packages/funnel/src/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const FunnelPropTypes = {
afterSeparatorOffset: PropTypes.number.isRequired,

isInteractive: PropTypes.bool.isRequired,
currentPartSizeExtension: PropTypes.number.isRequired,
onClick: PropTypes.func,
onMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func,
Expand Down Expand Up @@ -79,6 +80,7 @@ export const FunnelDefaultProps = {
afterSeparatorOffset: 0,

isInteractive: true,
currentPartSizeExtension: 0,

animate: true,
motionDamping: 13,
Expand Down
26 changes: 26 additions & 0 deletions website/src/data/components/funnel/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,23 @@ import { FunnelDefaultProps as defaults } from '@nivo/funnel'
import { groupProperties } from '../../../lib/componentProperties'

const props = [
{
key: 'data',
type: 'Array<Datum>',
group: 'Base',
help: 'Chart data.',
description: `
Chart data, which must conform to this structure:
\`\`\`
Array<{
id: string | number
label: string
value: number
}>
\`\`\`
`,
required: true,
},
{
key: 'margin',
group: 'Base',
Expand Down Expand Up @@ -269,6 +286,15 @@ const props = [
type: 'Array<string | Function>',
defaultValue: defaults.layers,
},
{
key: 'isInteractive',
group: 'Interactivity',
type: 'boolean',
help: 'Enable/disable interactivity.',
required: false,
defaultValue: defaults.isInteractive,
controlType: 'switch',
},
]

export const groups = groupProperties(props)
5 changes: 3 additions & 2 deletions website/src/pages/funnel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,12 @@ const initialProperties = {
afterSeparatorLength: 40,
afterSeparatorOffset: 20,

isInteractive: true,
currentPartSizeExtension: 30,

animate: true,
motionStiffness: 90,
motionDamping: 15,

isInteractive: true,
}

const Funnel = () => {
Expand Down

0 comments on commit a69780f

Please sign in to comment.