/**
* Warfarin Average Dose Adjustment
* @module warf
* @requires module:util
* @since v1.2.0
*/
import { checkValue, roundTo, displayValue, colorScale } from './util.js';
import * as LOG from "./logger.js";
$('#warf-aod').on('change', aodChanged);
$('#warf-changePercent').on('keyup', calculate);
$('#warf-changeDose').on('keyup', calculate);
$('#btnReset').on('click', () => {
doses.forEach( d => d.reset() );
aod = -1;
});
const colorStops = [
{
stop: 0,
hex: '#000000',
},
{
stop: 20,
hex: '#5a8ac6',
},
{
stop: 50,
hex: '#f8696b',
},
];
$(() => {
new Dose(1);
new Dose(2);
new Dose(3);
new Dose(4);
new Dose(5);
new Dose(6);
new Dose(7);
});
/** @type {Dose[]} */
const doses = [];
let aod = -1;
function aodChanged() {
const input = +checkValue($('#warf-aod').val(), -Infinity, Infinity, true);
aod = isNaN(input) ? -1 : input;
LOG.logArgs(`%cAOD dose changed to ${input} --> %cset to ${aod}`, 'color:purple', 'color:orange');
doses.forEach(d => {
if ( d.assumed ) d.val = aod;
});
calculate();
}
function calculate() {
const changePercent = +checkValue($('#warf-changePercent').val(), -Infinity, Infinity, true);
const changeDose = +checkValue($('#warf-changeDose').val(), 0, Infinity, true);
LOG.logArgs(`%cCalculating totals for ${changePercent}% change and ${changeDose} mg dose`, 'color:brown;font-weight:bold');
const res3 = getTotals(3, changePercent, changeDose);
const res5 = getTotals(5, changePercent, changeDose);
const res7 = getTotals(7, changePercent, changeDose);
displayValue('#warf-avg3', res3.avg, 0.1, ' mg');
displayValue('#warf-avg5', res5.avg, 0.1, ' mg');
displayValue('#warf-avg7', res7.avg, 0.1, ' mg');
displayValue('#warf-changePercent3', res3.pct, 0.1, ' mg', '', false, true);
displayValue('#warf-changePercent5', res5.pct, 0.1, ' mg', '', false, true);
displayValue('#warf-changePercent7', res7.pct, 0.1, ' mg', '', false, true);
displayPercentChange('#warf-changeDose3', res3.dose);
displayPercentChange('#warf-changeDose5', res5.dose);
displayPercentChange('#warf-changeDose7', res7.dose);
LOG.log( { changePercent, changeDose, res3, res5, res7 }, 'Calculation Results');
}
function displayPercentChange(selector, val) {
LOG.log(`Displaying percent change for ${selector}: ${val}`);
const rounded = Math.abs(roundTo(val, 1));
if ( val > 0 ) {
$(selector).html(`<strong>↑</strong> ${rounded} %`);
}
if ( val < 0 ) {
$(selector).html(`<strong>↓</strong> ${rounded} %`);
}
if ( val === 0 ) {
$(selector).html('—');
}
$(selector).css("color", colorScale(rounded, colorStops) );
}
/**
* Calculate the average dose over the last x days
*
* @param {Integer} days - Number of days to average
* @returns {Number} - Average dose, rounded to the nearest 0.1
*/
function getTotals(days, changePercent, changeDose) {
const res = {
avg: '',
pct: '',
dose: '',
};
if ( days < 1 || days > 7 ) {
LOG.warn(`${days} is not a valid number of days`);
return res;
}
LOG.groupCollapsed(`Getting average dose over ${days} days`);
const totalDose = doses.reduce(( sum, d ) => {
if ( sum < 0 ) return -1;
if ( d.day <= days ) {
if ( d.val >= 0 ) {
LOG.log(`Adding dose ${d.day} to total (${sum} += ${d.val})`);
return sum += d.val;
}
LOG.logArgs(`%cDose ${d.day} not set, cannot calculate average`, 'color:red');
return -1;
}
LOG.logArgs(`%cDose ${d.day} beyond requested days`, 'color:red');
return sum;
}, 0);
LOG.groupEnd();
if ( totalDose < 0 ) {
LOG.logArgs('%c...could not be calculated', 'color:red');
return res;
}
res.avg = roundTo(totalDose / days, 0.1);
LOG.logArgs(`%cTotal dose (${totalDose}) / days (${days}) = ${res.avg} mg`, 'color:green');
if ( !isNaN(changePercent) ) {
res.pct = res.avg + res.avg * changePercent / 100;
}
if ( !isNaN(changeDose) ) {
res.dose = ( changeDose - res.avg ) / res.avg * 100;
}
return res;
}
/** Class representing a warfarin dose. */
class Dose {
/**
* Create a Dose.
* @param {Integer} num - dose number
*/
constructor(num) {
this.ident = `#warf-dose${num}`;
this.day = num;
this.idx = num - 1;
this.val = -1;
this._val = -1;
this.assumed = true;
doses[this.idx] = this;
$(this.ident).on('change', () => this.changed() );
}
reset() {
this.val = -1;
this._val = -1;
}
changed() {
const input = $(this.ident).val();
this._val = +checkValue($(this.ident).val(), -Infinity, Infinity, true);
if ( isNaN(this._val) ) {
this.val = aod;
this.assumed = true;
} else {
this.val = this._val;
this.assumed = false;
}
LOG.logArgs(`%cDose ${this.day} changed to ${input}, value = ${this.val}%c${this.assumed ? ' (assumed)' : '' }`, 'color:blue', 'color:orange');
calculate();
}
}