Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable clock views #5625

Merged
merged 10 commits into from
Jun 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,29 @@ To learn more about the Nightscout API, visit https://YOUR-SITE.com/api-docs/ or

### Views

There are a few alternate web views available from the main menu that display a simplified BG stream. (If you launch one of these in a fullscreen view in iOS, you can use a left-to-right swipe gesture to exit the view.)
Nightscout allows to create custom, simplified views using a predefined set of elements. This option is available under `[+]` link in the main menu.

List of available items:
* `SGV` - Sensor Glucose Value
* `SGV age` - time since the last SGV read
* `SGV delta` - change of SGV in the last 5 minutes
* `Trend arrow` - icon of the SG trend
* `Time` - current time
* `Line break` - invisible item that will move following items to the next line (by default all are showing on the same level)

All visible items have `Size` property which allows to customize the view even more. Also, all items may appear multiple times on the view.

Apart from adding items, it is possible to customize other aspects of the views, like selecting `Color` or `Black` background. The first one will indicate current BG threshold (green = in range; blue = below range; yellow = above range; red = urgent below/above).
`Show SGV age` option will make `SGV age` item appear `Always` or only if the predefined threshold is reached: `Only after threshold`. Breaching `SGV age threshold` will also make `Color` background turn grey and strike through `SGV`.
`Clock view configurator` will generate an URL (available under `Open my clock view!` link) that could be bookmarked.

There are a few default views available from the main menu:
* `Clock` - Shows current BG, trend arrow, and time of day. Grey text on a black background.
* `Color` - Shows current BG and trend arrow. White text on a background that changes color to indicate current BG threshold (green = in range; blue = below range; yellow = above range; red = urgent below/above). Set `SHOW_CLOCK_DELTA` to `true` to show BG change in the last 5 minutes, set `SHOW_CLOCK_LAST_TIME` to `true` to always show BG age.
* `Color` - Shows current BG and trend arrow. White text on a color background.
* `Simple` - Shows current BG. Grey text on a black background.

If you launch one of these views in a fullscreen view in iOS, you can use a left-to-right swipe gesture to exit the view.

### Split View

Some users will need easy access to multiple Nightscout views at the same time. We have a special view for this case, accessed on /split path on your Nightscout URL. The view supports any number of sites between 1 to 8 way split, where the content for the screen can be loaded from multiple Nightscout instances. Note you still need to host separate instances for each Nightscout being monitored including the one that hosts the split view page - these variables only add the ability to load multiple views into one browser page. To set the URLs from which the content is loaded, set:
Expand Down
180 changes: 104 additions & 76 deletions lib/client/clock-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var client = {};

client.settings = browserSettings(client, window.serverSettings, $);

// console.log('settings', client.settings);
//console.log('settings', client.settings);
// client.settings now contains all settings

client.query = function query () {
Expand All @@ -20,7 +20,7 @@ client.query = function query () {
});

var secret = localStorage.getItem('apisecrethash');
var src = '/api/v1/entries.json?count=3&t=' + new Date().getTime();
var src = '/api/v1/entries.json?find[type]=sgv&count=3&t=' + new Date().getTime();

if (secret) {
src += '&secret=' + secret;
Expand All @@ -39,6 +39,7 @@ client.render = function render (xhr) {
let rec;
let delta;

// Get SGV, calculate DELTA
xhr.forEach(element => {
if (element.sgv && !rec) {
rec = element;
Expand All @@ -49,28 +50,65 @@ client.render = function render (xhr) {
});

let $errorMessage = $('#errorMessage');
let $inner = $('#inner');

// If no one measured value found => show "-?-"
if (!rec) {
if (!$errorMessage.length) {
$('#arrowDiv').append('<div id="errorMessage" title="No data found in DB">-?-</div>');
$('#arrow').hide();
$inner.after('<div id="errorMessage" title="No data found in DB">-?-</div>')
} else {
$errorMessage.show();
}
$inner.hide();
return;
} else {
$errorMessage.length && $errorMessage.hide();
$('#arrow').show();
$inner.show();
}

//Parse face parameters
let face = $inner.data('face').toLowerCase();

// Backward compatible
if (face === 'clock-color') {
face = 'c' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg40-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar30-nl-ag6';
}
else if (face === 'clock') {
face = 'bn0-sg40';
}
else if (face === 'bgclock') {
face = 'bn0-sg30-ar18-nl-nl-tm26';
}
else if (face === 'config') {
face = $inner.attr('data-face-config');
$inner.empty();
}

let faceParams = face.split('-');
let bgColor = false;
let staleMinutes = 13;
let alwaysShowTime = false;

let clockCreated = ($inner.children().length > 0);

for (let param in faceParams) {
if (param === '0') {
bgColor = (faceParams[param].substr(0, 1) === 'c'); // do we want colorful background?
alwaysShowTime = (faceParams[param].substr(1, 1) === 'y'); // always show "stale time" text?
staleMinutes = (faceParams[param].substr(2,2) - 0 >= 0) ? faceParams[param].substr(2,2) : 13; // threshold value (0=never)
} else if (!clockCreated){
let div = '<div class="' + faceParams[param].substr(0,2) + '"' + ((faceParams[param].substr(2,2) - 0 > 0) ? ' style="' + ((faceParams[param].substr(0,2) === 'ar') ? 'height' : 'font-size') + ':' + faceParams[param].substr(2,2) + 'vmin"' : '') + '></div>';
$inner.append(div);
}
}

let last = new Date(rec.date);
let now = new Date();

// Convert BG to mmol/L if necessary.
let displayValue;
let deltaDisplayValue;

if (window.serverSettings.settings.units === 'mmol') {
var displayValue = window.Nightscout.units.mgdlToMMOL(rec.sgv);
var deltaDisplayValue = window.Nightscout.units.mgdlToMMOL(delta);
displayValue = window.Nightscout.units.mgdlToMMOL(rec.sgv);
deltaDisplayValue = window.Nightscout.units.mgdlToMMOL(delta);
} else {
displayValue = rec.sgv;
deltaDisplayValue = Math.round(delta);
Expand All @@ -80,18 +118,8 @@ client.render = function render (xhr) {
deltaDisplayValue = '+' + deltaDisplayValue;
}

// Insert the BG value text.
$('#bgnow').html(displayValue);

// Insert the trend arrow.
$('#arrow').attr('src', '/images/' + (!rec.direction || rec.direction === 'NOT COMPUTABLE' ? 'NONE' : rec.direction) + '.svg');

// Time before data considered stale.
let staleMinutes = 13;
let threshold = 1000 * 60 * staleMinutes;

// Toggle stale if necessary.
$('#bgnow').toggleClass('stale', (now - last > threshold));
// Insert the delta value text.
$('.dt').html(deltaDisplayValue);

// Generate and insert the clock.
let timeDivisor = parseInt(client.settings.timeFormat ? client.settings.timeFormat : 12, 10);
Expand All @@ -105,51 +133,24 @@ client.render = function render (xhr) {
}
let m = today.getMinutes();
if (m < 10) m = "0" + m;
$('#clock').text(h + ":" + m);

/* global clockFace */
if (clockFace === 'clock-color') {

var bgHigh = window.serverSettings.settings.thresholds.bgHigh;
var bgLow = window.serverSettings.settings.thresholds.bgLow;
var bgTargetBottom = window.serverSettings.settings.thresholds.bgTargetBottom;
var bgTargetTop = window.serverSettings.settings.thresholds.bgTargetTop;
$('.tm').html(h + ":" + m);

var bgNum = parseFloat(rec.sgv);
// Color background
if (bgColor) {

// These are the particular shades of red, yellow, green, and blue.
var red = 'rgba(213,9,21,1)';
var yellow = 'rgba(234,168,0,1)';
var green = 'rgba(134,207,70,1)';
var blue = 'rgba(78,143,207,1)';

var elapsedMins = Math.round(((now - last) / 1000) / 60);

// Insert the BG stale time text.
let staleTimeText;
if (elapsedMins == 0) {
staleTimeText = 'Just now';
}
else if (elapsedMins == 1) {
staleTimeText = '1 minute ago';
}
else {
staleTimeText = elapsedMins + ' minutes ago';
}
$('#staleTime').text(staleTimeText);

// Force NS to always show 'x minutes ago'
if (window.serverSettings.settings.showClockLastTime) {
$('#staleTime').css('display', 'block');
}
let red = 'rgba(213,9,21,1)';
let yellow = 'rgba(234,168,0,1)';
let green = 'rgba(134,207,70,1)';
let blue = 'rgba(78,143,207,1)';

// Insert the delta value text.
$('#delta').html(deltaDisplayValue);
// Threshold values
let bgHigh = client.settings.thresholds.bgHigh;
let bgLow = client.settings.thresholds.bgLow;
let bgTargetBottom = client.settings.thresholds.bgTargetBottom;
let bgTargetTop = client.settings.thresholds.bgTargetTop;

// Show delta
if (window.serverSettings.settings.showClockDelta) {
$('#delta').css('display', 'inline-block');
}
let bgNum = parseFloat(rec.sgv);

// Threshold background coloring.
if (bgNum < bgLow) {
Expand All @@ -168,25 +169,52 @@ client.render = function render (xhr) {
$('body').css('background-color', red);
}

// Restyle body bg, and make the "x minutes ago" visible too.
if (now - last > threshold) {
$('body').css('background-color', 'grey');
$('body').css('color', 'black');
$('#arrow').css('filter', 'brightness(0%)');
}
else {
$('body').css('background-color', 'black');
}

if (!window.serverSettings.settings.showClockLastTime) {
$('#staleTime').css('display', 'block');
}
// Time before data considered stale.
let threshold = 1000 * 60 * staleMinutes;

} else {
$('body').css('color', 'white');
$('#arrow').css('filter', 'brightness(100%)');
let last = new Date(rec.date);
let now = new Date();

let elapsedMins = Math.round(((now - last) / 1000) / 60);

let thresholdReached = (now - last > threshold) && threshold > 0;

if (!window.serverSettings.settings.showClockLastTime) {
$('#staleTime').css('display', 'none');
}
// Insert the BG value text, toggle stale if necessary.
$('.sg').toggleClass('stale', thresholdReached).html(displayValue);

if (thresholdReached || alwaysShowTime) {
let staleTimeText;
if (elapsedMins === 0) {
staleTimeText = 'Just now';
}
else if (elapsedMins === 1) {
staleTimeText = '1 minute ago';
}
else {
staleTimeText = elapsedMins + ' minutes ago';
}

$('.ag').html(staleTimeText);
}
else {
$('.ag').html('');
}

// Insert the trend arrow.
let arrow = $('<img alt="arrow">').attr('src', '/images/' + (!rec.direction || rec.direction === 'NOT COMPUTABLE' ? 'NONE' : rec.direction) + '.svg');

// Restyle body bg
if (thresholdReached) {
$('body').css('background-color', 'grey').css('color', 'black');
$('.ar').css('filter', 'brightness(0%)').html(arrow);
} else {
$('body').css('color', bgColor ? 'white' : 'grey');
$('.ar').css('filter', bgColor ? 'brightness(100%)' : 'brightness(50%)').html(arrow);
}
};

Expand Down
2 changes: 1 addition & 1 deletion lib/server/clocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function clockviews() {
const face = req.params.face;
console.log('Clockface requested:', face);

res.render('shared.html', {
res.render('clock.html', {
face,
locals
});
Expand Down
28 changes: 0 additions & 28 deletions views/clockviews/bgclock.css

This file was deleted.

32 changes: 0 additions & 32 deletions views/clockviews/clock-color.css

This file was deleted.

39 changes: 39 additions & 0 deletions views/clockviews/clock-config.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#config-form {
position: fixed;
top: 10px;
left: 10px;
width: 250px;
min-width: 220px;
background: white;
color: black;
opacity: 0.8;
padding: 1%;
font-size: 10px;
}
#config-form p {
margin: 15px;
text-align: left;
}
input.elmt {
width: 120px;
}
select {
width: 100%;
}
#facename {
font-size: 7px;
}
#clocklink {
font-size: 18px;
}
#clocklink:link, #clocklink:visited {
background-color: #f44336;
color: white;
padding: 14px 25px;
text-align: center;
text-decoration: none;
display: inline-block;
}
#clocklink:hover, #clocklink:active {
background-color: red;
}
Loading