Growth charts: restore full 9-percentile Epic/CDC line set

Reverted from the 7-line reduced set back to the full clinical set:
3rd, 5th, 10th, 25th, 50th, 75th, 90th, 95th, 97th — matching what
Epic and the printed AAP/CDC/WHO charts display.

Kept the mobile-readability improvements from the prior pass:
  - Each percentile is a distinct hue (red / deep-orange / orange /
    amber / green / blue / violet / purple / pink)
  - Outer 3rd + 97th are dashed (abnormal-threshold convention); 5th
    and 95th use a tighter dash; rest solid
  - 50th remains bold green to anchor the center
  - Label plugin's white halo + vertical nudge keeps 3/5/10 and
    90/95/97 label stacks legible
  - Patient dot still on top, white-ringed

Fill bands updated for 9 indexes (3↔97, 5↔95, 10↔90, 25↔75).
This commit is contained in:
Daniel 2026-04-14 07:02:46 +02:00
parent 2cb99b263f
commit 1a176f082a

View file

@ -758,18 +758,20 @@
return M * Math.pow(1 + L * S * z, 1 / L);
}
// Seven reference lines — classic WHO/CDC set minus the near-duplicate
// 5th/95th, which crowd the 3rd/10th and 90th/97th labels on mobile.
// Each percentile gets a distinct solid color; dashed only for the
// outermost bands (3rd / 97th) so they read as "abnormal thresholds".
// Full Epic / CDC / WHO reference set: 3, 5, 10, 25, 50, 75, 90, 95, 97.
// Each percentile has its own hue so clinicians can match the patient
// dot to a band at a glance. Outer pairs (3/97) dashed — they're the
// abnormal-threshold lines on AAP-published charts.
var PERCENTILE_LINES = [
{ p: 3, z: -1.88079, color: 'rgba(220,38,38,0.85)', dash: [5,4], width: 1.4 }, // red
{ p: 10, z: -1.28155, color: 'rgba(234,88,12,0.85)', dash: [], width: 1.2 }, // orange
{ p: 25, z: -0.67449, color: 'rgba(202,138,4,0.85)', dash: [], width: 1.1 }, // amber
{ p: 3, z: -1.88079, color: 'rgba(220,38,38,0.85)', dash: [6,4], width: 1.4 }, // red
{ p: 5, z: -1.64485, color: 'rgba(234,88,12,0.8)', dash: [3,3], width: 1.1 }, // deep orange
{ p: 10, z: -1.28155, color: 'rgba(245,158,11,0.85)', dash: [], width: 1.1 }, // orange
{ p: 25, z: -0.67449, color: 'rgba(202,138,4,0.8)', dash: [], width: 1.0 }, // amber
{ p: 50, z: 0, color: 'rgba(22,163,74,0.95)', dash: [], width: 2.4 }, // green (center)
{ p: 75, z: 0.67449, color: 'rgba(37,99,235,0.85)', dash: [], width: 1.1 }, // blue
{ p: 90, z: 1.28155, color: 'rgba(124,58,237,0.85)', dash: [], width: 1.2 }, // violet
{ p: 97, z: 1.88079, color: 'rgba(219,39,119,0.9)', dash: [5,4], width: 1.4 } // pink
{ p: 75, z: 0.67449, color: 'rgba(37,99,235,0.8)', dash: [], width: 1.0 }, // blue
{ p: 90, z: 1.28155, color: 'rgba(124,58,237,0.85)', dash: [], width: 1.1 }, // violet
{ p: 95, z: 1.64485, color: 'rgba(168,85,247,0.8)', dash: [3,3], width: 1.1 }, // purple
{ p: 97, z: 1.88079, color: 'rgba(219,39,119,0.9)', dash: [6,4], width: 1.4 } // pink
];
function generatePercentileCurves(lmsTable, percentileLines) {
@ -795,12 +797,13 @@
order: 10
});
});
// Fill bands between symmetric percentile pairs. Indexes match the
// 7-line PERCENTILE_LINES array above: 3=0, 10=1, 25=2, 50=3, 75=4, 90=5, 97=6
// Fill bands between symmetric percentile pairs.
// Indexes: 3=0, 5=1, 10=2, 25=3, 50=4, 75=5, 90=6, 95=7, 97=8
var fills = [
{ outer: 0, inner: 6, color: 'rgba(220,38,38,0.05)' }, // 3rd-97th band (widest)
{ outer: 1, inner: 5, color: 'rgba(234,88,12,0.05)' }, // 10th-90th band
{ outer: 2, inner: 4, color: 'rgba(163,163,163,0.05)' } // 25th-75th band (IQR)
{ outer: 0, inner: 8, color: 'rgba(220,38,38,0.04)' }, // 3rd-97th (widest)
{ outer: 1, inner: 7, color: 'rgba(234,88,12,0.04)' }, // 5th-95th
{ outer: 2, inner: 6, color: 'rgba(245,158,11,0.04)' }, // 10th-90th
{ outer: 3, inner: 5, color: 'rgba(163,163,163,0.05)' } // 25th-75th (IQR)
];
fills.forEach(function(f) {
if (datasets[f.outer] && datasets[f.inner]) {