Skip to content

Commit

Permalink
add mes to bump chart
Browse files Browse the repository at this point in the history
  • Loading branch information
santiperone committed Jan 8, 2024
1 parent d87af09 commit 15e5b78
Show file tree
Hide file tree
Showing 12 changed files with 26,121 additions and 34,307 deletions.
1 change: 1 addition & 0 deletions packages/bump/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@nivo/legends": "workspace:*",
"@nivo/scales": "workspace:*",
"@nivo/tooltip": "workspace:*",
"@nivo/voronoi": "workspace:*",
"@react-spring/web": "9.4.5 || ^9.7.2",
"@types/d3-scale": "^3.2.3",
"@types/d3-shape": "^2.0.0",
Expand Down
128 changes: 83 additions & 45 deletions packages/bump/src/bump/Bump.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useBump } from './hooks'
import { bumpSvgDefaultProps } from './defaults'
import { Line } from './Line'
import { LinesLabels } from './LinesLabels'
import { Points } from './Points'
import { Mesh } from './Mesh'

type InnerBumpProps<Datum extends BumpDatum, ExtraProps extends BumpSerieExtraProps> = Omit<
BumpSvgProps<Datum, ExtraProps>,
Expand Down Expand Up @@ -57,7 +57,7 @@ const InnerBump = <Datum extends BumpDatum, ExtraProps extends BumpSerieExtraPro
BumpSvgProps<Datum, ExtraProps>['endLabelTextColor']
>,

pointComponent = bumpSvgDefaultProps.pointComponent as NonNullable<
pointComponent = bumpSvgDefaultProps.pointComponent as unknown as NonNullable<
BumpSvgProps<Datum, ExtraProps>['pointComponent']
>,
pointSize = bumpSvgDefaultProps.pointSize,
Expand All @@ -82,13 +82,22 @@ const InnerBump = <Datum extends BumpDatum, ExtraProps extends BumpSerieExtraPro

isInteractive = bumpSvgDefaultProps.isInteractive,
defaultActiveSerieIds = bumpSvgDefaultProps.defaultActiveSerieIds,
onMouseEnter,
onMouseMove,
onMouseLeave,
onClick,
tooltip = bumpSvgDefaultProps.tooltip as NonNullable<
BumpSvgProps<Datum, ExtraProps>['tooltip']
onSerieMouseEnter,
onSerieMouseMove,
onSerieMouseLeave,
onSerieClick,
onPointMouseEnter,
onPointMouseMove,
onPointMouseLeave,
onPointClick,
tooltipAnchor = bumpSvgDefaultProps.tooltipAnchor,
lineTooltip = bumpSvgDefaultProps.lineTooltip as NonNullable<
BumpSvgProps<Datum, ExtraProps>['lineTooltip']
>,
pointTooltip = bumpSvgDefaultProps.pointTooltip as NonNullable<
BumpSvgProps<Datum, ExtraProps>['pointTooltip']
>,
debugMesh = bumpSvgDefaultProps.debugMesh,
role = bumpSvgDefaultProps.role,
}: InnerBumpProps<Datum, ExtraProps>) => {
const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(
Expand All @@ -97,40 +106,49 @@ const InnerBump = <Datum extends BumpDatum, ExtraProps extends BumpSerieExtraPro
partialMargin
)

const { series, points, xScale, yScale, lineGenerator, activeSerieIds, setActiveSerieIds } =
useBump<Datum, ExtraProps>({
width: innerWidth,
height: innerHeight,
data,
interpolation,
xPadding,
xOuterPadding,
yOuterPadding,
lineWidth,
activeLineWidth,
inactiveLineWidth,
colors,
opacity,
activeOpacity,
inactiveOpacity,
pointSize,
activePointSize,
inactivePointSize,
pointColor,
pointBorderWidth,
activePointBorderWidth,
inactivePointBorderWidth,
pointBorderColor,
isInteractive,
defaultActiveSerieIds,
})
const {
series,
points,
xScale,
yScale,
lineGenerator,
activeSerieIds,
setActiveSerieIds,
setActivePointIds,
} = useBump<Datum, ExtraProps>({
width: innerWidth,
height: innerHeight,
data,
interpolation,
xPadding,
xOuterPadding,
yOuterPadding,
lineWidth,
activeLineWidth,
inactiveLineWidth,
colors,
opacity,
activeOpacity,
inactiveOpacity,
pointSize,
activePointSize,
inactivePointSize,
pointColor,
pointBorderWidth,
activePointBorderWidth,
inactivePointBorderWidth,
pointBorderColor,
isInteractive,
defaultActiveSerieIds,
})

const layerById: Record<BumpLayerId, ReactNode> = {
grid: null,
axes: null,
labels: null,
lines: null,
points: null,
mesh: null,
}

if (layers.includes('grid')) {
Expand Down Expand Up @@ -172,27 +190,47 @@ const InnerBump = <Datum extends BumpDatum, ExtraProps extends BumpSerieExtraPro
lineGenerator={lineGenerator}
yStep={yScale.step()}
isInteractive={isInteractive}
onMouseEnter={onMouseEnter}
onMouseMove={onMouseMove}
onMouseLeave={onMouseLeave}
onClick={onClick}
tooltip={tooltip}
onMouseEnter={onSerieMouseEnter}
onMouseMove={onSerieMouseMove}
onMouseLeave={onSerieMouseLeave}
onClick={onSerieClick}
lineTooltip={lineTooltip}
tooltipAnchor={tooltipAnchor}
/>
))}
</Fragment>
)
}

if (layers.includes('points')) {
layerById.points = (
<Points<Datum, ExtraProps>
key="points"
pointComponent={pointComponent}
if (isInteractive && tooltipAnchor === 'point') {
layerById.mesh = (
<Mesh
key="mesh"
points={points}
width={innerWidth}
height={innerHeight}
margin={margin}
setActivePointIds={setActivePointIds}
setActiveSerieIds={setActiveSerieIds}
onMouseEnter={onPointMouseEnter}
onMouseMove={onPointMouseMove}
onMouseLeave={onPointMouseLeave}
onClick={onPointClick}
tooltip={pointTooltip}
debug={debugMesh}
/>
)
}

if (layers.includes('points')) {
layerById.points = points.map(point =>
createElement(pointComponent, {
key: point.id,
point,
})
)
}

if (layers.includes('labels')) {
layerById.labels = (
<Fragment key="legends">
Expand Down
18 changes: 10 additions & 8 deletions packages/bump/src/bump/Line.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ interface LineProps<Datum extends BumpDatum, ExtraProps extends BumpSerieExtraPr
lineGenerator: D3Line<[number, number | null]>
yStep: number
isInteractive: BumpCommonProps<Datum, ExtraProps>['isInteractive']
onMouseEnter?: BumpCommonProps<Datum, ExtraProps>['onMouseEnter']
onMouseMove?: BumpCommonProps<Datum, ExtraProps>['onMouseMove']
onMouseLeave?: BumpCommonProps<Datum, ExtraProps>['onMouseLeave']
onClick?: BumpCommonProps<Datum, ExtraProps>['onClick']
onMouseEnter?: BumpCommonProps<Datum, ExtraProps>['onSerieMouseEnter']
onMouseMove?: BumpCommonProps<Datum, ExtraProps>['onSerieMouseMove']
onMouseLeave?: BumpCommonProps<Datum, ExtraProps>['onSerieMouseLeave']
onClick?: BumpCommonProps<Datum, ExtraProps>['onSerieClick']
setActiveSerieIds: (serieIds: string[]) => void
tooltip: BumpCommonProps<Datum, ExtraProps>['tooltip']
lineTooltip: BumpCommonProps<Datum, ExtraProps>['lineTooltip']
tooltipAnchor: string
}

export const Line = <Datum extends BumpDatum, ExtraProps extends BumpSerieExtraProps>({
Expand All @@ -27,7 +28,8 @@ export const Line = <Datum extends BumpDatum, ExtraProps extends BumpSerieExtraP
onMouseLeave,
onClick,
setActiveSerieIds,
tooltip,
lineTooltip,
tooltipAnchor,
}: LineProps<Datum, ExtraProps>) => {
const handlers = useBumpSerieHandlers<Datum, ExtraProps>({
serie,
Expand All @@ -37,7 +39,7 @@ export const Line = <Datum extends BumpDatum, ExtraProps extends BumpSerieExtraP
onMouseLeave,
onClick,
setActiveSerieIds,
tooltip,
lineTooltip,
})

const { animate, config: springConfig } = useMotionConfig()
Expand Down Expand Up @@ -69,7 +71,7 @@ export const Line = <Datum extends BumpDatum, ExtraProps extends BumpSerieExtraP
strokeOpacity={animatedProps.opacity}
style={{ pointerEvents: 'none' }}
/>
{isInteractive && (
{isInteractive && tooltipAnchor === 'line' && (
<path
data-testid={`line.${serie.id}.interactive`}
fill="none"
Expand Down
10 changes: 5 additions & 5 deletions packages/bump/src/bump/LinesLabels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,19 @@ export const LinesLabels = <Datum extends BumpDatum, ExtraProps extends BumpSeri

return (
<animated.text
data-testid={`label.${position}.${label.serie.id}`}
key={label.id}
data-testid={`label.${position}.${label?.serie.id}`}
key={label?.id}
x={animatedProps.x}
y={animatedProps.y}
textAnchor={label.textAnchor}
textAnchor={label?.textAnchor}
dominantBaseline="central"
opacity={animatedProps.opacity}
style={{
...theme.labels.text,
fill: label.color,
fill: label?.color,
}}
>
{label.label}
{label?.label}
</animated.text>
)
})}
Expand Down
118 changes: 118 additions & 0 deletions packages/bump/src/bump/Mesh.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { MouseEvent } from 'react'
import { createElement, memo, useCallback } from 'react'
import { useTooltip } from '@nivo/tooltip'
import { Mesh as BaseMesh } from '@nivo/voronoi'
import { BumpCommonProps, BumpDatum, BumpPoint, BumpSerieExtraProps } from './types'

interface MeshProps<Datum extends BumpDatum, ExtraProps extends BumpSerieExtraProps> {
points: BumpPoint<Datum, ExtraProps>[]
width: number
height: number
margin: {
top: number
right: number
bottom: number
left: number
}
setActivePointIds: (ids: string[]) => void
setActiveSerieIds: (ids: string[]) => void
onMouseEnter?: BumpCommonProps<Datum, ExtraProps>['onPointMouseEnter']
onMouseMove?: BumpCommonProps<Datum, ExtraProps>['onPointMouseMove']
onMouseLeave?: BumpCommonProps<Datum, ExtraProps>['onPointMouseLeave']
onClick?: BumpCommonProps<Datum, ExtraProps>['onPointClick']
tooltip: BumpCommonProps<Datum, ExtraProps>['pointTooltip']
debug: boolean
}

const InnerMesh = <Datum extends BumpDatum, ExtraProps extends BumpSerieExtraProps>({
points,
width,
height,
margin,
setActivePointIds,
setActiveSerieIds,
onMouseEnter,
onMouseMove,
onMouseLeave,
onClick,
tooltip,
debug,
}: MeshProps<Datum, ExtraProps>) => {
const { showTooltipAt, hideTooltip } = useTooltip()

const handleMouseEnter = useCallback(
(point: BumpPoint<Datum, ExtraProps>, event: MouseEvent) => {
showTooltipAt(
createElement(tooltip, { point }),
[point.x + margin.left, point.y ?? 0 + margin.top],
'top'
)
setActivePointIds([point.id])
setActiveSerieIds([point.serie.id])
onMouseEnter && onMouseEnter(point, event)
},
[
showTooltipAt,
tooltip,
margin.left,
margin.top,
setActivePointIds,
setActiveSerieIds,
onMouseEnter,
]
)

const handleMouseMove = useCallback(
(point: BumpPoint<Datum, ExtraProps>, event: MouseEvent) => {
showTooltipAt(
createElement(tooltip, { point }),
[point.x + margin.left, point.y ?? 0 + margin.top],
'top'
)
setActivePointIds([point.id])
setActiveSerieIds([point.serie.id])
onMouseMove && onMouseMove(point, event)
},
[
showTooltipAt,
tooltip,
margin.left,
margin.top,
setActivePointIds,
setActiveSerieIds,
onMouseMove,
]
)

const handleMouseLeave = useCallback(
(point: BumpPoint<Datum, ExtraProps>, event: MouseEvent) => {
hideTooltip()
setActivePointIds([])
setActiveSerieIds([])
onMouseLeave && onMouseLeave(point, event)
},
[hideTooltip, onMouseLeave, setActivePointIds, setActiveSerieIds]
)

const handleClick = useCallback(
(point: BumpPoint<Datum, ExtraProps>, event: MouseEvent) => {
onClick && onClick(point, event)
},
[onClick]
)

return (
<BaseMesh
nodes={points}
width={width}
height={height}
onMouseEnter={handleMouseEnter}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
onClick={handleClick}
debug={debug}
/>
)
}

export const Mesh = memo(InnerMesh) as typeof InnerMesh
6 changes: 4 additions & 2 deletions packages/bump/src/bump/Point.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { useSpring, animated, to } from '@react-spring/web'
import { useMotionConfig } from '@nivo/core'
import { BumpDatum, BumpPoint, BumpSerieExtraProps } from './types'

const pointStyle: SVGAttributes<SVGCircleElement>['style'] = { pointerEvents: 'none' }
const pointStyle: SVGAttributes<SVGCircleElement>['style'] = {
pointerEvents: 'none',
}

interface PointProps<Datum extends BumpDatum, ExtraProps extends BumpSerieExtraProps> {
export interface PointProps<Datum extends BumpDatum, ExtraProps extends BumpSerieExtraProps> {
point: BumpPoint<Datum, ExtraProps>
}

Expand Down
Loading

0 comments on commit 15e5b78

Please sign in to comment.