aboutsummaryrefslogtreecommitdiff
path: root/src/components/charts/BarChart.tsx
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-01-24 13:09:50 +0000
committerFuwn <[email protected]>2026-01-24 13:09:50 +0000
commit396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b (patch)
treeb9df4ca6a70db45cfffbae6fdd7252e20fb8e93c /src/components/charts/BarChart.tsx
downloadumami-main.tar.xz
umami-main.zip
Initial commitHEADmain
Created from https://vercel.com/new
Diffstat (limited to 'src/components/charts/BarChart.tsx')
-rw-r--r--src/components/charts/BarChart.tsx131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/components/charts/BarChart.tsx b/src/components/charts/BarChart.tsx
new file mode 100644
index 0000000..7bfc72d
--- /dev/null
+++ b/src/components/charts/BarChart.tsx
@@ -0,0 +1,131 @@
+import { useTheme } from '@umami/react-zen';
+import { useMemo, useState } from 'react';
+import { Chart, type ChartProps } from '@/components/charts/Chart';
+import { ChartTooltip } from '@/components/charts/ChartTooltip';
+import { useLocale } from '@/components/hooks';
+import { renderNumberLabels } from '@/lib/charts';
+import { getThemeColors } from '@/lib/colors';
+import { DATE_FORMATS, formatDate } from '@/lib/date';
+import { formatLongCurrency, formatLongNumber } from '@/lib/format';
+
+const dateFormats = {
+ millisecond: 'T',
+ second: 'pp',
+ minute: 'p',
+ hour: 'p - PP',
+ day: 'PPPP',
+ week: 'PPPP',
+ month: 'LLLL yyyy',
+ quarter: 'qqq',
+ year: 'yyyy',
+};
+
+export interface BarChartProps extends ChartProps {
+ unit?: string;
+ stacked?: boolean;
+ currency?: string;
+ renderXLabel?: (label: string, index: number, values: any[]) => string;
+ renderYLabel?: (label: string, index: number, values: any[]) => string;
+ XAxisType?: string;
+ YAxisType?: string;
+ minDate?: Date;
+ maxDate?: Date;
+}
+
+export function BarChart({
+ chartData,
+ renderXLabel,
+ renderYLabel,
+ unit,
+ XAxisType = 'timeseries',
+ YAxisType = 'linear',
+ stacked = false,
+ minDate,
+ maxDate,
+ currency,
+ ...props
+}: BarChartProps) {
+ const [tooltip, setTooltip] = useState(null);
+ const { theme } = useTheme();
+ const { locale } = useLocale();
+ const { colors } = useMemo(() => getThemeColors(theme), [theme]);
+
+ const chartOptions: any = useMemo(() => {
+ return {
+ __id: Date.now(),
+ scales: {
+ x: {
+ type: XAxisType,
+ stacked: true,
+ min: formatDate(minDate, DATE_FORMATS[unit], locale),
+ max: formatDate(maxDate, DATE_FORMATS[unit], locale),
+ offset: true,
+ time: {
+ unit,
+ },
+ grid: {
+ display: false,
+ },
+ border: {
+ color: colors.chart.line,
+ },
+ ticks: {
+ color: colors.chart.text,
+ autoSkip: false,
+ maxRotation: 0,
+ callback: renderXLabel,
+ },
+ },
+ y: {
+ type: YAxisType,
+ min: 0,
+ beginAtZero: true,
+ stacked: !!stacked,
+ grid: {
+ color: colors.chart.line,
+ },
+ border: {
+ color: colors.chart.line,
+ },
+ ticks: {
+ color: colors.chart.text,
+ callback: renderYLabel || renderNumberLabels,
+ },
+ },
+ },
+ };
+ }, [chartData, colors, unit, stacked, renderXLabel, renderYLabel]);
+
+ const handleTooltip = ({ tooltip }: { tooltip: any }) => {
+ const { opacity, labelColors, dataPoints } = tooltip;
+
+ setTooltip(
+ opacity
+ ? {
+ title: formatDate(
+ new Date(dataPoints[0].raw?.d || dataPoints[0].raw?.x || dataPoints[0].raw),
+ dateFormats[unit],
+ locale,
+ ),
+ color: labelColors?.[0]?.backgroundColor,
+ value: currency
+ ? formatLongCurrency(dataPoints[0].raw.y, currency)
+ : `${formatLongNumber(dataPoints[0].raw.y)} ${dataPoints[0].dataset.label}`,
+ }
+ : null,
+ );
+ };
+
+ return (
+ <>
+ <Chart
+ {...props}
+ type="bar"
+ chartData={chartData}
+ chartOptions={chartOptions}
+ onTooltip={handleTooltip}
+ />
+ {tooltip && <ChartTooltip {...tooltip} />}
+ </>
+ );
+}