hr histogram

This commit is contained in:
Gyuri Horák 2023-09-29 19:56:55 +02:00
parent b04122e3fd
commit 8d93147b39
Signed by: dyuri
GPG Key ID: 4993F07B3EAE8D38
4 changed files with 49 additions and 29 deletions

View File

@ -7,7 +7,7 @@ Trail running focused Garmin watch DataField (for myself)
- average
- current
- max
- gauge
- histogram
- pace
- current
- average

View File

@ -2,6 +2,5 @@
- pace/speed based on sport
- imperial unit support
- hr gauge => hr zone distribution
- track color => color coded by elevation gain/loss (or even vertical speed ?)
- https://github.com/loukad/vertlover

View File

@ -6,33 +6,34 @@ import Toybox.System;
class HeartRate extends WatchUi.Drawable {
hidden var hrZones as Array<Numeric>;
hidden var hrValue as Numeric;
hidden var aColor as Graphics.ColorValue | Number;
hidden var y as Numeric;
hidden var hrHist as Array<Numeric>;
hidden var hrZoneColors as Array<Numeric>;
hidden var hrTicks as Number;
hidden var y as Number;
function initialize(params as Dictionary) {
Drawable.initialize(params);
hrZones = [100, 120, 140, 160, 180, 200];
hrValue = 0.0f;
aColor = 0xFF8800;
hrZoneColors = UserProfile.getHeartRateZones(UserProfile.getCurrentSport());
hrHist = [0, 0, 0, 0, 0, 0, 0];
hrTicks = 0;
y = 64;
if (params.hasKey(:y)) {
y = params.get(:y) as Number;
}
}
function setHRZones(zones as Array<Numeric>) as Void {
hrZones = zones;
function setHRZoneColors(zoneColors as Array<Numeric>) as Void {
hrZoneColors = zoneColors;
}
function setHRValue(value as Numeric) as Void {
hrValue = value;
function setHRHist(hist as Array<Numeric>) as Void {
hrHist = hist;
}
function setHRColor(color) as Void {
aColor = color;
function setHRTicks(ticks as Number) as Void {
hrTicks = ticks;
}
function draw(dc as Dc) as Void {
@ -41,16 +42,16 @@ class HeartRate extends WatchUi.Drawable {
var width = dc.getWidth();
dc.drawLine(width * .1, 64, width * .9, 64);
var percentage = 0.0f;
var zoneNr = hrZones.size();
if (hrValue > hrZones[zoneNr - 1]) {
percentage = 1.0f;
} else if (hrValue < hrZones[0]) {
percentage = .0f;
} else {
percentage = (hrValue - hrZones[0]).toFloat() / (hrZones[zoneNr - 1] - hrZones[0]);
if (hrTicks == 0) {
return;
}
var drawFrom = 0;
for (var i = 0; i < hrHist.size(); i++) {
var drawTo = (drawFrom + width * hrHist[i].toFloat() / hrTicks).toNumber();
dc.setColor(hrZoneColors[i], Graphics.COLOR_TRANSPARENT);
dc.drawLine(drawFrom, y, drawTo, y);
drawFrom = drawTo;
}
dc.setColor(aColor, Graphics.COLOR_TRANSPARENT);
dc.drawLine(width * .1, 64, width * (.1 + .8 * percentage), 64);
}
}

View File

@ -13,6 +13,7 @@ class RepaFieldView extends WatchUi.DataField {
hidden var themeColor2 as Numeric;
hidden var themeColor3 as Numeric;
hidden var hrZones as Array<Numeric>;
hidden var hrHist as Array<Numeric>;
hidden var hrZoneColors as Array<Numeric>;
hidden var cadenceZones as Array<Numeric>;
hidden var cadenceZoneColors as Array<Numeric>;
@ -36,6 +37,7 @@ class RepaFieldView extends WatchUi.DataField {
hidden var fHrGraph;
// values
hidden var hrTicks as Number;
hidden var hrValue as Numeric;
hidden var ahrValue as Numeric;
hidden var mhrValue as Numeric;
@ -62,6 +64,8 @@ class RepaFieldView extends WatchUi.DataField {
ahrValue = 0;
mhrValue = 0;
hrZones = UserProfile.getHeartRateZones(UserProfile.getCurrentSport());
hrHist = [0, 0, 0, 0, 0, 0, 0];
hrTicks = 0;
hrZoneColors = [Graphics.COLOR_DK_GRAY, Graphics.COLOR_LT_GRAY, Graphics.COLOR_BLUE, Graphics.COLOR_GREEN, Graphics.COLOR_YELLOW, Graphics.COLOR_RED, Graphics.COLOR_DK_RED];
cadenceZones = [153, 163, 173, 183];
cadenceZoneColors = [Graphics.COLOR_RED, Graphics.COLOR_YELLOW, Graphics.COLOR_GREEN, Graphics.COLOR_BLUE, Graphics.COLOR_PURPLE];
@ -78,6 +82,19 @@ class RepaFieldView extends WatchUi.DataField {
cadence = 0;
}
function tickHr(v as Number) {
hrTicks++;
var hrzsize = hrZones.size();
for (var i = 0; i < hrzsize; i++) {
if (v < hrZones[i]) {
hrHist[i]++;
return;
}
}
// out of range
hrHist[hrzsize]++;
}
function calculateZoneColor(v as Numeric, zones as Array<Numeric>, zoneColors as Array<Numeric>) as Numeric {
for (var i = 0; i < zones.size(); i++) {
if (v < zones[i]) {
@ -134,6 +151,9 @@ class RepaFieldView extends WatchUi.DataField {
fMHr = View.findDrawableById("mhr") as Text;
fHrGraph = View.findDrawableById("HeartRate") as HeartRate;
// init fields
fHrGraph.setHRZoneColors(hrZoneColors);
// theme setup
fBgOverlay.setColor1(darken(themeColor, 4));
fBgOverlay.setColor2(darken(themeColor, 2));
@ -147,6 +167,7 @@ class RepaFieldView extends WatchUi.DataField {
function compute(info as Activity.Info) as Void {
if(info.currentHeartRate != null) {
hrValue = info.currentHeartRate as Number;
tickHr(hrValue);
} else {
hrValue = 0;
}
@ -229,9 +250,8 @@ class RepaFieldView extends WatchUi.DataField {
fMHr.setColor(darken(calculateZoneColor(mhrValue, hrZones, hrZoneColors), 2));
fMHr.setText(mhrValue.format("%d"));
if (fHrGraph != null) {
fHrGraph.setHRColor(hrColor);
fHrGraph.setHRZones(hrZones);
fHrGraph.setHRValue(hrValue);
fHrGraph.setHRHist(hrHist);
fHrGraph.setHRTicks(hrTicks);
}
// track
@ -267,7 +287,7 @@ class RepaFieldView extends WatchUi.DataField {
}
if (fTimerSec != null) {
fTimerSec.setColor(darken(timerColor, 1.5));
fTimerSec.setText(trs.format("%02d"));
fTimerSec.setText(":" + trs.format("%02d"));
}
}