diff --git a/packages/bump/src/area-bump/Area.tsx b/packages/bump/src/area-bump/Area.tsx index 9d5833400c..7b1c4d685a 100644 --- a/packages/bump/src/area-bump/Area.tsx +++ b/packages/bump/src/area-bump/Area.tsx @@ -64,6 +64,7 @@ export const Area = {startLabel !== false && ( - label={startLabel} + getLabel={startLabel} series={series} position="start" padding={startLabelPadding} @@ -191,7 +191,7 @@ const InnerAreaBump = - label={endLabel} + getLabel={endLabel} series={series} position="end" padding={endLabelPadding} diff --git a/packages/bump/src/area-bump/AreasLabels.tsx b/packages/bump/src/area-bump/AreasLabels.tsx index d10d58a8da..dbc1041fab 100644 --- a/packages/bump/src/area-bump/AreasLabels.tsx +++ b/packages/bump/src/area-bump/AreasLabels.tsx @@ -10,7 +10,7 @@ import { import { useAreaBumpSeriesLabels } from './hooks' interface AreaLabelsProps { - label: Exclude, false> + getLabel: Exclude, false> series: AreaBumpComputedSerie[] position: 'start' | 'end' padding: number @@ -21,7 +21,7 @@ export const AreasLabels = < Datum extends AreaBumpDatum, ExtraProps extends AreaBumpSerieExtraProps >({ - label, + getLabel, series, position, padding, @@ -31,7 +31,7 @@ export const AreasLabels = < const { animate, config: springConfig } = useMotionConfig() const labels = useAreaBumpSeriesLabels({ - label, + getLabel, series, position, padding, @@ -60,6 +60,7 @@ export const AreasLabels = < return ( ({ - label, series, position, padding, color, + getLabel, }: { - label: Exclude, false> series: AreaBumpComputedSerie[] position: 'start' | 'end' padding: number color: InheritedColorConfig> + getLabel: Exclude, false> }): AreaBumpLabelData[] => { const theme = useTheme() const getColor = useInheritedColor(color, theme) - const getLabel = usePropertyAccessor(label) - return useMemo(() => { let textAnchor: 'start' | 'end' let signedPadding: number @@ -350,12 +348,17 @@ export const useAreaBumpSeriesLabels = < } return series.map(serie => { + let label = serie.id + if (typeof getLabel === 'function') { + label = getLabel(serie.data) + } + const point = position === 'start' ? serie.points[0] : serie.points[serie.points.length - 1] return { id: serie.id, - label: getLabel(serie.data), + label, x: point.x + signedPadding, y: point.y, color: getColor(serie), diff --git a/packages/bump/src/area-bump/types.ts b/packages/bump/src/area-bump/types.ts index d8c3bf9a33..c17cbda871 100644 --- a/packages/bump/src/area-bump/types.ts +++ b/packages/bump/src/area-bump/types.ts @@ -1,7 +1,6 @@ import { FunctionComponent, MouseEvent } from 'react' import { Area } from 'd3-shape' import { - PropertyAccessor, Box, Theme, Dimensions, @@ -78,7 +77,7 @@ export type AreaBumpInterpolation = 'smooth' | 'linear' export type AreaBumpLabel< Datum extends AreaBumpDatum, ExtraProps extends AreaBumpSerieExtraProps -> = PropertyAccessor, string> | false +> = ((serie: AreaBumpSerie) => string) | boolean export interface AreaBumpLabelData< Datum extends AreaBumpDatum, ExtraProps extends AreaBumpSerieExtraProps diff --git a/packages/bump/src/bump/LinesLabels.tsx b/packages/bump/src/bump/LinesLabels.tsx index ad78c4f019..7d0c680646 100644 --- a/packages/bump/src/bump/LinesLabels.tsx +++ b/packages/bump/src/bump/LinesLabels.tsx @@ -6,7 +6,7 @@ import { useBumpSeriesLabels } from './hooks' interface LineLabelsProps { series: BumpComputedSerie[] - getLabel: BumpLabel + getLabel: Exclude, false> position: 'start' | 'end' padding: number color: InheritedColorConfig> diff --git a/packages/bump/src/bump/hooks.ts b/packages/bump/src/bump/hooks.ts index de2f5a563b..82825696f1 100644 --- a/packages/bump/src/bump/hooks.ts +++ b/packages/bump/src/bump/hooks.ts @@ -384,7 +384,7 @@ export const useBumpSeriesLabels = < position: 'start' | 'end' padding: number color: InheritedColorConfig> - getLabel: BumpLabel + getLabel: Exclude, false> }) => { const theme = useTheme() const getColor = useInheritedColor(color, theme) diff --git a/packages/bump/tests/AreaBump.test.tsx b/packages/bump/tests/AreaBump.test.tsx new file mode 100644 index 0000000000..234c61b72a --- /dev/null +++ b/packages/bump/tests/AreaBump.test.tsx @@ -0,0 +1,190 @@ +import { mount } from 'enzyme' +// @ts-ignore +import { AreaBump, AreaBumpSvgProps } from '../src' + +interface Datum { + x: number + y: number +} + +const sampleData: AreaBumpSvgProps>['data'] = [ + { + id: 'A', + data: [ + { + x: 2000, + y: 9, + }, + { + x: 2001, + y: 9, + }, + { + x: 2002, + y: 2, + }, + { + x: 2003, + y: 4, + }, + ], + }, + { + id: 'B', + data: [ + { + x: 2000, + y: 8, + }, + { + x: 2001, + y: 3, + }, + { + x: 2002, + y: 1, + }, + { + x: 2003, + y: 7, + }, + ], + }, + { + id: 'C', + data: [ + { + x: 2000, + y: 12, + }, + { + x: 2001, + y: 4, + }, + { + x: 2002, + y: 5, + }, + { + x: 2003, + y: 6, + }, + ], + }, +] + +const baseProps: AreaBumpSvgProps> = { + width: 800, + height: 600, + data: sampleData, + animate: false, +} + +it('should render a basic area bump chart', () => { + const wrapper = mount( {...baseProps} />) + + const areaA = wrapper.find(`path[data-testid='area.A']`) + expect(areaA.exists()).toBeTruthy() + + const areaB = wrapper.find(`path[data-testid='area.B']`) + expect(areaB.exists()).toBeTruthy() + + const areaC = wrapper.find(`path[data-testid='area.C']`) + expect(areaC.exists()).toBeTruthy() +}) + +describe('style', () => { + it('custom colors array', () => { + const colors = ['rgba(255, 0, 0, 1)', 'rgba(0, 255, 0, 1)', 'rgba(0, 0, 255, 1)'] + const wrapper = mount( {...baseProps} colors={colors} />) + + expect(wrapper.find(`path[data-testid='area.A']`).prop('fill')).toEqual(colors[0]) + expect(wrapper.find(`path[data-testid='area.B']`).prop('fill')).toEqual(colors[1]) + expect(wrapper.find(`path[data-testid='area.C']`).prop('fill')).toEqual(colors[2]) + }) + + it('colors from data', () => { + const colors = ['rgba(255, 0, 0, 1)', 'rgba(0, 255, 0, 1)', 'rgba(0, 0, 255, 1)'] + const wrapper = mount( + + {...baseProps} + data={sampleData.map((serie, i) => ({ + ...serie, + color: colors[i], + }))} + colors={serie => serie.color} + /> + ) + + expect(wrapper.find(`path[data-testid='area.A']`).prop('fill')).toEqual(colors[0]) + expect(wrapper.find(`path[data-testid='area.B']`).prop('fill')).toEqual(colors[1]) + expect(wrapper.find(`path[data-testid='area.C']`).prop('fill')).toEqual(colors[2]) + }) +}) + +describe('labels', () => { + it('default end labels', () => { + const wrapper = mount( {...baseProps} />) + + const endLabelA = wrapper.find(`text[data-testid='label.end.A']`) + expect(endLabelA.exists()).toBeTruthy() + expect(endLabelA.text()).toEqual('A') + expect(endLabelA.prop('textAnchor')).toEqual('start') + + const endLabelB = wrapper.find(`text[data-testid='label.end.B']`) + expect(endLabelB.exists()).toBeTruthy() + expect(endLabelB.text()).toEqual('B') + expect(endLabelB.prop('textAnchor')).toEqual('start') + + const endLabelC = wrapper.find(`text[data-testid='label.end.C']`) + expect(endLabelC.exists()).toBeTruthy() + expect(endLabelC.text()).toEqual('C') + expect(endLabelC.prop('textAnchor')).toEqual('start') + }) + + it('customize end labels', () => { + const wrapper = mount( + {...baseProps} endLabel={serie => `Serie ${serie.id}`} /> + ) + + expect(wrapper.find(`text[data-testid='label.end.A']`).text()).toEqual('Serie A') + expect(wrapper.find(`text[data-testid='label.end.B']`).text()).toEqual('Serie B') + expect(wrapper.find(`text[data-testid='label.end.C']`).text()).toEqual('Serie C') + }) + + it('label from data', () => { + const wrapper = mount( + + {...baseProps} + data={sampleData.map(serie => ({ + ...serie, + label: `Serie ${serie.id} label`, + }))} + endLabel={serie => serie.label} + /> + ) + + expect(wrapper.find(`text[data-testid='label.end.A']`).text()).toEqual('Serie A label') + expect(wrapper.find(`text[data-testid='label.end.B']`).text()).toEqual('Serie B label') + expect(wrapper.find(`text[data-testid='label.end.C']`).text()).toEqual('Serie C label') + }) + + it('start labels', () => { + const wrapper = mount( {...baseProps} startLabel />) + + const startLabelA = wrapper.find(`text[data-testid='label.start.A']`) + expect(startLabelA.exists()).toBeTruthy() + expect(startLabelA.text()).toEqual('A') + expect(startLabelA.prop('textAnchor')).toEqual('end') + + const startLabelB = wrapper.find(`text[data-testid='label.start.B']`) + expect(startLabelB.exists()).toBeTruthy() + expect(startLabelB.text()).toEqual('B') + expect(startLabelB.prop('textAnchor')).toEqual('end') + + const startLabelC = wrapper.find(`text[data-testid='label.start.C']`) + expect(startLabelC.exists()).toBeTruthy() + expect(startLabelC.text()).toEqual('C') + expect(startLabelC.prop('textAnchor')).toEqual('end') + }) +})