Skip to content

Commit

Permalink
feat(marimekko): compute bars from top level component and pass them …
Browse files Browse the repository at this point in the history
…to custom layers
  • Loading branch information
plouc committed Nov 16, 2020
1 parent 57b27d8 commit 146a04b
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 72 deletions.
18 changes: 8 additions & 10 deletions packages/marimekko/src/Bar.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import React, { createElement, MouseEvent } from 'react'
import { animated, SpringValues } from 'react-spring'
import { animated, SpringValues, to } from 'react-spring'
import { useTooltip } from '@nivo/tooltip'
import { DimensionDatum } from './types'
import { BarDatum } from './types'
import { BarTooltip } from './BarTooltip'

interface BarProps<RawDatum> {
datum: DimensionDatum<RawDatum>
borderWidth: number
borderColor: string
bar: BarDatum<RawDatum>
animatedProps: SpringValues<{
x: number
y: number
Expand All @@ -19,12 +17,12 @@ interface BarProps<RawDatum> {
}>
}

export const Bar = <RawDatum,>({ datum, borderWidth, animatedProps }: BarProps<RawDatum>) => {
export const Bar = <RawDatum,>({ bar, animatedProps }: BarProps<RawDatum>) => {
const { showTooltipFromEvent, hideTooltip } = useTooltip()

const handle = (event: MouseEvent) => {
showTooltipFromEvent(
createElement<{ datum: DimensionDatum<RawDatum> }>(BarTooltip, { datum }),
createElement<{ bar: BarDatum<RawDatum> }>(BarTooltip, { bar }),
event
)
}
Expand All @@ -33,11 +31,11 @@ export const Bar = <RawDatum,>({ datum, borderWidth, animatedProps }: BarProps<R
<animated.rect
x={animatedProps.x}
y={animatedProps.y}
width={animatedProps.width}
height={animatedProps.height}
width={to(animatedProps.width, value => Math.max(value, 0))}
height={to(animatedProps.height, value => Math.max(value, 0))}
fill={animatedProps.color}
stroke={animatedProps.borderColor}
strokeWidth={borderWidth}
strokeWidth={bar.borderWidth}
onMouseEnter={handle}
onMouseMove={handle}
onMouseLeave={hideTooltip}
Expand Down
10 changes: 5 additions & 5 deletions packages/marimekko/src/BarTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from 'react'
import { BasicTooltip } from '@nivo/tooltip'
import { DimensionDatum } from './types'
import { BarDatum } from './types'

export const BarTooltip = <RawDatum,>({ datum }: { datum: DimensionDatum<RawDatum> }) => (
export const BarTooltip = <RawDatum,>({ bar }: { bar: BarDatum<RawDatum> }) => (
<BasicTooltip
id={`${datum.datum.id} - ${datum.id}`}
value={datum.value}
id={`${bar.datum.id} - ${bar.id}`}
value={bar.value}
enableChip={true}
color={datum.color}
color={bar.color}
/>
)
50 changes: 7 additions & 43 deletions packages/marimekko/src/Bars.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,15 @@
import React, { useMemo } from 'react'
import React from 'react'
import { useTransition, config } from 'react-spring'
// @ts-ignore
import { useTheme } from '@nivo/core'
import { InheritedColorConfig, useInheritedColor } from '@nivo/colors'
import { ComputedDatum, DimensionDatum } from './types'
import { BarDatum } from './types'
import { Bar } from './Bar'

interface BarsProps<RawDatum> {
data: ComputedDatum<RawDatum>[]
borderWidth: number
borderColor: InheritedColorConfig<DimensionDatum<RawDatum>>
bars: BarDatum<RawDatum>[]
}

interface BarData<RawDatum> extends DimensionDatum<RawDatum> {
key: string
borderColor: string
}

export const Bars = <RawDatum,>({ data, borderWidth, borderColor }: BarsProps<RawDatum>) => {
const theme = useTheme()
const getBorderColor = useInheritedColor<DimensionDatum<RawDatum>>(borderColor, theme)

const allBars = useMemo(() => {
const all: BarData<RawDatum>[] = []
data.forEach(datum => {
datum.dimensions.forEach(dimension => {
all.push({
key: `${datum.id}-${dimension.id}`,
...dimension,
borderColor: getBorderColor(dimension),
})
})
})

return all
}, [data, borderWidth, getBorderColor])

export const Bars = <RawDatum,>({ bars }: BarsProps<RawDatum>) => {
const transition = useTransition<
BarData<RawDatum>,
BarDatum<RawDatum>,
{
x: number
y: number
Expand All @@ -47,7 +19,7 @@ export const Bars = <RawDatum,>({ data, borderWidth, borderColor }: BarsProps<Ra
opacity: number
borderColor: string
}
>(allBars, {
>(bars, {
key: bar => bar.key,
initial: bar => ({
x: bar.x,
Expand Down Expand Up @@ -100,15 +72,7 @@ export const Bars = <RawDatum,>({ data, borderWidth, borderColor }: BarsProps<Ra
return (
<>
{transition((style, bar) => {
return (
<Bar<RawDatum>
key={bar.key}
datum={bar}
borderWidth={borderWidth}
borderColor={bar.borderColor}
animatedProps={style}
/>
)
return <Bar<RawDatum> key={bar.key} bar={bar} animatedProps={style} />
})}
</>
)
Expand Down
22 changes: 10 additions & 12 deletions packages/marimekko/src/Marimekko.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Container, SvgWrapper, useDimensions } from '@nivo/core'
import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'
import { SvgProps, LayerId, DimensionDatum } from './types'
import { defaultProps } from './props'
import { useMarimekko } from './hooks'
import { useMarimekko, useLayerContext } from './hooks'
import { Bars } from './Bars'

const InnerMarimekko = <RawDatum,>({
Expand All @@ -29,13 +29,15 @@ const InnerMarimekko = <RawDatum,>({
partialMargin
)

const { computedData } = useMarimekko<RawDatum>({
const { computedData, bars } = useMarimekko<RawDatum>({
data,
id,
value,
colors,
dimensions,
layout,
colors,
borderColor,
borderWidth,
width: innerWidth,
height: innerHeight,
})
Expand All @@ -47,16 +49,12 @@ const InnerMarimekko = <RawDatum,>({
legends: null,
}

layerById.bars = (
<Bars<RawDatum>
key="bars"
data={computedData}
borderWidth={borderWidth}
borderColor={borderColor}
/>
)
layerById.bars = <Bars<RawDatum> key="bars" bars={bars} />

const layerContext: any = {}
const layerContext = useLayerContext<RawDatum>({
data: computedData,
bars,
})

return (
<SvgWrapper
Expand Down
52 changes: 51 additions & 1 deletion packages/marimekko/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { useMemo } from 'react'
import { get } from 'lodash'
import { stack as d3Stack, Stack, stackOffsetDiverging, Series } from 'd3-shape'
import { ScaleLinear, scaleLinear } from 'd3-scale'
// @ts-ignore
import { useTheme } from '@nivo/core'
import { InheritedColorConfig, useInheritedColor, useOrdinalColorScale } from '@nivo/colors'
import {
NormalizedDatum,
ComputedDatum,
Expand All @@ -10,8 +13,9 @@ import {
Layout,
DimensionDatum,
CommonProps,
CustomLayerProps,
BarDatum,
} from './types'
import { useOrdinalColorScale } from '@nivo/colors'

// d3 stack does not support defining `.keys()` using
// a mix of keys and custom value accessors, so we're
Expand Down Expand Up @@ -212,13 +216,40 @@ export const useComputedData = <RawDatum>({
return computedData
}

export const useBars = <RawDatum>(
data: ComputedDatum<RawDatum>[],
borderColor: InheritedColorConfig<DimensionDatum<RawDatum>>,
borderWidth: number
) => {
const theme = useTheme()
const getBorderColor = useInheritedColor<DimensionDatum<RawDatum>>(borderColor, theme)

return useMemo(() => {
const all: BarDatum<RawDatum>[] = []
data.forEach(datum => {
datum.dimensions.forEach(dimension => {
all.push({
key: `${datum.id}-${dimension.id}`,
...dimension,
borderColor: getBorderColor(dimension),
borderWidth,
})
})
})

return all
}, [data, borderWidth, getBorderColor])
}

export const useMarimekko = <RawDatum>({
data,
id,
value,
dimensions: rawDimensions,
layout,
colors,
borderColor,
borderWidth,
width,
height,
}: {
Expand All @@ -228,6 +259,8 @@ export const useMarimekko = <RawDatum>({
dimensions: DataProps<RawDatum>['dimensions']
layout: Layout
colors: CommonProps<RawDatum>['colors']
borderColor: InheritedColorConfig<DimensionDatum<RawDatum>>
borderWidth: number
width: number
height: number
}) => {
Expand All @@ -246,8 +279,25 @@ export const useMarimekko = <RawDatum>({
colors,
layout,
})
const bars = useBars<RawDatum>(computedData, borderColor, borderWidth)

return {
computedData,
bars,
}
}

export const useLayerContext = <RawDatum>({
data,
bars,
}: {
data: ComputedDatum<RawDatum>[]
bars: BarDatum<RawDatum>[]
}): CustomLayerProps<RawDatum> =>
useMemo(
() => ({
data,
bars,
}),
[data, bars]
)
9 changes: 8 additions & 1 deletion packages/marimekko/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,19 @@ export interface ComputedDatum<RawDatum> extends NormalizedDatum<RawDatum> {
dimensions: DimensionDatum<RawDatum>[]
}

export interface BarDatum<RawDatum> extends DimensionDatum<RawDatum> {
key: string
borderColor: string
borderWidth: number
}

export type LabelAccessorFunction<RawDatum> = (datum: ComputedDatum<RawDatum>) => string | number

export type LayerId = 'grid' | 'axes' | 'bars' | 'legends'

export interface CustomLayerProps<RawDatum> {
nodes: ComputedDatum<RawDatum>
data: ComputedDatum<RawDatum>[]
bars: BarDatum<RawDatum>[]
}

export type CustomLayer<RawDatum> = React.FC<CustomLayerProps<RawDatum>>
Expand Down
8 changes: 8 additions & 0 deletions website/src/data/components/marimekko/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,19 @@ const props = [
help: 'Value accessor.',
description: `
Define how to access the value of each datum,
wich is gonna dictate the thickness of the bars,
by default, nivo will look for the \`value\` property.
`,
type: 'string | (datum: RawDatum): number',
required: true,
},
{
key: 'dimensions',
group: 'Base',
help: 'Data dimensions configuration.',
type: '{ id: string, value: string | (datum: RawDatum) => number }',
required: true,
},
{
key: 'valueFormat',
group: 'Base',
Expand Down

0 comments on commit 146a04b

Please sign in to comment.