├── .gitignore
├── Screenshot Fenix3.jpg
├── Screenshot Round Watch.jpg
├── manifest.xml
├── resources
├── images
│ ├── launcher_icon.png
│ └── monkey.png
└── resources.xml
└── source
├── HRCirclesApp.mc
└── HRCirclesView.mc
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | bin/HRCircles.prg.debug.xml
3 |
4 | bin/HRCircles.iq
5 |
6 | bin/HRCircles.prg
7 |
--------------------------------------------------------------------------------
/Screenshot Fenix3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anderssonfilip/HRCircles/30954697b9ef85ac8ce589f28babf49e9a7266c9/Screenshot Fenix3.jpg
--------------------------------------------------------------------------------
/Screenshot Round Watch.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anderssonfilip/HRCircles/30954697b9ef85ac8ce589f28babf49e9a7266c9/Screenshot Round Watch.jpg
--------------------------------------------------------------------------------
/manifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | eng
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/resources/images/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anderssonfilip/HRCircles/30954697b9ef85ac8ce589f28babf49e9a7266c9/resources/images/launcher_icon.png
--------------------------------------------------------------------------------
/resources/images/monkey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anderssonfilip/HRCircles/30954697b9ef85ac8ce589f28babf49e9a7266c9/resources/images/monkey.png
--------------------------------------------------------------------------------
/resources/resources.xml:
--------------------------------------------------------------------------------
1 |
2 | HRZones
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source/HRCirclesApp.mc:
--------------------------------------------------------------------------------
1 | using Toybox.Application as App;
2 |
3 | class HRCirclesApp extends App.AppBase {
4 |
5 | //! onStart() is called on application start up
6 | function onStart() {
7 | }
8 |
9 | //! onStop() is called when your application is exiting
10 | function onStop() {
11 | }
12 |
13 | //! Return the initial view of your application here
14 | function getInitialView() {
15 | return [ new HRCirclesView() ];
16 |
17 |
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/source/HRCirclesView.mc:
--------------------------------------------------------------------------------
1 | using Toybox.WatchUi as Ui;
2 | using Toybox.Graphics as Gfx;
3 | using Toybox.UserProfile as User;
4 | using Toybox.Math as Math;
5 |
6 | class HRCirclesView extends Ui.DataField {
7 |
8 | const age = Time.Gregorian.info(Time.now(), Time.FORMAT_SHORT).year - User.getProfile().birthYear.toNumber();
9 |
10 | const maxHR = 220 - age;
11 | var hr = 0;
12 | const restingHR = User.getProfile().restingHeartRate.toNumber();
13 | const hrr = maxHR - restingHR;
14 |
15 | var timeInZone = new [5];
16 | var zones = [48, 58, 67, 77, 88]; // percentages
17 | var timeInZone = [0, 0, 0, 0, 0];
18 |
19 | //! Rendering Constants
20 | const BAR_THICKNESS = 7;
21 | const ARC_MAX_ITERS = 300;
22 |
23 | var numberColor = Gfx.COLOR_WHITE;
24 |
25 | const fullCircle = Math.PI * 2;
26 |
27 | function initialize() {
28 |
29 | // convert to beats
30 | for(var i = 0; i < zones.size(); i++){
31 | zones[i] = ((zones[i] / 100f) * hrr).toNumber();
32 | }
33 | }
34 |
35 | //! The given info object contains all the current workout information.
36 | //! Calculate a value and return it in this method.
37 | function compute(info) {
38 |
39 | if(info.currentHeartRate == null) // no activity
40 | {
41 | return;
42 | }
43 |
44 | hr = info.currentHeartRate - restingHR;
45 |
46 | if(hr > zones[0] && hr <= zones[1])
47 | {
48 | timeInZone[0] += 1;
49 | numberColor = Gfx.COLOR_DK_GREEN;
50 | }
51 | else if(hr > zones[1] && hr <= zones[2])
52 | {
53 | timeInZone[1] += 1;
54 | numberColor = Gfx.COLOR_GREEN;
55 | }
56 | else if(hr > zones[2] && hr <= zones[3])
57 | {
58 | timeInZone[2] += 1;
59 | numberColor = Gfx.COLOR_YELLOW;
60 | }
61 | else if(hr > zones[3] && hr <= zones[4])
62 | {
63 | timeInZone[3] += 1;
64 | numberColor = Gfx.COLOR_ORANGE;
65 | }
66 | else if(hr > zones[4])
67 | {
68 | timeInZone[4] += 1;
69 | numberColor = Gfx.COLOR_RED;
70 | }
71 |
72 | return info.currentHeartRate;
73 | }
74 |
75 | function onUpdate(dc){
76 |
77 | if(hr <= 0.0)
78 | {
79 | return;
80 | }
81 |
82 | // normalize zones with total time
83 | var sum = 0.0;
84 | for(var i = 0; i < timeInZone.size(); i++)
85 | {
86 | sum += timeInZone[i];
87 | }
88 |
89 | if(sum <= 0.0)
90 | {
91 | return;
92 | }
93 |
94 | dc.clear();
95 | dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_RED);
96 | dc.fillRectangle(0, 0, dc.getWidth(), dc.getHeight());
97 | dc.setColor(numberColor, Gfx.COLOR_TRANSPARENT);
98 |
99 | dc.drawText(dc.getWidth()/2, dc.getHeight()/2 - 48, Gfx.FONT_NUMBER_HOT, (hr + restingHR).toString(), Gfx.TEXT_JUSTIFY_CENTER);
100 |
101 | // width & height assumed equal to draw arc of a circle
102 | var c = dc.getWidth()/2;
103 | //var cy = dc.getHeight()/2;
104 |
105 | // draw arc for each zone
106 | drawArc(dc, c, c, c-BAR_THICKNESS, (fullCircle * timeInZone[0]) / sum, Gfx.COLOR_DK_GREEN);
107 | drawArc(dc, c, c, c-BAR_THICKNESS * 2, (fullCircle * timeInZone[1]) / sum, Gfx.COLOR_GREEN);
108 | drawArc(dc, c, c, c-BAR_THICKNESS * 4, (fullCircle * timeInZone[2]) / sum, Gfx.COLOR_YELLOW);
109 | drawArc(dc, c, c, c-BAR_THICKNESS * 6, (fullCircle * timeInZone[3]) / sum, Gfx.COLOR_ORANGE);
110 | drawArc(dc, c, c, c-BAR_THICKNESS * 8, (fullCircle * timeInZone[4]) / sum, Gfx.COLOR_RED);
111 | }
112 |
113 | //! Fast (but kind of bad-looking) arc drawing.
114 | //! From http://stackoverflow.com/questions/8887686/arc-subdivision-algorithm/8889666#8889666
115 | //! TODO: Once we have drawArc, use that instead.
116 | function drawArc(dc, cx, cy, radius, theta, color) {
117 |
118 | dc.setColor(color, Gfx.COLOR_BLACK);
119 |
120 | var iters = ARC_MAX_ITERS * (theta / (2 * Math.PI));
121 | var dx = 0;
122 | var dy = -radius;
123 | var ctheta = Math.cos(theta/(iters - 1));
124 | var stheta = Math.sin(theta/(iters - 1));
125 |
126 | dc.fillCircle(cx + dx, cy + dy, BAR_THICKNESS);
127 |
128 | for(var i=1; i < iters; ++i) {
129 | var dxtemp = ctheta * dx - stheta * dy;
130 | dy = stheta * dx + ctheta * dy;
131 | dx = dxtemp;
132 | dc.fillCircle(cx + dx, cy + dy, BAR_THICKNESS);
133 | }
134 | }
135 | }
--------------------------------------------------------------------------------