Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 43 additions & 8 deletions packages/propel/src/charts/bar-chart/root.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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(<K extends string, T extends string>(props: TBarChartProps<K, T>) => {
const {
data,
Expand All @@ -44,29 +46,62 @@ export const BarChart = React.memo(<K extends string, T extends string>(props: T
const [activeLegend, setActiveLegend] = useState<string | null>(null);

// derived values
const { stackKeys, stackLabels, stackDotColors } = useMemo(() => {
const { stackKeys, stackLabels } = useMemo(() => {
const keys: string[] = [];
const labels: Record<string, string> = {};
const colors: Record<string, string> = {};

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<string, string>[], 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<string, string> = {};
for (const bar of bars) {
colors[bar.key] = getBarColor(payload, bar.key);
}
return colors;
},
[bars, getBarColor]
);

const renderBars = useMemo(
() =>
bars.map((bar) => (
<Bar
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"];
Expand Down Expand Up @@ -158,7 +193,7 @@ export const BarChart = React.memo(<K extends string, T extends string>(props: T
activeKey={activeBar}
itemKeys={stackKeys}
itemLabels={stackLabels}
itemDotColors={stackDotColors}
itemDotColors={getAllBarColors(payload || [])}
/>
);
}}
Expand Down
Loading