583 lines
21 KiB
JavaScript
583 lines
21 KiB
JavaScript
/*
|
|
biomon - Signs monitoring and patient management application
|
|
|
|
Copyright (C) 2015 Entr'ouvert
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
var DASHBOARD = DASHBOARD || (function(){
|
|
|
|
var
|
|
/* Literal object for configuration */
|
|
_player_conf = {'range_value': 2},
|
|
|
|
/* Ajax endpoints */
|
|
_instants_url = "livedata_provider/instants",
|
|
_means_url = "livedata_provider/means",
|
|
_histograms_url = "livedata_provider/histograms",
|
|
_rendering_url = "livedata_provider/render",
|
|
_minmax_url = "livedata_provider/minmax",
|
|
_next_alert_url = "livedata_provider/next_alert",
|
|
_previous_alert_url = "livedata_provider/previous_alert",
|
|
|
|
/* Flag for pausing or playing data, in simulated real time. */
|
|
_play = true,
|
|
|
|
/* Time range of date displayed by the dashboard */
|
|
_range_values = [1, 2, 5, 10, 20, 30, 60, 120, 180, 720, 1440, 2880, 4320, 10080],
|
|
_index = null,
|
|
_range_value = null,
|
|
|
|
/* Time frame displayed by the dashboard */
|
|
_epoch_frame = new Array(),
|
|
|
|
/*
|
|
If defined, pause_time define the end datetime of the time frame
|
|
displayed in the dashboard instead of now if not defined.
|
|
*/
|
|
_pause_time = null;
|
|
|
|
_index = _player_conf['range_value'],
|
|
_range_value = _range_values[_index],
|
|
_epoch_frame["from"] = Math.floor(new Date().getTime()/1000);
|
|
_epoch_frame["until"] = Math.floor(new Date().getTime()/1000);
|
|
|
|
function get_range_value(){
|
|
return _range_value;
|
|
};
|
|
|
|
function _get_epoch_range() {
|
|
var now = new Date();
|
|
var end = Math.floor(now.getTime()/1000);
|
|
if( _pause_time ){
|
|
end = _pause_time;
|
|
}
|
|
var range = _range_value * 60;
|
|
var start = end - range;
|
|
_epoch_frame["from"] = start
|
|
_epoch_frame["until"] = end
|
|
if (!$('#datepicker-player').datepicker( "widget" ).is(":visible")){
|
|
/*
|
|
Do not refresh if datepicker is opened.
|
|
*/
|
|
if( _pause_time ){
|
|
$('#datepicker-player').datepicker("setDate", new Date(_pause_time*1000));
|
|
} else {
|
|
$('#datepicker-player').datepicker("setDate", now);
|
|
}
|
|
}
|
|
};
|
|
|
|
/*
|
|
Reload functions
|
|
* grab data
|
|
* set DOM
|
|
*/
|
|
function _reload_instants(){
|
|
var target = _instants_url
|
|
target += "?"
|
|
target = UTILS.dict_to_query(target, _epoch_frame);
|
|
target = UTILS.fresh_query(target);
|
|
$.ajax( {
|
|
type: 'Get',
|
|
url: target,
|
|
success: function(data) {
|
|
$("span#heartrate").removeClass();
|
|
if(data[0]) {
|
|
$("span#heartrate").text(data[0]);
|
|
if(data[1]) {
|
|
$("span#heartrate").addClass(data[1]);
|
|
$("span#heartrate").fadeOut('fast');
|
|
$("span#heartrate").fadeIn('slow');
|
|
}
|
|
} else {
|
|
$("span#heartrate").text('-');
|
|
}
|
|
$("span#temperature").removeClass();
|
|
if(data[2]) {
|
|
$("span#temperature").text(data[2].toFixed(1));
|
|
if(data[3]) {
|
|
$("span#temperature").addClass(data[3]);
|
|
$("span#temperature").fadeOut('fast');
|
|
$("span#temperature").fadeIn('slow');
|
|
}
|
|
} else {
|
|
$("span#temperature").text('-');
|
|
}
|
|
},
|
|
error: function(xhr, ajaxOptions, thrownError) {
|
|
$("span#heartrate").text('-');
|
|
$("span#temperature").text('-');
|
|
}
|
|
})
|
|
};
|
|
function _reload_means(){
|
|
var target = _means_url
|
|
target += "?duration=300&"
|
|
target = UTILS.dict_to_query(target, _epoch_frame);
|
|
target = UTILS.fresh_query(target);
|
|
$.ajax( {
|
|
type: 'Get',
|
|
url: target,
|
|
success: function(data) {
|
|
if(data[0]) {
|
|
$("span#heartrate-mean1").text(data[0].toPrecision(2));
|
|
} else {
|
|
$("span#heartrate-mean1").text('-');
|
|
}
|
|
if(data[1]) {
|
|
$("span#temperature-mean1").text(data[1].toPrecision(2));
|
|
} else {
|
|
$("span#temperature-mean1").text('-');
|
|
}
|
|
},
|
|
error: function() {
|
|
$("span#heartrate-mean1").text('-');
|
|
$("span#temperature-mean1").text('-');
|
|
}
|
|
})
|
|
target = _means_url;
|
|
target += "?duration=86400&";
|
|
target = UTILS.dict_to_query(target, _epoch_frame);
|
|
target = UTILS.fresh_query(target);
|
|
$.ajax( {
|
|
type: 'Get',
|
|
url: target,
|
|
success: function(data) {
|
|
if(data[0]) {
|
|
$("span#heartrate-mean2").text(data[0].toPrecision(2));
|
|
} else {
|
|
$("span#heartrate-mean2").text('-');
|
|
}
|
|
if(data[1]) {
|
|
$("span#temperature-mean2").text(data[1].toPrecision(2));
|
|
} else {
|
|
$("span#temperature-mean2").text('-');
|
|
}
|
|
},
|
|
error: function() {
|
|
$("span#heartrate-mean2").text('-');
|
|
$("span#temperature-mean2").text('-');
|
|
}
|
|
})
|
|
}
|
|
function _reload_minmax(){
|
|
var target = _minmax_url
|
|
target += "?duration=" + (_range_value * 60) + "&"
|
|
target = UTILS.dict_to_query(target, _epoch_frame);
|
|
target = UTILS.fresh_query(target);
|
|
$.ajax( {
|
|
type: 'Get',
|
|
url: target,
|
|
success: function(data) {
|
|
if(data[0]) {
|
|
$("span#heartrate-min").text(data[0]);
|
|
} else {
|
|
$("span#heartrate-min").text('-');
|
|
}
|
|
if(data[1]) {
|
|
$("span#heartrate-max").text(data[1]);
|
|
} else {
|
|
$("span#heartrate-max").text('-');
|
|
}
|
|
if(data[2]) {
|
|
$("span#temperature-min").text(data[2].toFixed(1));
|
|
} else {
|
|
$("span#temperature-min").text('-');
|
|
}
|
|
if(data[3]) {
|
|
$("span#temperature-max").text(data[3].toFixed(1));
|
|
} else {
|
|
$("span#temperature-max").text('-');
|
|
}
|
|
},
|
|
error: function() {
|
|
$("span#heartrate-min").text('-');
|
|
$("span#heartrate-max").text('-');
|
|
$("span#temperature-min").text('-');
|
|
$("span#temperature-max").text('-');
|
|
}
|
|
});
|
|
}
|
|
function _reload_hr_histo(){
|
|
var target = _histograms_url + "?metric=heartrate&"
|
|
target = UTILS.dict_to_query(target, _epoch_frame);
|
|
target = UTILS.fresh_query(target);
|
|
$("#histo-heartrate").attr("src", target);
|
|
};
|
|
function _reload_t_histo(){
|
|
var target = _histograms_url + "?metric=temperature&"
|
|
target = UTILS.dict_to_query(target, _epoch_frame);
|
|
target = UTILS.fresh_query(target);
|
|
$("#histo-temperature").attr("src", target);
|
|
};
|
|
function _reload_hr_graph(){
|
|
var target = _rendering_url + '?metric=heartrate&duration=' + (_range_value * 60) + '&';
|
|
target = UTILS.dict_to_query(target, _epoch_frame);
|
|
target = UTILS.fresh_query(target);
|
|
$("#graph-heartrate").attr("src", target);
|
|
};
|
|
function _reload_t_graph(){
|
|
var target = _rendering_url + '?metric=temperature&duration=' + (_range_value * 60) + '&';
|
|
target = UTILS.dict_to_query(target, _epoch_frame);
|
|
target = UTILS.fresh_query(target);
|
|
$("#graph-temperature").attr("src", target);
|
|
};
|
|
|
|
/*
|
|
refresh functions
|
|
* call reloading functions
|
|
* use timeout
|
|
*/
|
|
var _refresh_time_globals_to = null;
|
|
function _refresh_time_globals(){
|
|
if( _pause_time ){
|
|
_pause_time += 1;
|
|
}
|
|
_get_epoch_range();
|
|
_refresh_time_globals_to = setTimeout(function(){
|
|
_refresh_time_globals();
|
|
}, 1000);
|
|
};
|
|
var _refresh_delay_to = null;
|
|
function _refresh_delay(){
|
|
if( _pause_time ){
|
|
var now = new Date().getTime()/1000;
|
|
now = Math.floor(now);
|
|
$("span#delay-title").fadeIn('fast');
|
|
$("span#delay-value").fadeIn('fast');
|
|
$("span#delay-value").text(UTILS.get_display_time_s(now - _pause_time));
|
|
if( !_play ){
|
|
$("span#delay-value").fadeOut('slow');
|
|
}
|
|
}else{
|
|
$("span#delay-value").fadeOut("slow", function(){
|
|
$("span#delay-value").text("");
|
|
});
|
|
$("span#delay-title").fadeOut('slow');
|
|
};
|
|
_refresh_delay_to = setTimeout(function(){
|
|
_refresh_delay();
|
|
}, 1000);
|
|
};
|
|
var _refresh_instants_to = null;
|
|
function _refresh_instants(){
|
|
_reload_instants();
|
|
_refresh_instants_to = setTimeout(function(){
|
|
_refresh_instants();
|
|
}, 1000);
|
|
};
|
|
var _refresh_means_to = null;
|
|
function _refresh_means(){
|
|
_reload_means();
|
|
_refresh_means_to = setTimeout(function(){
|
|
_refresh_means();
|
|
}, 2000);
|
|
}
|
|
var _refresh_minmax_to = null;
|
|
function _refresh_minmax(){
|
|
_reload_minmax();
|
|
_refresh_minmax_to = setTimeout(function(){
|
|
_refresh_minmax();
|
|
}, 2000);
|
|
}
|
|
var _refresh_t_histo_to = null;
|
|
function _refresh_t_histo(){
|
|
_reload_t_histo();
|
|
_refresh_t_histo_to = setTimeout(function(){
|
|
_refresh_t_histo();
|
|
}, 3000);
|
|
}
|
|
var _refresh_hr_histo_to = null;
|
|
function _refresh_hr_histo(){
|
|
_reload_hr_histo();
|
|
_refresh_hr_histo_to = setTimeout(function(){
|
|
_refresh_hr_histo();
|
|
}, 3000);
|
|
}
|
|
var _refresh_t_graph_to = null;
|
|
function _refresh_t_graph(){
|
|
_reload_t_graph();
|
|
_refresh_t_graph_to = setTimeout(function(){
|
|
_refresh_t_graph();
|
|
}, 1000);
|
|
}
|
|
var _refresh_hr_graph_to = null;
|
|
function _refresh_hr_graph(){
|
|
_reload_hr_graph();
|
|
_refresh_hr_graph_to = setTimeout(function(){
|
|
_refresh_hr_graph();
|
|
}, 1000);
|
|
}
|
|
|
|
|
|
function refresh(arrival){
|
|
if ( arrival || !arguments.length ) {
|
|
_pause_time = null;
|
|
_refresh_delay();
|
|
}
|
|
if ( !_refresh_time_globals_to ) {
|
|
_refresh_time_globals();
|
|
_refresh_instants();
|
|
_refresh_means();
|
|
_refresh_minmax();
|
|
_refresh_t_histo();
|
|
_refresh_hr_histo();
|
|
_refresh_t_graph();
|
|
_refresh_hr_graph();
|
|
}
|
|
}
|
|
|
|
function stop_refresh(departure){
|
|
clearTimeout(_refresh_time_globals_to);
|
|
_refresh_time_globals_to = null;
|
|
clearTimeout(_refresh_instants_to);
|
|
_refresh_instants_to = null;
|
|
clearTimeout(_refresh_means_to);
|
|
_refresh_means_to = null;
|
|
clearTimeout(_refresh_minmax_to);
|
|
_refresh_minmax_to = null;
|
|
clearTimeout(_refresh_t_histo_to);
|
|
_refresh_t_histo_to = null;
|
|
clearTimeout(_refresh_hr_histo_to);
|
|
_refresh_hr_histo_to = null;
|
|
clearTimeout(_refresh_t_graph_to);
|
|
_refresh_t_graph_to = null;
|
|
clearTimeout(_refresh_hr_graph_to);
|
|
_refresh_hr_graph_to = null;
|
|
if ( departure || !arguments.length) {
|
|
clearTimeout(_refresh_delay_to);
|
|
_pause_time = null;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Reload the dashboard content only once.
|
|
Called in pause mode after modifying pause_time or range_value.
|
|
*/
|
|
function _reload_dashboard(){
|
|
/* Update display */
|
|
_get_epoch_range();
|
|
_reload_instants();
|
|
_reload_means();
|
|
_reload_minmax();
|
|
_reload_hr_histo();
|
|
_reload_t_histo();
|
|
_reload_hr_graph();
|
|
_reload_t_graph();
|
|
/* Update time range display */
|
|
$("span#time-frame-value").text(UTILS.get_display_time_min(_range_value));
|
|
/* Set date picker */
|
|
$('#datepicker-player').datepicker("setDate", new Date(_pause_time*1000));
|
|
}
|
|
|
|
$(document).ready(function(){
|
|
/*
|
|
Enhance display when server's offline
|
|
*/
|
|
$("#histo-heartrate").error(function(){
|
|
$(this).hide();
|
|
$(this).next().show();
|
|
});
|
|
$("#histo-heartrate").load(function(){
|
|
$(this).next().hide();
|
|
$(this).show();
|
|
});
|
|
$("#histo-temperature").error(function(){
|
|
$(this).hide();
|
|
$(this).next().show();
|
|
});
|
|
$("#histo-temperature").load(function(){
|
|
$(this).next().hide();
|
|
$(this).show();
|
|
});
|
|
$("#graph-heartrate").error(function(){
|
|
$(this).hide();
|
|
$(this).next().show();
|
|
});
|
|
$("#graph-heartrate").load(function(){
|
|
$(this).next().hide();
|
|
$(this).show();
|
|
});
|
|
$("#graph-temperature").error(function(){
|
|
$(this).hide();
|
|
$(this).next().show();
|
|
});
|
|
$("#graph-temperature").load(function(){
|
|
$(this).next().hide();
|
|
$(this).show();
|
|
});
|
|
$("#datepicker-player").datetimepicker({
|
|
showAnim: "fold",
|
|
showSecond: true,
|
|
timeFormat: 'HH:mm:ss',
|
|
defaultDate: new Date(),
|
|
onClose: function(date, picker){
|
|
var end = $(this).datepicker('getDate');
|
|
end = Math.floor(end.getTime()/1000);
|
|
now = Math.floor(new Date().getTime()/1000);
|
|
if (end < now) {
|
|
_pause_time = end;
|
|
}
|
|
}
|
|
});
|
|
$("span#time-frame-value").text(UTILS.get_display_time_min(_range_value));
|
|
|
|
/* Dashboard UI handler */
|
|
$("button#graph-pause").click(function() {
|
|
stop_refresh(false);
|
|
if(!_pause_time){
|
|
_pause_time = new Date().getTime()/1000;
|
|
_pause_time = Math.floor(_pause_time);
|
|
}
|
|
});
|
|
$("button#graph-play").click(function() {
|
|
refresh(delay=false);
|
|
});
|
|
$("button#graph-live").click(function() {
|
|
_pause_time = null;
|
|
if ( !_refresh_time_globals_to ) {
|
|
refresh(false);
|
|
}
|
|
});
|
|
$("button#graph-next-alert").click(function() {
|
|
var after = _pause_time || Math.floor(new Date().getTime()/1000);
|
|
after = after - _range_value * 60;
|
|
var target = _next_alert_url
|
|
target += "?after=" + after + '&';
|
|
target = UTILS.fresh_query(target);
|
|
$.ajax( {
|
|
type: 'Get',
|
|
url: target,
|
|
success: function(data) {
|
|
if ( data.length ) {
|
|
var start = Math.floor(Date.parse(data[4])/1000);
|
|
var end = data.length==6 ? new Date(data[5]) : new Date();
|
|
end = Math.floor(end/1000);
|
|
set_frame(end, start);
|
|
if ( data.length == 5 ) {
|
|
UTILS.show_message(data[2] + ' (' + gettext("Opened") +
|
|
')<br\>' + gettext("Start") + ' : ' +
|
|
$.format.date(new Date(data[4]), "dd/MM/yyyy HH:mm:ss"), 5000);
|
|
} else {
|
|
UTILS.show_message(data[2] + ' (' + gettext("Closed") +
|
|
')<br\>' + gettext("Start") + ' : ' +
|
|
$.format.date(new Date(data[4]), "dd/MM/yyyy HH:mm:ss") +
|
|
'<br\>' + gettext("End") + ' : ' +
|
|
$.format.date(new Date(data[5]), "dd/MM/yyyy HH:mm:ss"), 5000);
|
|
}
|
|
} else {
|
|
UTILS.show_message(gettext("There's no alert next."));
|
|
}
|
|
},
|
|
error: function(xhr, ajaxOptions, thrownError) {
|
|
UTILS.show_message(gettext("Database offline."));
|
|
}
|
|
});
|
|
});
|
|
/*
|
|
The previous alert is an alert before the start of the timeframe.
|
|
|
|
If an episode has started before the start of the timeframe it
|
|
set the time frame at the beginning of the episode.
|
|
The browsing of previous alerts rely on the fact that browsing is done
|
|
with the pause and the alert lookup check a datetime strictly before.
|
|
If it was not in pause, it would always reframe on the same episode.
|
|
*/
|
|
$("button#graph-previous-alert").click(function() {
|
|
var before = _pause_time || Math.floor(new Date().getTime()/1000);
|
|
before = before - _range_value * 60;
|
|
var target = _previous_alert_url
|
|
target += "?before=" + before + '&';
|
|
target = UTILS.fresh_query(target);
|
|
$.ajax( {
|
|
type: 'Get',
|
|
url: target,
|
|
success: function(data) {
|
|
if( data.length ) {
|
|
var start = Math.floor(Date.parse(data[4])/1000);
|
|
var end = data.length==6 ? new Date(data[5]) : new Date();
|
|
end = Math.floor(end/1000);
|
|
set_frame(end, start);
|
|
if( data.length == 5 ) {
|
|
UTILS.show_message(data[2] + ' (' + gettext("Opened") +
|
|
')<br\>' + gettext("Start") + ' : ' +
|
|
$.format.date(new Date(data[4]), "dd/MM/yyyy HH:mm:ss"), 5000);
|
|
} else {
|
|
UTILS.show_message(data[2] + ' (' + gettext("Closed") +
|
|
')<br\>' + gettext("Start") + ' : ' +
|
|
$.format.date(new Date(data[4]), "dd/MM/yyyy HH:mm:ss") +
|
|
'<br\>' + gettext("End") + ' : ' +
|
|
$.format.date(new Date(data[5]), "dd/MM/yyyy HH:mm:ss"), 5000);
|
|
}
|
|
} else {
|
|
UTILS.show_message(gettext("There's no alert before."));
|
|
}
|
|
},
|
|
error: function(xhr, ajaxOptions, thrownError) {
|
|
UTILS.show_message(gettext("Database offline."));
|
|
}
|
|
});
|
|
});
|
|
$("button#zoom-in").click(function() {
|
|
if( _index > 0 ) {
|
|
_index -= 1;
|
|
_range_value = _range_values[_index];
|
|
}
|
|
$("span#time-frame-value").text(UTILS.get_display_time_min(_range_value));
|
|
_reload_dashboard();
|
|
});
|
|
$("button#zoom-out").click(function() {
|
|
if( _index < _range_values.length - 1) {
|
|
_index += 1;
|
|
_range_value = _range_values[_index];
|
|
}
|
|
$("span#time-frame-value").text(UTILS.get_display_time_min(_range_value));
|
|
_reload_dashboard();
|
|
});
|
|
$("button#graph-time-last-24").click(function() {
|
|
_range_value = 1440;
|
|
_index = 10;
|
|
$("span#time-frame-value").text(UTILS.get_display_time_min(_range_value));
|
|
_reload_dashboard();
|
|
});
|
|
});
|
|
|
|
function set_frame(end, start){
|
|
var duration = end - start;
|
|
/* look for the closest range above that duration */
|
|
for( var new_index=0; new_index < _range_values.length; new_index++ ) {
|
|
var rv = _range_values[new_index] * 60
|
|
if ( rv > duration ) {
|
|
break;
|
|
}
|
|
}
|
|
_index = new_index;
|
|
_range_value = _range_values[_index];
|
|
/* Stop playing */
|
|
stop_refresh(false);
|
|
/* Time frame start at the beginning of the event */
|
|
_pause_time = start + _range_value * 60;
|
|
_reload_dashboard();
|
|
}
|
|
|
|
return {
|
|
get_range_value: get_range_value,
|
|
refresh: refresh,
|
|
stop_refresh: stop_refresh,
|
|
set_frame: set_frame
|
|
}
|
|
})();
|