"use client"; import { motion } from "motion/react"; import { memo, useEffect, useMemo, useState } from "react"; import { createPortal } from "react-dom"; import { cn } from "@/lib/utils"; import { useChart, useChartStable } from "./chart-context"; export interface BarYAxisProps { /** Whether to show all labels or skip some for dense data. Default: true */ showAllLabels?: boolean; /** Maximum number of labels to show. Default: 20 */ maxLabels?: number; } interface BarYAxisLabelProps { label: string; y: number; bandHeight: number; isHovered: boolean; } function BarYAxisLabel({ label, y, bandHeight, isHovered, }: BarYAxisLabelProps) { return (
{label}
); } export function BarYAxis(props: BarYAxisProps) { const { containerRef, barScale } = useChartStable(); const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); const container = containerRef.current; if (!(mounted && container)) { return null; } if (!barScale) { return null; } return ; } const BarYAxisInner = memo(function BarYAxisInner({ showAllLabels = true, maxLabels = 20, container, }: BarYAxisProps & { container: HTMLDivElement }) { const { margin, barScale, bandWidth, barXAccessor, data, hoveredBarIndex } = useChart(); // Generate labels for each bar const labelsToShow = useMemo(() => { if (!(barScale && bandWidth && barXAccessor)) { return []; } const allLabels = data.map((d, i) => { const label = barXAccessor(d); const bandY = barScale(label) ?? 0; // Center the label vertically within the band const y = bandY + margin.top; return { label, y, bandHeight: bandWidth, index: i }; }); // If showAllLabels is true or we have fewer than maxLabels, show all if (showAllLabels || allLabels.length <= maxLabels) { return allLabels; } // Otherwise, skip some labels to avoid crowding const step = Math.ceil(allLabels.length / maxLabels); return allLabels.filter((_, i) => i % step === 0); }, [ barScale, bandWidth, barXAccessor, data, margin.top, showAllLabels, maxLabels, ]); return createPortal(
{labelsToShow.map((item) => ( ))}
, container ); }); BarYAxis.displayName = "BarYAxis"; export default BarYAxis;