perfect-postcode/frontend/src/components/map/EnumBarChart.tsx
2026-05-11 21:38:26 +01:00

75 lines
2.7 KiB
TypeScript

import { ts } from '../../i18n/server';
import { getEnumValueColor } from '../../lib/consts';
export default function EnumBarChart({
counts,
globalCounts,
featureName,
}: {
counts: Record<string, number>;
globalCounts?: Record<string, number>;
featureName: string;
}) {
const entries = Object.entries(counts).sort(([, countA], [, countB]) => countB - countA);
const localTotal = entries.reduce((sum, [, c]) => sum + c, 0);
// When global counts are available, normalize both to percentages for comparison
const globalTotal = globalCounts ? Object.values(globalCounts).reduce((sum, c) => sum + c, 0) : 0;
const hasGlobal = globalCounts && globalTotal > 0;
// Compute max percentage across both datasets for consistent bar scaling
const maxPct = entries.reduce((max, [label, count]) => {
const localPct = localTotal > 0 ? count / localTotal : 0;
const globalPct = hasGlobal ? (globalCounts[label] ?? 0) / globalTotal : 0;
return Math.max(max, localPct, globalPct);
}, 0);
// Fallback to raw count scaling when no global data
const maxCount = Math.max(...entries.map(([, count]) => count), 1);
return (
<div className="space-y-1 mt-1">
{entries.map(([label, count]) => {
const localPct = localTotal > 0 ? count / localTotal : 0;
const globalPct = hasGlobal ? (globalCounts[label] ?? 0) / globalTotal : 0;
const localWidth = hasGlobal
? maxPct > 0
? (localPct / maxPct) * 100
: 0
: (count / maxCount) * 100;
const globalWidth = hasGlobal && maxPct > 0 ? (globalPct / maxPct) * 100 : 0;
const color = getEnumValueColor(featureName, label);
const barStyle = `rgb(${color[0]},${color[1]},${color[2]})`;
return (
<div key={label} className="flex items-center gap-2 text-xs">
<span className="w-16 truncate text-warm-500 dark:text-warm-400 text-right shrink-0">
{ts(label)}
</span>
<div className="flex-1 h-3 bg-warm-100 dark:bg-navy-700 rounded overflow-hidden relative">
{hasGlobal && (
<div
className="absolute inset-y-0 left-0 bg-warm-300/60 dark:bg-warm-600/60 rounded"
style={{ width: `${globalWidth}%` }}
/>
)}
<div
className="h-full rounded relative"
style={{
width: `${localWidth}%`,
backgroundColor: barStyle,
}}
/>
</div>
<span className="w-8 text-warm-500 dark:text-warm-400 text-right shrink-0">
{count}
</span>
</div>
);
})}
</div>
);
}