nightscout
Version:
Nightscout acts as a web-based CGM (Continuous Glucose Monitor) to allow multiple caregivers to remotely view a patients glucose data in realtime.
914 lines (823 loc) • 35.7 kB
JavaScript
var init = function init () {
'use strict';
//for the tests window isn't the global object
var $ = window.$;
var _ = window._;
var moment = window.moment;
var Nightscout = window.Nightscout;
var client = Nightscout.client;
var report_plugins_preinit = Nightscout.report_plugins_preinit;
var report_plugins;
client.init(function loaded () {
report_plugins = report_plugins_preinit(client.ctx);
Nightscout.report_plugins = report_plugins;
// init HTML code
report_plugins.addHtmlFromPlugins(client);
// make show() accessible outside for treatments.js
report_plugins.show = show;
var translate = client.translate;
var maxInsulinValue = 0
, maxCarbsValue = 0
, maxDailyCarbsValue = 0;
var maxdays = 6 * 31;
var datastorage = {};
var daystoshow = {};
var sorteddaystoshow = [];
var targetBGdefault = {
'mg/dl': {
low: client.settings.thresholds.bgTargetBottom
, high: client.settings.thresholds.bgTargetTop
}
, 'mmol': {
low: client.utils.scaleMgdl(client.settings.thresholds.bgTargetBottom)
, high: client.utils.scaleMgdl(client.settings.thresholds.bgTargetTop)
}
};
var ONE_MIN_IN_MS = 60000;
prepareGUI();
// ****** FOOD CODE START ******
var food_categories = [];
var food_list = [];
var filter = {
category: ''
, subcategory: ''
, name: ''
};
function fillFoodForm (event) {
$('#rp_category').empty().append('<option value="">' + translate('(none)') + '</option>');
Object.keys(food_categories).forEach(function eachCategory (s) {
$('#rp_category').append('<option value="' + s + '">' + s + '</option>');
});
filter.category = '';
fillFoodSubcategories();
$('#rp_category').change(fillFoodSubcategories);
$('#rp_subcategory').change(doFoodFilter);
$('#rp_name').on('input', doFoodFilter);
return maybePrevent(event);
}
function fillFoodSubcategories (event) {
filter.category = $('#rp_category').val();
filter.subcategory = '';
$('#rp_subcategory').empty().append('<option value="">' + translate('(none)') + '</option>');
if (filter.category !== '') {
Object.keys(food_categories[filter.category] || {}).forEach(function eachSubCategory (s) {
$('#rp_subcategory').append('<option value="' + s + '">' + s + '</option>');
});
}
doFoodFilter();
return maybePrevent(event);
}
function doFoodFilter (event) {
if (event) {
filter.category = $('#rp_category').val();
filter.subcategory = $('#rp_subcategory').val();
filter.name = $('#rp_name').val();
}
$('#rp_food').empty();
for (var i = 0; i < food_list.length; i++) {
if (filter.category !== '' && food_list[i].category !== filter.category) { continue; }
if (filter.subcategory !== '' && food_list[i].subcategory !== filter.subcategory) { continue; }
if (filter.name !== '' && food_list[i].name.toLowerCase().indexOf(filter.name.toLowerCase()) < 0) { continue; }
var o = '';
o += food_list[i].name + ' | ';
o += translate('Portion') + ': ' + food_list[i].portion + ' ';
o += food_list[i].unit + ' | ';
o += translate('Carbs') + ': ' + food_list[i].carbs + ' g';
$('#rp_food').append('<option value="' + food_list[i]._id + '">' + o + '</option>');
}
return maybePrevent(event);
}
$('#info').html('<b>' + translate('Loading food database') + ' ...</b>');
$.ajax('/api/v1/food/regular.json', {
headers: client.headers()
, success: function foodLoadSuccess (records) {
records.forEach(function(r) {
food_list.push(r);
if (r.category && !food_categories[r.category]) { food_categories[r.category] = {}; }
if (r.category && r.subcategory) { food_categories[r.category][r.subcategory] = true; }
});
fillFoodForm();
}
}).done(function() {
if (food_list.length) {
enableFoodGUI();
} else {
disableFoodGUI();
}
}).fail(function() {
disableFoodGUI();
});
function enableFoodGUI () {
$('#info').html('');
$('.rp_foodgui').css('display', '');
$('#rp_food').change(function(event) {
$('#rp_enablefood').prop('checked', true);
return maybePrevent(event);
});
}
function disableFoodGUI () {
$('#info').html('');
$('.rp_foodgui').css('display', 'none');
}
// ****** FOOD CODE END ******
function prepareGUI () {
$('.presetdates').click(function(event) {
var days = $(this).attr('days');
$('#rp_enabledate').prop('checked', true);
return setDataRange(event, days);
});
$('#rp_show').click(show);
$('#rp_notes').bind('input', function(event) {
$('#rp_enablenotes').prop('checked', true);
return maybePrevent(event);
});
$('#rp_eventtype').bind('input', function(event) {
$('#rp_enableeventtype').prop('checked', true);
return maybePrevent(event);
});
// fill careportal events
$('#rp_eventtype').empty();
_.each(client.careportal.events, function eachEvent (event) {
$('#rp_eventtype').append('<option value="' + event.val + '">' + translate(event.name) + '</option>');
});
$('#rp_eventtype').append('<option value="sensor">' + '>>> ' + translate('All sensor events') + '</option>');
$('#rp_targetlow').val(targetBGdefault[client.settings.units.toLowerCase()].low);
$('#rp_targethigh').val(targetBGdefault[client.settings.units.toLowerCase()].high);
if (client.settings.scaleY === 'linear') {
$('#rp_linear').prop('checked', true);
$('#wrp_linear').prop('checked', true);
} else {
$('#rp_log').prop('checked', true);
$('#wrp_log').prop('checked', true);
}
$('.menutab').click(switchreport_handler);
setDataRange(null, 7);
}
function sgvToColor (sgv, options) {
var color = 'darkgreen';
if (sgv > options.targetHigh) {
color = 'red';
} else if (sgv < options.targetLow) {
color = 'red';
}
return color;
}
function show (event) {
var options = {
width: 1000
, height: 300
, weekwidth: 1000
, weekheight: 300
, targetLow: 3.5
, targetHigh: 10
, raw: true
, notes: true
, food: true
, insulin: true
, carbs: true
, iob: true
, cob: true
, basal: true
, scale: report_plugins.consts.scaleYFromSettings(client)
, weekscale: report_plugins.consts.scaleYFromSettings(client)
, units: client.settings.units
};
// default time range if no time range specified in GUI
var zone = client.sbx.data.profile.getTimezone();
var timerange = '&find[created_at][$gte]=' + moment.tz('2000-01-01', zone).toISOString();
//console.log(timerange,zone);
options.targetLow = parseFloat($('#rp_targetlow').val().replace(',', '.'));
options.targetHigh = parseFloat($('#rp_targethigh').val().replace(',', '.'));
options.raw = $('#rp_optionsraw').is(':checked');
options.iob = $('#rp_optionsiob').is(':checked');
options.cob = $('#rp_optionscob').is(':checked');
options.openAps = $('#rp_optionsopenaps').is(':checked');
options.predicted = $('#rp_optionspredicted').is(':checked');
options.predictedTruncate = $('#rp_optionsPredictedTruncate').is(':checked');
options.basal = $('#rp_optionsbasal').is(':checked');
options.notes = $('#rp_optionsnotes').is(':checked');
options.food = $('#rp_optionsfood').is(':checked');
options.insulin = $('#rp_optionsinsulin').is(':checked');
options.insulindistribution = $('#rp_optionsdistribution').is(':checked');
options.carbs = $('#rp_optionscarbs').is(':checked');
options.scale = ($('#rp_linear').is(':checked') ? report_plugins.consts.SCALE_LINEAR : report_plugins.consts.SCALE_LOG);
options.weekscale = ($('#wrp_linear').is(':checked') ? report_plugins.consts.SCALE_LINEAR : report_plugins.consts.SCALE_LOG);
options.order = ($('#rp_oldestontop').is(':checked') ? report_plugins.consts.ORDER_OLDESTONTOP : report_plugins.consts.ORDER_NEWESTONTOP);
options.width = parseInt($('#rp_size :selected').attr('x'));
options.weekwidth = parseInt($('#wrp_size :selected').attr('x'));
options.height = parseInt($('#rp_size :selected').attr('y'));
options.weekheight = parseInt($('#wrp_size :selected').attr('y'));
options.loopalyzer = $("#loopalyzer").hasClass("selected"); // We only want to run through Loopalyzer if that tab is selected
if (options.loopalyzer) {
options.iob = true;
options.cob = true;
options.openAps = true;
}
options.bgcheck = $('#rp_optionsbgcheck').is(':checked');
options.othertreatments = $('#rp_optionsothertreatments').is(':checked');
const reportStorage = require('./reportstorage');
reportStorage.saveProps(options);
var matchesneeded = 0;
// date range
function datefilter () {
if ($('#rp_enabledate').is(':checked')) {
matchesneeded++;
var from = moment.tz($('#rp_from').val().replace(/\//g, '-') + 'T00:00:00', zone);
var to = moment.tz($('#rp_to').val().replace(/\//g, '-') + 'T23:59:59', zone);
timerange = '&find[created_at][$gte]=' + from.toISOString() + '&find[created_at][$lt]=' + to.toISOString();
//console.log($('#rp_from').val(),$('#rp_to').val(),zone,timerange);
while (from <= to) {
if (daystoshow[from.format('YYYY-MM-DD')]) {
daystoshow[from.format('YYYY-MM-DD')]++;
} else {
daystoshow[from.format('YYYY-MM-DD')] = 1;
}
from.add(1, 'days');
}
}
//console.log('Dayfilter: ',daystoshow);
foodfilter();
}
//food filter
function foodfilter () {
if ($('#rp_enablefood').is(':checked')) {
matchesneeded++;
var _id = $('#rp_food').val();
if (_id) {
var treatmentData;
var tquery = '?find[boluscalc.foods._id]=' + _id + timerange;
$.ajax('/api/v1/treatments.json' + tquery, {
headers: client.headers()
, success: function(xhr) {
treatmentData = xhr.map(function(treatment) {
return moment.tz(treatment.created_at, zone).format('YYYY-MM-DD');
});
// unique it
treatmentData = $.grep(treatmentData, function(v, k) {
return $.inArray(v, treatmentData) === k;
});
treatmentData.sort(function(a, b) { return a > b; });
}
}).done(function() {
//console.log('Foodfilter: ',treatmentData);
for (var d = 0; d < treatmentData.length; d++) {
if (daystoshow[treatmentData[d]]) {
daystoshow[treatmentData[d]]++;
} else {
daystoshow[treatmentData[d]] = 1;
}
}
notesfilter();
});
}
} else {
notesfilter();
}
}
//notes filter
function notesfilter () {
if ($('#rp_enablenotes').is(':checked')) {
matchesneeded++;
var notes = $('#rp_notes').val();
if (notes) {
var treatmentData;
var tquery = '?find[notes]=/' + notes + '/i';
$.ajax('/api/v1/treatments.json' + tquery + timerange, {
headers: client.headers()
, success: function(xhr) {
treatmentData = xhr.map(function(treatment) {
return moment.tz(treatment.created_at, zone).format('YYYY-MM-DD');
});
// unique it
treatmentData = $.grep(treatmentData, function(v, k) {
return $.inArray(v, treatmentData) === k;
});
treatmentData.sort(function(a, b) { return a > b; });
}
}).done(function() {
//console.log('Notesfilter: ',treatmentData);
for (var d = 0; d < treatmentData.length; d++) {
if (daystoshow[treatmentData[d]]) {
daystoshow[treatmentData[d]]++;
} else {
daystoshow[treatmentData[d]] = 1;
}
}
eventtypefilter();
});
}
} else {
eventtypefilter();
}
}
//event type filter
function eventtypefilter () {
if ($('#rp_enableeventtype').is(':checked')) {
matchesneeded++;
var eventtype = $('#rp_eventtype').val();
if (eventtype) {
var treatmentData;
var tquery = '?find[eventType]=/' + eventtype + '/i';
$.ajax('/api/v1/treatments.json' + tquery + timerange, {
headers: client.headers()
, success: function(xhr) {
treatmentData = xhr.map(function(treatment) {
return moment.tz(treatment.created_at, zone).format('YYYY-MM-DD');
});
// unique it
treatmentData = $.grep(treatmentData, function(v, k) {
return $.inArray(v, treatmentData) === k;
});
treatmentData.sort(function(a, b) { return a > b; });
}
}).done(function() {
//console.log('Eventtypefilter: ',treatmentData);
for (var d = 0; d < treatmentData.length; d++) {
if (daystoshow[treatmentData[d]]) {
daystoshow[treatmentData[d]]++;
} else {
daystoshow[treatmentData[d]] = 1;
}
}
daysfilter();
});
}
} else {
daysfilter();
}
}
function daysfilter () {
matchesneeded++;
Object.keys(daystoshow).forEach(function eachDay (d) {
var day = moment.tz(d, zone).day();
if (day === 0 && $('#rp_su').is(':checked')) { daystoshow[d]++; }
if (day === 1 && $('#rp_mo').is(':checked')) { daystoshow[d]++; }
if (day === 2 && $('#rp_tu').is(':checked')) { daystoshow[d]++; }
if (day === 3 && $('#rp_we').is(':checked')) { daystoshow[d]++; }
if (day === 4 && $('#rp_th').is(':checked')) { daystoshow[d]++; }
if (day === 5 && $('#rp_fr').is(':checked')) { daystoshow[d]++; }
if (day === 6 && $('#rp_sa').is(':checked')) { daystoshow[d]++; }
});
countDays();
addPreviousDayTreatments();
display();
}
function display () {
var count = 0;
sorteddaystoshow = [];
$('#info').html('<b>' + translate('Loading') + ' ...</b>');
for (var d in daystoshow) {
if (count < maxdays) {
$('#info').append($('<div id="info-' + d + '"></div>'));
count++;
loadData(d, options, dataLoadedCallback);
} else {
$('#info').append($('<div>' + d + ' ' + translate('not displayed') + '.</div>'));
delete daystoshow[d];
}
}
if (count === 0) {
$('#info').html('<b>' + translate('Result is empty') + '</b>');
$('#rp_show').css('display', '');
}
}
var dayscount = 0;
var loadeddays = 0;
function countDays () {
for (var d in daystoshow) {
if (Object.prototype.hasOwnProperty.call(daystoshow, d)) {
if (daystoshow[d] === matchesneeded) {
if (dayscount < maxdays) {
dayscount++;
}
} else {
delete daystoshow[d];
}
}
}
//console.log('Total: ', daystoshow, 'Matches needed: ', matchesneeded, 'Will be loaded: ', dayscount);
}
function addPreviousDayTreatments () {
for (var d in daystoshow) {
if (Object.prototype.hasOwnProperty.call(daystoshow, d)) {
var day = moment.tz(d, zone);
var previous = day.subtract(1, 'days');
var formated = previous.format('YYYY-MM-DD');
if (!daystoshow[formated]) {
daystoshow[formated] = { treatmentsonly: true };
console.log('Adding ' + formated + ' for loading treatments');
dayscount++;
}
}
}
//console.log('Total: ', daystoshow, 'Matches needed: ', matchesneeded, 'Will be loaded: ', dayscount);
}
function dataLoadedCallback (day) {
loadeddays++;
if (!daystoshow[day].treatmentsonly) {
sorteddaystoshow.push(day);
}
if (loadeddays === dayscount) {
sorteddaystoshow.sort();
var dFrom = sorteddaystoshow[0];
var dTo = sorteddaystoshow[(sorteddaystoshow.length - 1)];
if (options.order === report_plugins.consts.ORDER_NEWESTONTOP) {
sorteddaystoshow.reverse();
}
loadProfileSwitch(dFrom, function loadProfileSwitchCallback () {
loadProfilesRange(dFrom, dTo, sorteddaystoshow.length, function loadProfilesCallback () {
$('#info > b').html('<b>' + translate('Rendering') + ' ...</b>');
window.setTimeout(function() {
showreports(options);
}, 0);
});
});
}
}
$('#rp_show').css('display', 'none');
daystoshow = {};
datefilter();
return maybePrevent(event);
}
function showreports (options) {
// prepare some data used in more reports
datastorage.allstatsrecords = [];
datastorage.alldays = 0;
sorteddaystoshow.forEach(function eachDay (day) {
if (!daystoshow[day].treatmentsonly) {
datastorage.allstatsrecords = datastorage.allstatsrecords.concat(datastorage[day].statsrecords);
datastorage.alldays++;
}
});
options.maxInsulinValue = maxInsulinValue;
options.maxCarbsValue = maxCarbsValue;
options.maxDailyCarbsValue = maxDailyCarbsValue;
datastorage.treatments = [];
datastorage.devicestatus = [];
datastorage.combobolusTreatments = [];
datastorage.tempbasalTreatments = [];
Object.keys(daystoshow).forEach(function eachDay (day) {
datastorage.treatments = datastorage.treatments.concat(datastorage[day].treatments);
datastorage.devicestatus = datastorage.devicestatus.concat(datastorage[day].devicestatus);
datastorage.combobolusTreatments = datastorage.combobolusTreatments.concat(datastorage[day].combobolusTreatments);
datastorage.tempbasalTreatments = datastorage.tempbasalTreatments.concat(datastorage[day].tempbasalTreatments);
});
datastorage.tempbasalTreatments = Nightscout.client.ddata.processDurations(datastorage.tempbasalTreatments);
datastorage.treatments.sort(function sort (a, b) { return a.mills - b.mills; });
for (var d in daystoshow) {
if (Object.prototype.hasOwnProperty.call(daystoshow, d)) {
if (daystoshow[d].treatmentsonly) {
delete daystoshow[d];
delete datastorage[d];
}
}
}
report_plugins.eachPlugin(function(plugin) {
// jquery plot doesn't draw to hidden div
$('#' + plugin.name + '-placeholder').css('display', '');
console.log('Drawing ', plugin.name);
var skipRender = false;
if (plugin.name == 'daytoday' && !$('#daytoday').hasClass('selected')) skipRender = true;
if (plugin.name == 'treatments' && !$('#treatments').hasClass('selected')) skipRender = true;
if (plugin.name == 'weektoweek' && !$('#weektoweek').hasClass('selected')) skipRender = true;
if (plugin.name == 'loopalyzer' && !$('#loopalyzer').hasClass('selected')) skipRender = true;
if (skipRender) {
console.log('Skipping ', plugin.name);
} else {
plugin.report(datastorage, sorteddaystoshow, options);
}
if (!$('#' + plugin.name).hasClass('selected')) {
$('#' + plugin.name + '-placeholder').css('display', 'none');
}
});
$('#info').html('');
$('#rp_show').css('display', '');
}
function setDataRange (event, days) {
$('#rp_to').val(moment().format('YYYY-MM-DD'));
$('#rp_from').val(moment().add(-days + 1, 'days').format('YYYY-MM-DD'));
return maybePrevent(event);
}
function switchreport_handler (event) {
var id = $(this).attr('id');
$('.menutab').removeClass('selected');
$('#' + id).addClass('selected');
$('.tabplaceholder').css('display', 'none');
$('#' + id + '-placeholder').css('display', '');
return maybePrevent(event);
}
function loadData (day, options, callback) {
// check for loaded data
if ((options.openAps || options.predicted || options.iob || options.cob) && datastorage[day] && !datastorage[day].devicestatus.length) {
// OpenAPS requested but data not loaded. Load anyway ...
} else if (datastorage[day] && day !== moment().format('YYYY-MM-DD')) {
callback(day);
return;
}
// patientData = [actual, predicted, mbg, treatment, cal, devicestatusData];
var data = {};
var cgmData = []
, mbgData = []
, treatmentData = []
, calData = [];
var from;
if (client.sbx.data.profile.getTimezone()) {
from = moment(day).tz(client.sbx.data.profile.getTimezone()).startOf('day').format('x');
} else {
from = moment(day).startOf('day').format('x');
}
from = parseInt(from);
var to = from + 1000 * 60 * 60 * 24;
function loadCGMData () {
if (daystoshow[day].treatmentsonly) {
data.sgv = [];
data.mbg = [];
data.cal = [];
return $.Deferred().resolve();
}
$('#info-' + day).html('<b>' + translate('Loading CGM data of') + ' ' + day + ' ...</b>');
var query = '?find[date][$gte]=' + from + '&find[date][$lt]=' + to + '&count=10000';
return $.ajax('/api/v1/entries.json' + query, {
headers: client.headers()
, success: function(xhr) {
xhr.forEach(function(element) {
if (element) {
if (element.mbg) {
mbgData.push({
y: element.mbg
, mills: element.date
, d: element.dateString
, device: element.device
});
} else if (element.sgv) {
cgmData.push({
y: element.sgv
, mills: element.date
, d: element.dateString
, device: element.device
, filtered: element.filtered
, unfiltered: element.unfiltered
, noise: element.noise
, rssi: element.rssi
, sgv: element.sgv
});
} else if (element.type === 'cal') {
calData.push({
mills: element.date + 1
, d: element.dateString
, scale: element.scale
, intercept: element.intercept
, slope: element.slope
});
}
}
});
// sometimes cgm contains duplicates. uniq it.
data.sgv = cgmData.slice();
data.sgv.sort(function(a, b) { return a.mills - b.mills; });
var lastDate = 0;
data.sgv = data.sgv.filter(function(d) {
var ok = (lastDate + ONE_MIN_IN_MS) <= d.mills;
lastDate = d.mills;
if (!ok) { console.log("itm", JSON.stringify(d)); }
return ok;
});
data.mbg = mbgData.slice();
data.mbg.sort(function(a, b) { return a.mills - b.mills; });
data.cal = calData.slice();
data.cal.sort(function(a, b) { return a.mills - b.mills; });
}
});
}
function loadTreatmentData () {
if (!datastorage.profileSwitchTreatments)
datastorage.profileSwitchTreatments = [];
$('#info-' + day).html('<b>' + translate('Loading treatments data of') + ' ' + day + ' ...</b>');
var tquery = '?find[created_at][$gte]=' + new Date(from).toISOString() + '&find[created_at][$lt]=' + new Date(to).toISOString() + '&count=1000';
return $.ajax('/api/v1/treatments.json' + tquery, {
headers: client.headers()
, cache: false
, success: function(xhr) {
treatmentData = xhr.map(function(treatment) {
var timestamp = new Date(treatment.timestamp || treatment.created_at);
treatment.mills = timestamp.getTime();
return treatment;
});
data.treatments = treatmentData.slice();
data.treatments.sort(function(a, b) { return a.mills - b.mills; });
// filter 'Combo Bolus' events
data.combobolusTreatments = data.treatments.filter(function filterComboBoluses (t) {
return t.eventType === 'Combo Bolus';
});
// filter temp basal treatments
data.tempbasalTreatments = data.treatments.filter(function filterTempBasals (t) {
return t.eventType === 'Temp Basal';
});
// filter profile switch treatments
var profileSwitch = data.treatments.filter(function filterProfileSwitch (t) {
return t.eventType === 'Profile Switch';
});
datastorage.profileSwitchTreatments = datastorage.profileSwitchTreatments.concat(profileSwitch);
}
});
}
function loadDevicestatusData () {
if (daystoshow[day].treatmentsonly) {
data.devicestatus = [];
return $.Deferred().resolve();
}
if (options.iob || options.cob || options.openAps || options.predicted) {
$('#info-' + day).html('<b>' + translate('Loading device status data of') + ' ' + day + ' ...</b>');
var tquery = '?find[created_at][$gte]=' + new Date(from).toISOString() + '&find[created_at][$lt]=' + new Date(to).toISOString() + '&count=10000';
return $.ajax('/api/v1/devicestatus.json' + tquery, {
headers: client.headers()
, success: function(xhr) {
data.devicestatus = xhr.map(function(devicestatus) {
devicestatus.mills = new Date(devicestatus.timestamp || devicestatus.created_at).getTime();
return devicestatus;
});
}
});
} else {
data.devicestatus = [];
return $.Deferred().resolve();
}
}
$.when(loadCGMData(), loadTreatmentData(), loadDevicestatusData()).done(function() {
$('#info-' + day).html('<b>' + translate('Processing data of') + ' ' + day + ' ...</b>');
processData(data, day, options, callback);
});
}
function loadProfileSwitch (from, callback) {
$('#info > b').html('<b>' + translate('Loading profile switch data') + ' ...</b>');
var tquery = '?find[eventType]=Profile Switch' + '&find[created_at][$lte]=' + new Date(from).toISOString() + '&count=1';
$.ajax('/api/v1/treatments.json' + tquery, {
headers: client.headers()
, success: function(xhr) {
var treatmentData = xhr.map(function(treatment) {
var timestamp = new Date(treatment.timestamp || treatment.created_at);
treatment.mills = timestamp.getTime();
return treatment;
});
if (!datastorage.profileSwitchTreatments)
datastorage.profileSwitchTreatments = [];
datastorage.profileSwitchTreatments = datastorage.profileSwitchTreatments.concat(treatmentData);
datastorage.profileSwitchTreatments.sort(function(a, b) { return a.mills - b.mills; });
}
}).done(function() {
callback();
});
}
function loadProfilesRange (dateFrom, dateTo, dayCount, callback) {
$('#info > b').html('<b>' + translate('Loading profile range') + ' ...</b>');
$.when(
loadProfilesRangeCore(dateFrom, dateTo, dayCount)
, loadProfilesRangePrevious(dateFrom)
, loadProfilesRangeNext(dateTo)
)
.done(callback)
.fail(function() {
datastorage.profiles = [];
});
}
function loadProfilesRangeCore (dateFrom, dateTo) {
$('#info > b').html('<b>' + translate('Loading core profiles') + ' ...</b>');
//The results must be returned in descending order to work with key logic in routines such as getCurrentProfile
var tquery = '?find[startDate][$gte]=' + new Date(dateFrom).toISOString() + '&find[startDate][$lte]=' + new Date(dateTo).toISOString() + '&sort[startDate]=-1&count=1000';
return $.ajax('/api/v1/profiles' + tquery, {
headers: client.headers()
, async: false
, success: function(records) {
datastorage.profiles = records;
}
});
}
function loadProfilesRangePrevious (dateFrom) {
$('#info > b').html('<b>' + translate('Loading previous profile') + ' ...</b>');
//Find first one before the start date and add to datastorage.profiles
var tquery = '?find[startDate][$lt]=' + new Date(dateFrom).toISOString() + '&sort[startDate]=-1&count=1';
return $.ajax('/api/v1/profiles' + tquery, {
headers: client.headers()
, async: false
, success: function(records) {
records.forEach(function(r) {
datastorage.profiles.push(r);
});
}
});
}
function loadProfilesRangeNext (dateTo) {
$('#info > b').html('<b>' + translate('Loading next profile') + ' ...</b>');
//Find first one after the end date and add to datastorage.profiles
var tquery = '?find[startDate][$gt]=' + new Date(dateTo).toISOString() + '&sort[startDate]=1&count=1';
return $.ajax('/api/v1/profiles' + tquery, {
headers: client.headers()
, async: false
, success: function(records) {
records.forEach(function(r) {
//must be inserted as top to maintain profiles being sorted by date in descending order
datastorage.profiles.unshift(r);
});
}
});
}
function processData (data, day, options, callback) {
if (daystoshow[day].treatmentsonly) {
datastorage[day] = data;
$('#info-' + day).html('');
callback(day);
return;
}
// treatments
data.dailyCarbs = 0;
data.dailyProtein = 0;
data.dailyFat = 0;
data.treatments.forEach(function(d) {
if (parseFloat(d.insulin) > maxInsulinValue) {
maxInsulinValue = parseFloat(d.insulin);
}
if (parseFloat(d.carbs) > maxCarbsValue) {
maxCarbsValue = parseFloat(d.carbs);
}
if (d.carbs) {
data.dailyCarbs += Number(d.carbs);
}
if (d.protein) {
data.dailyProtein += Number(d.protein);
}
if (d.fat) {
data.dailyFat += Number(d.fat);
}
});
if (data.dailyCarbs > maxDailyCarbsValue) {
maxDailyCarbsValue = data.dailyCarbs;
}
var cal = data.cal[data.cal.length - 1];
var temp1 = [];
var rawbg = client.rawbg;
if (cal) {
temp1 = data.sgv.map(function(entry) {
entry.mgdl = entry.y; // value names changed from enchilada
var rawBg = rawbg.calc(entry, cal);
return { mills: entry.mills, date: new Date(entry.mills - 2 * 1000), y: rawBg, sgv: client.utils.scaleMgdl(rawBg), color: 'gray', type: 'rawbg', filtered: entry.filtered, unfiltered: entry.unfiltered };
}).filter(function(entry) { return entry.y > 0 });
}
var temp2 = data.sgv.map(function(obj) {
return { mills: obj.mills, date: new Date(obj.mills), y: obj.y, sgv: client.utils.scaleMgdl(obj.y), color: sgvToColor(client.utils.scaleMgdl(obj.y), options), type: 'sgv', noise: obj.noise, filtered: obj.filtered, unfiltered: obj.unfiltered };
});
data.sgv = [].concat(temp1, temp2);
//Add MBG's also, pretend they are SGV's
data.sgv = data.sgv.concat(data.mbg.map(function(obj) { return { date: new Date(obj.mills), y: obj.y, sgv: client.utils.scaleMgdl(obj.y), color: 'red', type: 'mbg', device: obj.device } }));
// make sure data range will be exactly 24h
var from;
if (client.sbx.data.profile.getTimezone()) {
from = moment(day).tz(client.sbx.data.profile.getTimezone()).startOf('day').toDate();
} else {
from = moment(day).startOf('day').toDate();
}
var to = new Date(from.getTime() + 1000 * 60 * 60 * 24);
data.sgv.push({ date: from, y: 40, sgv: 40, color: 'transparent', type: 'rawbg' });
data.sgv.push({ date: to, y: 40, sgv: 40, color: 'transparent', type: 'rawbg' });
// clear error data. we don't need it to display them
data.sgv = data.sgv.filter(function(d) {
if (d.y < 39) {
return false;
}
return true;
});
data.sgv = data.sgv.map(function eachSgv (sgv) {
var status = _.find(data.devicestatus, function(d) {
return d.mills >= sgv.mills && d.mills < sgv.mills + 5 * 60 * 1000;
});
if (status && status.openaps) {
sgv.openaps = status.openaps;
}
return sgv;
});
// for other reports
data.statsrecords = data.sgv.filter(function(r) {
if (r.type) {
return r.type === 'sgv';
} else {
return true;
}
}).map(function(r) {
var ret = {};
ret.sgv = parseFloat(r.sgv);
ret.bgValue = parseInt(r.y);
ret.displayTime = r.date;
return ret;
});
datastorage[day] = data;
$('#info-' + day).html('');
callback(day);
}
function maybePrevent (event) {
if (event) {
event.preventDefault();
}
return false;
}
});
};
module.exports = init;