From aa12ed310be6f00e4e00eafe610b714da54d1e1f Mon Sep 17 00:00:00 2001 From: Andrwe Lord Weber Date: Sat, 27 Mar 2021 10:45:03 +0100 Subject: [PATCH] added graphing for HRM Signed-off-by: Andrwe Lord Weber --- apps.json | 2 +- apps/heart/ChangeLog | 1 + apps/heart/app.js | 197 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 19fa93262..5685c55c7 100644 --- a/apps.json +++ b/apps.json @@ -445,7 +445,7 @@ { "id": "heart", "name": "Heart Rate Recorder", "icon": "app.png", - "version":"0.02", + "version":"0.03", "interface": "interface.html", "description": "Application that allows you to record your heart rate. Can run in background", "tags": "tool,health,widget", diff --git a/apps/heart/ChangeLog b/apps/heart/ChangeLog index 70134af27..ad14390e1 100644 --- a/apps/heart/ChangeLog +++ b/apps/heart/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Don't overwrite existing settings on app update Clean up recordings on app removal +0.03: added graphing feature of 164 latest measurements diff --git a/apps/heart/app.js b/apps/heart/app.js index 366a1068d..5d2008014 100644 --- a/apps/heart/app.js +++ b/apps/heart/app.js @@ -1,8 +1,25 @@ +const GraphXZero = 40; +const GraphYZero = 200; +const GraphY100 = 80; + +const GraphMarkerOffset = 5; +const MaxValueCount = 164; +const GraphXMax = GraphXZero + MaxValueCount; + Bangle.loadWidgets(); Bangle.drawWidgets(); var settings = require("Storage").readJSON("heart.json",1)||{}; +var globalSettings = require('Storage').readJSON('setting.json', true) || {timezone: 0}; +require('DateExt').locale({ + str: "0D.0M. 0h:0m", + offset: [ + globalSettings.timezone * 60, + globalSettings.timezone * 60 + ] +}); + function getFileNbr(n) { return ".heart"+n.toString(36); } @@ -36,6 +53,7 @@ function showMainMenu() { } }, 'View Records': viewRecords, + 'Graph Records': graphRecords, '< Back': ()=>{load();} }; return E.showMenu(mainMenu); @@ -97,4 +115,183 @@ function viewRecord(n) { return E.showMenu(menu); } +function graphRecords() { + const menu = { + '': { 'title': 'Heart Records' } + }; + var found = false; + for (var n=0;n<36;n++) { + var f = require("Storage").open(getFileNbr(n),"r"); + var line = f.readLine(); + if (line!==undefined) { + menu["#"+n+" "+Date(line.split(",")[0]*1000).as().str] = graphRecord.bind(null,n); + found = true; + } + } + if (!found) + menu["No Records Found"] = function(){}; + menu['< Back'] = showMainMenu; + return E.showMenu(menu); +} + +// based on batchart +function renderHomeIcon() { + //Home for Btn2 + g.setColor(1, 1, 1); + g.drawLine(220, 118, 227, 110); + g.drawLine(227, 110, 234, 118); + + g.drawPoly([222,117,222,125,232,125,232,117], false); + g.drawRect(226,120,229,125); +} + +function renderChart() { + // Left Y axis (Battery) + g.setColor(1, 1, 0); + g.drawLine(GraphXZero, GraphYZero + GraphMarkerOffset, GraphXZero, GraphY100); + + g.setFontAlign(1, -1, 0); + g.drawString("150", 35, GraphY100 - GraphMarkerOffset); + g.drawLine(GraphXZero - GraphMarkerOffset, GraphY100, GraphXZero, GraphY100); + + g.drawString("125", 35, GraphYZero - 110 - GraphMarkerOffset); + g.drawLine(GraphXZero - GraphMarkerOffset, 150, GraphXZero, 150); + + g.drawString("100", 35, GraphYZero - 100 - GraphMarkerOffset); + g.drawLine(GraphXZero - GraphMarkerOffset, 150, GraphXZero, 150); + + g.drawString("90", 35, GraphYZero - 90 - GraphMarkerOffset); + g.drawLine(GraphXZero - GraphMarkerOffset, 150, GraphXZero, 150); + + g.drawString("80", 35, GraphYZero - 70 - GraphMarkerOffset); + g.drawLine(GraphXZero - GraphMarkerOffset, 150, GraphXZero, 150); + + g.drawString("70", 35, GraphYZero - 50 - GraphMarkerOffset); + g.drawLine(GraphXZero - GraphMarkerOffset, 150, GraphXZero, 150); + + g.drawString("60", 35, GraphYZero - 30 - GraphMarkerOffset); + g.drawLine(GraphXZero - GraphMarkerOffset, 150, GraphXZero, 150); + + g.drawString("50", 35, GraphYZero - 20 - GraphMarkerOffset); + g.drawLine(GraphXZero - GraphMarkerOffset, 150, GraphXZero, 150); + + g.drawString("40", 35, GraphYZero - 10 - GraphMarkerOffset); + g.drawLine(GraphXZero - GraphMarkerOffset, 150, GraphXZero, 150); + + g.drawString("30", 35, GraphYZero - GraphMarkerOffset); + + g.setColor(1, 1, 1); + g.drawLine(GraphXZero - GraphMarkerOffset, GraphYZero, GraphXMax + GraphMarkerOffset, GraphYZero); + + console.log("Finished drawing chart"); +} + +// as drawing starts at 30 HRM decreasing measrure by 30 +// recalculate for range 110-150 as only 20 pixels are available +function getY(measure) { + positionY = GraphYZero - measure + 30; + if (100 < measure < 150) { + positionY = GraphYZero - ( 100 + Math.round((measure - 100)/2) ) + 30; + g.setColor(1, 0, 0); + } else if (60 < measrure < 100) { + positionY = GraphYZero - ( 30 + Math.round((measure - 30)/2) ) + 30; + g.setColor(0, 1, 0); + } + if (positionY > GraphYZero) { + positionY = GraphYZero; + g.setColor(1, 0, 0); + } + if (positionY < GraphY100) { + positionY = GraphY100; + g.setColor(1, 0, 0); + } + return positionY; +} + +function stop() { + E.showMenu(); + load(); +} + +function graphRecord(n) { + E.showMenu({'': 'Heart Record '+n}); + E.showMessage( + "Loading Data ...\n\nMay take a while,\nwill vibrate\nwhen done.", + 'Heart Record '+n + ); + g.setFont("Vector", 10); + + var lastPixel; + var lineCount = 0; + var positionX = GraphXZero; + var positionY = GraphYZero; + var startLine = 1; + var tempCount = 0; + var f = require("Storage").open(getFileNbr(n),"r"); + var line = f.readLine(); + var times = Array(2); + console.log("Counting lines"); + while (line !== undefined) { + lineCount++; + line = f.readLine(); + } + console.log(`Line count: ${lineCount}`); + if (lineCount > MaxValueCount) { + startLine = lineCount - MaxValueCount; + } + console.log(`start: ${startLine}`); + + f = require("Storage").open(getFileNbr(n),"r"); + line = f.readLine(); + while (line !== undefined) { + currentLine = line; + line = f.readLine(); + tempCount++; + if (tempCount == startLine) { + g.clear(); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + renderHomeIcon(); + renderChart(); + } else if (tempCount > startLine) { + positionX++; + if (parseInt(currentLine.split(",")[2]) >= 70) { + g.setColor(1, 1, 1); + oldPositionY = positionY; + positionY = getY(parseInt(currentLine.split(",")[1])); + if (times[0] === undefined) { + times[0] = parseInt(currentLine.split(",")[0]); + } + if (tempCount == startLine + 1) { + g.setPixel(positionX, positionY); + } else { + g.drawLine(positionX - 1, oldPositionY, positionX, positionY); + times[1] = parseInt(currentLine.split(",")[0]); + } + } + } + g.flip(); + } + + g.setColor(1, 1, 0); + g.setFont("Vector", 10); + console.log('start: ' + times[0]); + console.log('end: ' + times[1]); + if (times[0] !== undefined) { + g.setFontAlign(-1, -1, 0); + var startdate = new Date(times[0]*1000); + g.drawString(startdate.local().as("0h:0m").str, 15, GraphYZero + 12); + } + if (times[1] !== undefined) { + g.setFontAlign(1, -1, 0); + var enddate = new Date(times[1]*1000); + g.drawString(enddate.local().as().str, GraphXMax, GraphYZero + 12); + } + console.log("Finished rendering data"); + Bangle.buzz(200, 0.3); + setWatch(stop, BTN2, {edge:"falling", debounce:50, repeat:false}); +} + showMainMenu(); + +// vim: et ts=2 sw=2