Skip to content
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
4 changes: 4 additions & 0 deletions pages/components/charts.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ <h3 id="weight-chart-title" class="chart-title">Gewicht</h3>
<p class="display-info"></p>
<div id="weight_chart" class="detail-chart"></div>

<h3 id="delta-chart-title" class="chart-title">Gewichtsdelta</h3>
<p class="delta-display-info"></p>
<div id="delta_chart" class="detail-chart"></div>

<h3 id="temperature-chart-title" class="chart-title">Temperatur</h3>
<p class="display-info"></p>
<div id="temp_chart" class="detail-chart"></div>
Expand Down
9 changes: 9 additions & 0 deletions pages/components/modals.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ <h4>Zeitraum ändern <span class="badge red white-text">Experimentelle Funktion<
<input id="from-date-input" type="text" class="datepicker" placeholder="Alle Daten von ...">
<b>Datum an dem die angezeigten Daten enden sollen:</b>
<input id="to-date-input" type="text" class="datepicker" placeholder="Alle Daten bis ...">
<p>
<label>
<input id="daterange-save-to" type="checkbox" class="filled-in" checked="checked" />
<span>Enddatum für den nächsten Besuch speichern</span>
</label>
</p>

<b>Zeitspanne für die Berechnung von Delta Werten (in Minuten):</b>
<input id="delta-span-input" type="number" class="input" placeholder="Standardmäßig 1 Tag also 1440">

<p><b>Warum sehen die Diagramme bei einem Zeitraum größer als 10 Tage anders aus?</b> Die Daten werden, besonders bei großen Datenmengen (über 10 Tage), dadurch reduziert, dass ein Durchschnittswert für jeden Tag gebildet wird. Da es insgesamt 48 gemessene Datensätze pro Tag gibt, wäre das Diagramm ansonsten schwer bis kaum ablesbar.
So sind auch bei großen Zeiträumen langfristige Tendenzen ablesbar. Die unreduzierten Daten sind per API abrufbar.
Expand Down
8 changes: 7 additions & 1 deletion public/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,13 @@ footer {
}
.display-info {
text-align: center;
margin-bottom: 0;
margin-bottom: 0%;
}

#reload-button {
position: fixed;
bottom: 100px;
right: 23px;
}

/* Credit: https://stackoverflow.com/a/55788640/18085012 */
Expand Down
84 changes: 55 additions & 29 deletions public/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,42 @@ document.addEventListener('DOMContentLoaded', async () => {
M.Dropdown.init(document.querySelectorAll('.dropdown-trigger'), {});
M.ScrollSpy.init(document.querySelectorAll('.scrollspy'), {});

let fromDate = window.localStorage.getItem("daterange-from");
let toDate = window.localStorage.getItem("daterange-to");
let deltaTimespan = window.localStorage.getItem('delta-timespan');

if (fromDate === null || toDate === null || deltaTimespan === null) {
console.warn("Cleared localStorage because one or more saved values are not initialized.");
window.localStorage.clear();
// If no date range is set, use the last 7 days
fromDate = luxon.DateTime.now().minus({ days: 7 }).toJSDate();
toDate = luxon.DateTime.now().toJSDate();
} else {
fromDate = luxon.DateTime.fromISO(fromDate).toJSDate();
toDate = luxon.DateTime.fromISO(toDate).toJSDate();
}
// Set daterange save checkbox to setting saved in localStorage
document.getElementById("daterange-save-to").checked = window.localStorage.getItem("daterange-save-to") === "1";
if (window.localStorage.getItem("daterange-save-to") === "0") {
toDate = luxon.DateTime.now().toJSDate();
}

datePickerFrom = M.Datepicker.init(document.getElementById('from-date-input'), {
minDate: luxon.DateTime.now().minus({ years: 1 }).toJSDate(),
//minDate: luxon.DateTime.now().minus({ years: 1 }).toJSDate(),
maxDate: luxon.DateTime.now().toJSDate(),
defaultDate: luxon.DateTime.now().minus({ days: 4 }).toJSDate(),
defaultDate: fromDate,
setDefaultDate: true
});

datePickerTo = M.Datepicker.init(document.getElementById('to-date-input'), {
minDate: luxon.DateTime.now().minus({ years: 1 }).toJSDate(),
//minDate: luxon.DateTime.now().minus({ years: 1 }).toJSDate(),
maxDate: luxon.DateTime.now().toJSDate(),
defaultDate: luxon.DateTime.now().toJSDate(),
defaultDate: toDate,
setDefaultDate: true
});

document.getElementById("delta-span-input").value = window.localStorage.getItem("delta-timespan");

// Get data from the last 24 hours and populate beeLogger.currentData
var data = await beeLogger.getCurrentData()
.catch(err => errorHandler('current-data', err));
Expand All @@ -47,7 +69,7 @@ document.addEventListener('DOMContentLoaded', async () => {
errorHandler('current-data', 204);
}

await updateCurrentData(data);
//await updateCurrentData(data); // Handled by applyDateRange()

// Set up background task for keeping the 'measured' date up-to-date
setInterval(() => {
Expand All @@ -68,22 +90,16 @@ document.addEventListener('DOMContentLoaded', async () => {
// Load charts when the library is ready
await createChartsForDateRange();

checkbox = document.getElementById('scale-switch');
let checkbox = document.getElementById('scale-switch');

checkbox.addEventListener('change', async (e) => {
let fromDate = luxon.DateTime.fromJSDate(datePickerFrom.date);
let toDate = luxon.DateTime.fromJSDate(datePickerTo.date);

// Calculate difference between dates
let diff = fromDate.diff(toDate, 'days');
diff = Math.abs(diff.toObject().days);

// Redraw chart when the state of the switch changed
element = document.getElementById('scale-switch');
window.localStorage.setItem("separate-weight", element.checked ? '1' : '0');
await drawCompareChart(beeLogger.cachedData['data'], element.checked);
});

checkbox.checked = false;
checkbox.checked = window.localStorage.getItem("separate-weight") == true;

// Timeout function in variable to later be able to stop it again
// when the window was resized again
Expand Down Expand Up @@ -116,7 +132,12 @@ function applyDateRange() {

var fromDate = luxon.DateTime.fromJSDate(datePickerFrom.date);
var toDate = luxon.DateTime.fromJSDate(datePickerTo.date);


window.localStorage.setItem('daterange-from', fromDate.toISO());
window.localStorage.setItem('daterange-to', toDate.toISO());
window.localStorage.setItem('daterange-save-to', document.getElementById("daterange-save-to").checked ? '1' : '0');
window.localStorage.setItem('delta-timespan', document.getElementById("delta-span-input").value)

// Calculate difference between dates
var diff = fromDate.diff(toDate, 'days');
diff = Math.abs(diff.toObject().days);
Expand Down Expand Up @@ -147,7 +168,8 @@ function applyDateRange() {
reject();
return;
}


await updateCurrentData(dataObject);
await drawCharts(data);
resolve();
});
Expand Down Expand Up @@ -211,19 +233,23 @@ async function updateCurrentData(data) {
* @returns {string} HTML containing the weight delta (in a fitting color)
*/
function getWeightDeltaString(data) {
// Get weight from most recent record
let weightCurrent = data[Object.keys(data).length - 1].weight;
// Get weight from the record in the middle of the array (measured approximately 24 hours ago)
// This is done in case there is no record from *exactly* 24 hours ago
let weightStartIndex = Math.floor(((Object.keys(data).length - 1) / 2))
let weightStart = data[weightStartIndex].weight;
// Calculate the delta of the current and start weight
let weightDelta = Number(weightCurrent) - Number(weightStart);
// Limit float to 2 decimal places
weightDelta = weightDelta.toFixed(3);
// Format HTML string with green color for weight growth and red color for weight decline
let weightDeltaString = weightDelta >= 0 ? `<p style='color: #8aff6b;'>+${weightDelta} g</p>` : `<p style='color: #fe7373;'>${weightDelta} g</p>`;
return weightDeltaString;
let timespan = document.getElementById("delta-span-input").value * 60000; // in ms
if (timespan === undefined || timespan == null || timespan === 0) {
timespan = 86400000; // 24h
}
let i = Object.keys(data).length - 1;
let newer_measured = new Date(data[i].measured);
let newer_weight = data[i].weight;

while (newer_measured.getTime() - Date.parse(data[i].measured) < timespan && i > 0) {
i--;
}
let older_weight = data[i].weight;

let weightDelta = newer_weight - older_weight;
weightDelta = weightDelta.toFixed(2);

return weightDelta >= 0 ? `<p style='color: #8aff6b;'>+${weightDelta}</p>` : `<p style='color: #fe7373;'>${weightDelta}</p>`;
}

/**
Expand Down
70 changes: 68 additions & 2 deletions public/js/charts.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ async function drawCharts(data) {

data = data['data'];

// Try to get the time interval between records to use for delta graph.
let deltaGraphInterval = document.getElementById("delta-span-input").value;

// If none or invalid interval is specified, use 24 hours by default (in ms).
if (typeof deltaGraphInterval !== 'string' || deltaGraphInterval === '' || deltaGraphInterval === '0' ) {
deltaGraphInterval = 86400000;
} else {
// Turn input string into number and convert to milliseconds.
deltaGraphInterval = parseInt(deltaGraphInterval) * 60000;
}

if (data == undefined || data == [] || Object.keys(data) == 0) {
errorHandler('charts', 204);
return;
Expand All @@ -43,9 +54,10 @@ async function drawCharts(data) {

// document.getElementById('charts').classList.remove('hide');

await drawCompareChart(data, false);
await drawCompareChart(data, window.localStorage.getItem("separate-weight") == true);
await drawTempChart(data);
await drawWeightChart(data);
await drawDeltaChart(data, deltaGraphInterval);
await drawHumidityChart(data);

document.getElementById('beelogger-daterange-icon').classList.remove('hide');
Expand Down Expand Up @@ -140,7 +152,7 @@ async function drawTempChart(data) {
}

/**
* Generates and renders the weight chart on the page.
* Generates and renders the weight delta chart on the page.
*
* @param {Array} data Array containing the data records that the graph should be generated from
*/
Expand Down Expand Up @@ -172,6 +184,60 @@ async function drawWeightChart(data) {
});
}

/**
* Generates and renders the weight delta chart on the page.
*
* @param {Array} data Array containing the data records that the graph should be generated from
* @param {number} interval The amount of time between records used for delta calculation (in between will be ignored)
*/
async function drawDeltaChart(data, interval) {
// Create array to visualize as a chart.
let deltaData = [['Gemessen', 'Delta (g)']];

// Start with newest record.
let recordIndex = Object.keys(data).length - 1;

// Go through each record.
while (recordIndex !== 0) {
let newerRecord = data[recordIndex];
let newerRecordTimestamp = new Date(newerRecord.measured);
let newerWeight = newerRecord.weight;

// Go further in the dataset until the set interval is reached again.
while (newerRecordTimestamp.getTime() - Date.parse(data[recordIndex].measured) < interval && recordIndex > 0) {
recordIndex--;
}

// The weight of the record one interval further.
let olderWeight = data[recordIndex].weight;

// Calculate the difference between the two weights.
let weightDelta = newerWeight - olderWeight;

// Push timestamp and weight data to visualization data array.
deltaData.push([newerRecordTimestamp, weightDelta]);
}

let weightDataTable = google.visualization.arrayToDataTable(deltaData);
let weightChart = new google.visualization.LineChart(document.getElementById('delta_chart'));

weightChart.draw(weightDataTable, {
height: '100%',
lineWidth: 2,
colors: ['black'],
chartArea: {
left: '10%',
top: '10%',
right: '10%',
width: '100%',
height: '70%'
},
legend: {
position: 'bottom'
},
});
}

/**
* Generates and renders the humidity chart on the page.
*
Expand Down