/* Neonatal jaundice treatment threshold calculator Copyright (C) 2024-2025 Lee Yingtong Li This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // -------------------------------------- // Extra questions by guideline/gestation function updateExtraQuestions() { // Show or hide extra questions according to guideline and gestation let guideline = document.getElementById('guideline').value; let gestation = document.getElementById('gestation').valueAsNumber; if (guideline === 'rwh') { document.getElementById('questions_rwh').classList.remove('hidden'); if (gestation >= 35) { document.getElementById('questions_rwh_geq35').classList.remove('hidden'); document.getElementById('questions_rwh_lt35').classList.add('hidden'); } else { document.getElementById('questions_rwh_geq35').classList.add('hidden'); document.getElementById('questions_rwh_lt35').classList.remove('hidden'); } } else { document.getElementById('questions_rwh').classList.add('hidden'); } // Also update source in footer if (guideline === 'nice') { document.getElementById('guideline_source').innerHTML = 'National Institute for Health and Clinical Excellence. Neonatal jaundice treatment threshold graphs. In: Jaundice in newborn babies under 28 days. London: National Institute for Health and Clinical Excellence; 2023. (NICE clinical guidelines; CG98). https://www.nice.org.uk/guidance/cg98'; } else if (guideline === 'rwh') { if (gestation >= 35) { document.getElementById('guideline_source').innerHTML = 'Royal Women\'s Hospital. Jaundice (hyperbilirubinaemia) in newborn infants ≥ 35 weeks gestation: guideline. Version 2.0. Melbourne: Royal Women\'s Hospital; 2025.'; } else { document.getElementById('guideline_source').innerHTML = 'Royal Women\'s Hospital. Jaundice (hyperbilirubinaemia) in preterm infants < 35 weeks gestation: guideline. Version 2.0. Melbourne: Royal Women\'s Hospital; 2025.'; } } else { throw new Error('Unexpected guideline'); } } updateExtraQuestions(); // -------------- // Graph plotting function isGestationValid(guideline, gestation) { if (isNaN(gestation)) { return false; } if (guideline === 'nice' && gestation < 23) { return false; } return true; } function plotGraphData() { let guideline = document.getElementById('guideline').value; let gestation = document.getElementById('gestation').valueAsNumber; if (!isGestationValid(guideline, gestation)) { chart.data.datasets[0].data = []; chart.data.datasets[1].data = []; } else if (guideline === 'nice') { chart.data.datasets[0].data = [...Array(14*24).keys()].map((i) => i / 24).map((d) => ({x: d, y: nice_phototherapy_thresh(d, gestation)})); chart.data.datasets[1].data = [...Array(14*24).keys()].map((i) => i / 24).map((d) => ({x: d, y: nice_exchange_thresh(d, gestation)})); } else if (guideline === 'rwh') { let dat = document.getElementById('dat').checked; let bw_lt2500 = document.getElementById('bw_lt2500').checked; let bw_lt1000 = document.getElementById('bw_lt1000').checked; let fhx_rbc = document.getElementById('fhx_rbc').checked; let bruising = document.getElementById('bruising').checked; chart.data.datasets[0].data = [...Array(14*24).keys()].map((i) => i / 24).map((d) => ({x: d, y: rwh_phototherapy_thresh(d, gestation, dat, bw_lt2500, bw_lt1000, fhx_rbc, bruising)})); chart.data.datasets[1].data = [...Array(14*24).keys()].map((i) => i / 24).map((d) => ({x: d, y: rwh_exchange_thresh(d, gestation, dat, bw_lt2500, bw_lt1000, fhx_rbc, bruising)})); } else { throw new Error('Unexpected guideline'); } chart.update(); } Chart.defaults.color = '#111827'; // gray-900 Chart.defaults.font.family = 'Manrope, Helvetica, Arial, sans-serif'; const chart = new Chart(document.getElementById('bilirubinChart'), { type: 'scatter', data: { datasets: [ { label: 'Phototherapy', data: [], showLine: true, pointStyle: false }, { label: 'Exchange transfusion', data: [], showLine: true, pointStyle: false }, { label: 'Measurement', data: [] } ] }, options: { scales: { x: { title: { display: true, text: 'Chronological age (days)' }, min: 0, max: 14, ticks: { stepSize: 0.25, callback: (value) => value % 1 == 0 ? value : '', autoSkip: false, maxRotation: 0 }, grid: { color: (context) => context.tick.value % 1 == 0 ? '#9ca3af' : '#e5e7eb' // gray-400 / gray-200 } }, y: { title: { display: true, text: 'Total bilirubin (μmol/L)' }, min: 0, max: 550, ticks: { stepSize: 10, callback: (value) => value % 50 == 0 ? value : '', autoSkip: false }, grid: { color: (context) => context.tick.value % 50 == 0 ? '#9ca3af' : '#e5e7eb' // gray-400 / gray-200 } } }, interaction: { mode: 'x', intersect: false }, plugins: { tooltip: { callbacks: { title: (context) => prettyPrintDays(context[0].parsed.x), label: (context) => context.dataset.label + ': ' + Math.round(context.parsed.y) }, filter: (context, idx, items) => Math.abs(context.parsed.x - items[0].parsed.x) < 0.5/24 } }, maintainAspectRatio: false } }); plotGraphData(); // ------------ // Prefill form let dateNow = dateToISOStringLocal(new Date()); if (document.getElementById('time_birth').value === '') { document.getElementById('time_birth').value = dateNow; } if (document.getElementById('time_measurement').value === '') { document.getElementById('time_measurement').value = dateNow; } // -------------------------- // Plot bilirubin measurement function updateBilirubin() { let resultDiv = document.getElementById('result'); let resultP = resultDiv.querySelector('p'); let guideline = document.getElementById('guideline').value; let bilirubin = document.getElementById('bilirubin').valueAsNumber; let gestation = document.getElementById('gestation').valueAsNumber; if (document.getElementById('time_birth').value === '') { resultDiv.className = 'hidden'; return; } if (document.getElementById('time_measurement').value === '') { resultDiv.className = 'hidden'; return; } if (isNaN(bilirubin)) { resultDiv.className = 'hidden'; return; } if (!isGestationValid(guideline, gestation)) { resultDiv.className = 'hidden'; return; } let d = chronoAgeInDays(new Date(document.getElementById('time_birth').value), new Date(document.getElementById('time_measurement').value)); // Calculate thresholds let phototherapy_thresh_value, exchange_thresh_value; if (guideline === 'nice') { phototherapy_thresh_value = nice_phototherapy_thresh(d, gestation); exchange_thresh_value = nice_exchange_thresh(d, gestation); } else if (guideline === 'rwh') { let dat = document.getElementById('dat').checked; let bw_lt2500 = document.getElementById('bw_lt2500').checked; let bw_lt1000 = document.getElementById('bw_lt1000').checked; let fhx_rbc = document.getElementById('fhx_rbc').checked; let bruising = document.getElementById('bruising').checked; phototherapy_thresh_value = rwh_phototherapy_thresh(d, gestation, dat, bw_lt2500, bw_lt1000, fhx_rbc, bruising); exchange_thresh_value = rwh_exchange_thresh(d, gestation, dat, bw_lt2500, bw_lt1000, fhx_rbc, bruising); } else { throw new Error('Unexpected guideline'); } // Format for display let [result_text, text_colour, background_colour, accent_colour] = describeBilirubin(d, bilirubin, phototherapy_thresh_value, exchange_thresh_value); resultDiv.className = 'border-l-4 ' + accent_colour + ' ' + background_colour + ' py-2 px-4 mt-4'; resultP.className = 'text-sm ' + text_colour; resultP.innerHTML = result_text; // Update graph chart.data.datasets[2].data = [{x: d, y: bilirubin}]; chart.update(); } updateBilirubin();