mirror of https://github.com/espruino/BangleApps
Add bar graphs
parent
d709857ac7
commit
a7575ecd9a
|
@ -49,3 +49,7 @@ and run `EspruinoDocs/bin/minify.js lib.js lib.min.js`
|
|||
* Yearly view
|
||||
* Heart rate 'zone' graph
|
||||
* .. other
|
||||
|
||||
## License
|
||||
|
||||
The graphs on the web interface use Chart.js, licensed under MIT License.
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -6,6 +6,7 @@
|
|||
<div id="content"></div>
|
||||
|
||||
<script src="../../core/lib/interface.js"></script>
|
||||
<script type="module" src="chart.min.js"></script>
|
||||
<script>
|
||||
const DB_RECORD_LEN = 4;
|
||||
const DB_RECORDS_PER_HR = 6;
|
||||
|
@ -83,7 +84,8 @@ function getMonthList() {
|
|||
<td>${f.str}</td>
|
||||
<td>
|
||||
<button class="btn btn-primary" filename="${f.filename}" date="${f.date}" task="downloadcsv">Download CSV</button>
|
||||
<button class="btn btn-primary" filename="${f.filename}" date="${f.date}" task="viewmonth">View</button>
|
||||
<button class="btn btn-primary" filename="${f.filename}" date="${f.date}" monthstr="${f.str}" task="monthtable">Table</button>
|
||||
<button class="btn btn-primary" filename="${f.filename}" date="${f.date}" monthstr="${f.str}" task="monthgraph">Graph</button>
|
||||
<button class="btn btn-error" filename="${f.filename}" date="${f.date}" task="delete" style="float: right;margin-right: 5px;">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -109,6 +111,7 @@ function getMonthList() {
|
|||
var filename = button.getAttribute("filename");
|
||||
var date = button.getAttribute("date");
|
||||
if (!filename || !date) return;
|
||||
var monthstr = button.getAttribute("monthstr");
|
||||
var task = button.getAttribute("task");
|
||||
if (task=="delete") {
|
||||
Util.showModal("Deleting...");
|
||||
|
@ -120,21 +123,56 @@ function getMonthList() {
|
|||
if (task=="downloadcsv") {
|
||||
downloadHealth(filename, data => saveCSV(data, date, `Bangle.js Health ${date}`));
|
||||
}
|
||||
if (task=="viewmonth") {
|
||||
viewMonthlyData(filename, date);
|
||||
if (task=="monthtable") {
|
||||
viewMonthDataAsTable(filename, date, monthstr);
|
||||
}
|
||||
if (task=="monthgraph") {
|
||||
viewMonthDataAsGraph(filename, date, monthstr);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function viewMonthlyData(filename, date) {
|
||||
Util.showModal("Reading Health info...");
|
||||
Util.readStorage(
|
||||
function getDailyData(data) {
|
||||
var dailyData = [];
|
||||
var idx = DB_HEADER_LEN;
|
||||
for (var day = 0; day < 31; day++) {
|
||||
var dayData = {steps: 0, bpm: 0, movement: 0};
|
||||
for (var hr = 0; hr < 24; hr++) { // actually 25, see below
|
||||
for (var m = 0; m < DB_RECORDS_PER_HR; m++) {
|
||||
var h = data.substr(idx, DB_RECORD_LEN);
|
||||
if (h != "\xFF\xFF\xFF\xFF") {
|
||||
var h = {
|
||||
day : day + 1,
|
||||
hr : hr,
|
||||
min : m * 10,
|
||||
steps : (h.charCodeAt(0) << 8) | h.charCodeAt(1),
|
||||
bpm : h.charCodeAt(2),
|
||||
movement : h.charCodeAt(3)
|
||||
};
|
||||
dayData.steps += h.steps; // sum
|
||||
dayData.bpm = (dayData.bpm + h.bpm) / 2; // average
|
||||
dayData.movement += h.movement; // sum
|
||||
}
|
||||
idx += DB_RECORD_LEN;
|
||||
}
|
||||
}
|
||||
idx += DB_RECORD_LEN; // +1 because we have an extra record with totals
|
||||
// for the end of the day
|
||||
|
||||
dailyData[day + 1] = dayData;
|
||||
}
|
||||
return dailyData;
|
||||
}
|
||||
|
||||
function viewMonthDataAsTable(filename, date, monthstr) {
|
||||
Util.showModal("Reading Health info...");
|
||||
Util.readStorage(
|
||||
filename, data => {
|
||||
Util.hideModal();
|
||||
|
||||
var htmlOverview = `<h1> Month ` + date + `: </ h1>
|
||||
var htmlOverview = `<h1>` + monthstr + `</ h1>
|
||||
<button class="btn btn-primary" id="backtomonth" style="float: right;margin-right: 5px;">Back</button>
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
|
@ -147,36 +185,16 @@ Util.readStorage(
|
|||
</thead>
|
||||
<tbody>\n`;
|
||||
|
||||
var idx = DB_HEADER_LEN;
|
||||
for (var day = 0; day < 31; day++) {
|
||||
var dayData = {steps: 0, bpm: 0, movement: 0};
|
||||
for (var hr = 0; hr < 24; hr++) { // actually 25, see below
|
||||
for (var m = 0; m < DB_RECORDS_PER_HR; m++) {
|
||||
var h = data.substr(idx, DB_RECORD_LEN);
|
||||
if (h != "\xFF\xFF\xFF\xFF") {
|
||||
var h = {
|
||||
day : day + 1,
|
||||
hr : hr,
|
||||
min : m * 10,
|
||||
steps : (h.charCodeAt(0) << 8) | h.charCodeAt(1),
|
||||
bpm : h.charCodeAt(2),
|
||||
movement : h.charCodeAt(3)
|
||||
};
|
||||
dayData.steps += h.steps; // sum
|
||||
dayData.bpm = (dayData.bpm + h.bpm) / 2; // average
|
||||
dayData.movement += h.movement; // sum
|
||||
}
|
||||
idx += DB_RECORD_LEN;
|
||||
var dailyData = getDailyData(data);
|
||||
for (var i = 1; i < dailyData.length + 1; i++) {
|
||||
var dayData = dailyData[i];
|
||||
if (dayData) {
|
||||
htmlOverview += `<tr>
|
||||
<td>${i}</td>
|
||||
<td>${dayData.steps}</td>
|
||||
<td>${Math.round(dayData.bpm)}</td>
|
||||
<td>${dayData.movement}</td></tr>`
|
||||
}
|
||||
}
|
||||
idx += DB_RECORD_LEN; // +1 because we have an extra record with totals
|
||||
// for the end of the day
|
||||
|
||||
htmlOverview += `<tr>
|
||||
<td>${day + 1}</td>
|
||||
<td>${dayData.steps}</td>
|
||||
<td>${Math.round(dayData.bpm)}</td>
|
||||
<td>${dayData.movement}</td></tr>`
|
||||
}
|
||||
htmlOverview += `</tbody></table>`;
|
||||
domContent.innerHTML = htmlOverview;
|
||||
|
@ -186,6 +204,98 @@ Util.readStorage(
|
|||
});
|
||||
}
|
||||
|
||||
function viewMonthDataAsGraph(filename, date, monthstr) {
|
||||
Util.showModal("Reading Health info...");
|
||||
Util.readStorage(
|
||||
filename, data => {
|
||||
Util.hideModal();
|
||||
|
||||
var html = `<h1>` + monthstr + `</ h1>
|
||||
<button class="btn btn-primary" id="backtomonth" style="float: right;margin-right: 5px;">Back</button>
|
||||
<h2>Steps</h2>
|
||||
<canvas id="chartSteps"></canvas>
|
||||
<h2>BPM</h2>
|
||||
<canvas id="chartBPM"></canvas>
|
||||
<h2>Movement</h2>
|
||||
<canvas id="chartMovement"></canvas>`
|
||||
domContent.innerHTML = html;
|
||||
domContent.querySelector("#backtomonth").addEventListener("click",event => {
|
||||
getMonthList();
|
||||
});
|
||||
|
||||
var labels = [];
|
||||
var dataSteps = [], dataBPM = [], dataMovement = [];
|
||||
|
||||
var dailyData = getDailyData(data);
|
||||
for (var i = 1; i < dailyData.length + 1; i++) {
|
||||
var dayData = dailyData[i];
|
||||
if (dayData) {
|
||||
labels.push(i);
|
||||
dataSteps.push(dayData.steps);
|
||||
dataBPM.push(dayData.bpm);
|
||||
dataMovement.push(dayData.movement);
|
||||
}
|
||||
}
|
||||
|
||||
new Chart(document.getElementById("chartSteps"), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: '# of steps',
|
||||
data: dataSteps,
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new Chart(document.getElementById("chartBPM"), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Beats per minute',
|
||||
data: dataBPM,
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new Chart(document.getElementById("chartMovement"), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Movement',
|
||||
data: dataMovement,
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
getMonthList();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue