import React, { useMemo } from 'react'; import { BarStack } from '@vx/shape'; import { scaleOrdinal, scaleLinear, scaleBand } from '@vx/scale'; import { Group } from '@vx/group'; import { AxisBottom, AxisRight } from '@vx/axis'; import { BarChart as BarChartType } from '../../../types.generated'; import { lineColors } from './lineColors'; import Legend from './Legend'; type Props = { chartData: BarChartType; width: number; height: number; }; const MARGIN_SIZE = 32; function transformName(label: string) { if (label === 'DATA_JOB') { return 'TASK'; } if (label === 'DATA_FLOW') { return 'PIPELINE'; } return label; } function transformChartData(chartData: BarChartType) { return chartData.bars.map((bar, i) => ({ index: i, name: transformName(bar.name), ...bar.segments.reduce( (obj, segment) => ({ ...obj, [segment.label]: segment.value, }), {}, ), })); } export const BarChart = ({ chartData, width, height }: Props) => { const keys = useMemo( () => chartData.bars .flatMap((bar) => bar.segments.map((segment) => segment.label)) .filter((x, i, a) => a.indexOf(x) === i), [chartData], ); const totals = useMemo( () => chartData.bars.map((bar) => bar.segments.reduce((total, segment) => total + segment.value, 0)), [chartData], ); const segmentScale = scaleOrdinal({ domain: keys, range: lineColors.slice(0, keys.length), }); const transformedChartData = useMemo(() => transformChartData(chartData), [chartData]); const yAxisScale = scaleLinear({ domain: [0, Math.max(...totals) * 1.1], }); const xAxisScale = scaleBand({ domain: transformedChartData.map((bar) => bar.name), padding: 0.2, }); const xMax = width - MARGIN_SIZE; const yMax = height - MARGIN_SIZE - 80; xAxisScale.rangeRound([0, xMax]); yAxisScale.range([yMax, 0]); return ( <> data={transformedChartData} keys={keys} x={(data) => data.name} xScale={xAxisScale} yScale={yAxisScale} color={segmentScale} > {(barStacks) => { return barStacks.map((barStack) => barStack.bars .filter((bar) => !Number.isNaN(bar.bar[1])) .map((bar) => ( {bar.bar[1] - bar.bar[0]} )), ); }} ({ fontSize: 11, textAnchor: 'start', angle: 40, })} /> ({ fontSize: 10, dx: '3px', dy: '1px', textAnchor: 'start', })} /> ); };