diff --git a/packages/propel/src/charts/bar-chart/root.tsx b/packages/propel/src/charts/bar-chart/root.tsx index 0d34b27836e..23a21143219 100644 --- a/packages/propel/src/charts/bar-chart/root.tsx +++ b/packages/propel/src/charts/bar-chart/root.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ "use client"; -import React, { useMemo, useState } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import { BarChart as CoreBarChart, Bar, @@ -21,6 +21,8 @@ import { CustomXAxisTick, CustomYAxisTick } from "../components/tick"; import { CustomTooltip } from "../components/tooltip"; import { barShapeVariants } from "./bar"; +const DEFAULT_BAR_FILL_COLOR = "#000000"; + export const BarChart = React.memo((props: TBarChartProps) => { const { data, @@ -44,21 +46,55 @@ export const BarChart = React.memo((props: T const [activeLegend, setActiveLegend] = useState(null); // derived values - const { stackKeys, stackLabels, stackDotColors } = useMemo(() => { + const { stackKeys, stackLabels } = useMemo(() => { const keys: string[] = []; const labels: Record = {}; - const colors: Record = {}; for (const bar of bars) { keys.push(bar.key); labels[bar.key] = bar.label; - // For tooltip, we need a string color. If fill is a function, use a default color - colors[bar.key] = typeof bar.fill === "function" ? bar.fill({}) : bar.fill; } - return { stackKeys: keys, stackLabels: labels, stackDotColors: colors }; + return { stackKeys: keys, stackLabels: labels }; }, [bars]); + // get bar color dynamically based on payload + const getBarColor = useCallback( + (payload: Record[], barKey: string) => { + const bar = bars.find((b) => b.key === barKey); + if (!bar) return DEFAULT_BAR_FILL_COLOR; + + if (typeof bar.fill === "function") { + const payloadItem = payload?.find((item) => item.dataKey === barKey); + if (payloadItem?.payload) { + try { + return bar.fill(payloadItem.payload); + } catch (error) { + console.error(error); + return DEFAULT_BAR_FILL_COLOR; + } + } else { + return DEFAULT_BAR_FILL_COLOR; // fallback color when no payload data + } + } else { + return bar.fill; + } + }, + [bars] + ); + + // get all bar colors + const getAllBarColors = useCallback( + (payload: any[]) => { + const colors: Record = {}; + for (const bar of bars) { + colors[bar.key] = getBarColor(payload, bar.key); + } + return colors; + }, + [bars, getBarColor] + ); + const renderBars = useMemo( () => bars.map((bar) => ( @@ -66,7 +102,6 @@ export const BarChart = React.memo((props: T key={bar.key} dataKey={bar.key} stackId={bar.stackId} - fill={typeof bar.fill === "function" ? bar.fill({}) : bar.fill} opacity={!!activeLegend && activeLegend !== bar.key ? 0.1 : 1} shape={(shapeProps: any) => { const shapeVariant = barShapeVariants[bar.shapeVariant ?? "bar"]; @@ -158,7 +193,7 @@ export const BarChart = React.memo((props: T activeKey={activeBar} itemKeys={stackKeys} itemLabels={stackLabels} - itemDotColors={stackDotColors} + itemDotColors={getAllBarColors(payload || [])} /> ); }}