This commit is contained in:
Andras Schmelczer 2026-05-09 09:26:40 +01:00
parent 701c17a703
commit f114ada255
44 changed files with 5264 additions and 1674 deletions

View file

@ -34,6 +34,7 @@ export function DualHistogram({
p1,
p99,
globalMean,
meanLabel = 'National avg',
formatLabel,
}: {
localCounts: number[];
@ -41,6 +42,7 @@ export function DualHistogram({
p1: number;
p99: number;
globalMean?: number;
meanLabel?: string;
formatLabel?: (value: number) => string;
}) {
const targetBars = 25;
@ -84,34 +86,51 @@ export function DualHistogram({
const meanFrac = globalMean != null && p99 > p1 ? (globalMean - p1) / (p99 - p1) : null;
// Account for outlier bins: middle region spans bars 1..n-2
const meanPct = meanFrac != null ? ((1 + meanFrac * middleBins) / barCount) * 100 : null;
const showMeanMarker = meanPct != null && meanPct >= 0 && meanPct <= 100;
const meanLabelStyle =
showMeanMarker && meanPct < 12
? { left: 0 }
: showMeanMarker && meanPct > 88
? { right: 0 }
: { left: '50%', transform: 'translateX(-50%)' };
return (
<div className="mt-1">
<div className="relative flex items-end gap-px h-10">
{Array.from({ length: barCount }).map((_, index) => {
const globalHeight = (globalBars[index] / globalMax) * 100;
const localHeight = (localBars[index] / localMax) * 100;
return (
<div key={index} className="flex-1 relative min-w-[2px] h-full flex items-end">
<div
className="absolute bottom-0 left-0 right-0 bg-warm-300/40 dark:bg-warm-600/40 rounded-t-sm"
style={{ height: `${globalHeight}%` }}
/>
<div
className="absolute bottom-0 left-0 right-0 bg-teal-500 dark:bg-teal-400 rounded-t-sm"
style={{
height: `${localHeight}%`,
opacity: localBars[index] > 0 ? 1 : 0.1,
}}
/>
</div>
);
})}
{meanPct != null && meanPct >= 0 && meanPct <= 100 && (
<div className={showMeanMarker ? 'relative pt-5' : 'relative'}>
<div className="relative flex items-end gap-px h-10">
{Array.from({ length: barCount }).map((_, index) => {
const globalHeight = (globalBars[index] / globalMax) * 100;
const localHeight = (localBars[index] / localMax) * 100;
return (
<div key={index} className="flex-1 relative min-w-[2px] h-full flex items-end">
<div
className="absolute bottom-0 left-0 right-0 bg-warm-300/40 dark:bg-warm-600/40 rounded-t-sm"
style={{ height: `${globalHeight}%` }}
/>
<div
className="absolute bottom-0 left-0 right-0 bg-teal-500 dark:bg-teal-400 rounded-t-sm"
style={{
height: `${localHeight}%`,
opacity: localBars[index] > 0 ? 1 : 0.1,
}}
/>
</div>
);
})}
</div>
{showMeanMarker && (
<div
className="absolute bottom-0 top-0 w-px border-l border-dashed border-warm-400 dark:border-warm-500"
className="pointer-events-none absolute inset-y-0"
style={{ left: `${meanPct}%` }}
/>
>
<div
className="absolute top-0 max-w-[7rem] truncate rounded-sm border border-warm-300 bg-white px-1 py-0.5 text-[9px] font-medium leading-none text-warm-600 shadow-sm dark:border-warm-600 dark:bg-navy-900 dark:text-warm-300"
style={meanLabelStyle}
>
{meanLabel}
</div>
<div className="absolute bottom-0 top-5 w-px border-l border-dashed border-warm-400 dark:border-warm-500" />
</div>
)}
</div>
{tickBars.size > 0 && (