Growth charts: label each percentile curve (3rd, 50th, 97th, …)
Adds a Chart.js plugin that draws the percentile label at the right end of each reference line, matching the convention on printed WHO/CDC growth charts. Lets clinicians identify lines at a glance without using the legend. Canvas gets 30px right-padding so the labels don't get clipped.
This commit is contained in:
parent
e32e9977f5
commit
de0562060b
1 changed files with 33 additions and 0 deletions
|
|
@ -811,6 +811,34 @@
|
||||||
|
|
||||||
var _chartInstances = {};
|
var _chartInstances = {};
|
||||||
|
|
||||||
|
// Chart.js plugin — draws the percentile label (e.g. "50th") at the
|
||||||
|
// right end of each percentile curve so the lines are identifiable
|
||||||
|
// without a legend. Standard on printed WHO/CDC growth charts.
|
||||||
|
var percentileLabelPlugin = {
|
||||||
|
id: 'percentileLabels',
|
||||||
|
afterDatasetsDraw: function(chart) {
|
||||||
|
var ctx = chart.ctx;
|
||||||
|
chart.data.datasets.forEach(function(ds, i) {
|
||||||
|
// Only the percentile line datasets (labels look like "50th")
|
||||||
|
if (!ds.label || !/^\d+th$/.test(ds.label)) return;
|
||||||
|
var meta = chart.getDatasetMeta(i);
|
||||||
|
if (!meta || meta.hidden || !meta.data || !meta.data.length) return;
|
||||||
|
var last = meta.data[meta.data.length - 1];
|
||||||
|
if (!last) return;
|
||||||
|
ctx.save();
|
||||||
|
ctx.font = '600 10px -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif';
|
||||||
|
ctx.fillStyle = typeof ds.borderColor === 'string' ? ds.borderColor : '#555';
|
||||||
|
ctx.textAlign = 'left';
|
||||||
|
ctx.textBaseline = 'middle';
|
||||||
|
// Solidify alpha so labels remain readable even when the line is faint
|
||||||
|
var m = ctx.fillStyle.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
||||||
|
if (m) ctx.fillStyle = 'rgb(' + m[1] + ',' + m[2] + ',' + m[3] + ')';
|
||||||
|
ctx.fillText(ds.label, last.x + 4, last.y);
|
||||||
|
ctx.restore();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function renderGrowthChart(canvasId, containerId, lmsTable, patientX, patientY, xLabel, yLabel, extraDatasets) {
|
function renderGrowthChart(canvasId, containerId, lmsTable, patientX, patientY, xLabel, yLabel, extraDatasets) {
|
||||||
if (typeof Chart === 'undefined') return; // Chart.js not loaded yet
|
if (typeof Chart === 'undefined') return; // Chart.js not loaded yet
|
||||||
|
|
||||||
|
|
@ -841,11 +869,16 @@
|
||||||
_chartInstances[canvasId] = new Chart(document.getElementById(canvasId), {
|
_chartInstances[canvasId] = new Chart(document.getElementById(canvasId), {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: { datasets: datasets },
|
data: { datasets: datasets },
|
||||||
|
plugins: [percentileLabelPlugin],
|
||||||
options: {
|
options: {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: true,
|
maintainAspectRatio: true,
|
||||||
aspectRatio: 1.6,
|
aspectRatio: 1.6,
|
||||||
animation: { duration: 300 },
|
animation: { duration: 300 },
|
||||||
|
// Leave ~28px of padding on the right so the percentile labels
|
||||||
|
// ("50th", "95th", ...) drawn past the last data point are not
|
||||||
|
// clipped by the canvas edge.
|
||||||
|
layout: { padding: { right: 30 } },
|
||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: {
|
||||||
type: 'linear',
|
type: 'linear',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue