import { createContext, useCallback, useContext, useMemo } from 'react';
import {
Bar,
BarChart,
type BarProps,
CartesianGrid,
Cell,
Label,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts';
import {
TOOLTIP_STYLE,
COUNT_STYLE,
LABEL_STYLE,
MAX_TICK_LABEL_CHARS,
TITLE_STYLE,
TICKS_SHOW_ALL_LABELS_BELOW,
UNITS_LABEL_OFFSET,
TICK_MARGIN,
COUNT_KEY,
} from '../../constants/chartConstants';
import {
BarCountFillMode,
BaseBarChartProps,
CategoricalChartDataItem,
CustomBarLabelProps,
TooltipPayload,
} from '../../types/chartTypes';
import { useChartTranslation } from '../../ChartConfigProvider';
import NoData from '../NoData';
import { useTransformedChartData } from '../../util/chartUtils';
import ChartWrapper from './ChartWrapper';
const tickFormatter = (tickLabel: string) => {
if (tickLabel.length <= MAX_TICK_LABEL_CHARS) {
return tickLabel;
}
return `${tickLabel.substring(0, MAX_TICK_LABEL_CHARS)}...`;
};
const BAR_CHART_MARGINS = { bottom: 100, right: 0 };
const BAR_CHART_MARGIN_TOP_COUNTS = 35;
const BAR_CHART_MARGIN_TOP_NO_COUNTS = 10;
const MIN_BAR_WIDTH_FOR_COUNTS = 11;
const BAR_LABEL_SPACING = 4; // Spacing of a BarLabel above the actual bar, in pixels.
const BAR_LABEL_APPROX_NUMBER_WIDTH = 9.2;
const BaseBarChart = ({
height,
width,
units,
title,
onClick,
onChartClick,
chartFill,
otherFill,
showBarCounts,
barCountFillMode,
...params
}: BaseBarChartProps) => {
showBarCounts = showBarCounts ?? true; // Show bar counts by default
const t = useChartTranslation();
const margins = useMemo(
() => ({
...BAR_CHART_MARGINS,
// Top margin needs to accommodate bar count labels:
top: showBarCounts ? BAR_CHART_MARGIN_TOP_COUNTS : BAR_CHART_MARGIN_TOP_NO_COUNTS,
}),
[showBarCounts]
);
const fill = (entry: CategoricalChartDataItem, index: number) =>
entry.x === 'missing' ? otherFill : chartFill[index % chartFill.length];
const data = useTransformedChartData(params, true);
const totalCount = data.reduce((sum, e) => sum + e.y, 0);
const onHover: BarProps['onMouseEnter'] = useCallback(
(_data, _index, e) => {
const { target } = e;
if (onClick && target) (target as SVGElement).style.cursor = 'pointer';
},
[onClick]
);
if (data.length === 0) {
return
{name}
{value} ({percentage}%)