03-27-2018 17:19 - edited 03-27-2018 17:20
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

03-27-2018 17:19 - edited 03-27-2018 17:20
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi all,
Hope all is well. What's the most efficient way to write javascript that embeds the step count and calorie count into the rect elements below? I am trying to create a vertical bar graph for each.
Also, is it best practice to include all the javascript in the index.js file or have a .js file for each metric? Thanks in advance!
<svg class="background"> <rect id="mySteps" x="312" y="0" width="18" height="100%" fill="white" /> <rect id="myCalories" x="330" y="0" width="18" height="100%" fill="#1abc9c" /> </svg>
Answered! Go to the Best Answer.

- Labels:
-
JavaScript
Accepted Solutions
03-28-2018 07:25 - edited 03-28-2018 07:27
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


03-28-2018 07:25 - edited 03-28-2018 07:27
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
I've been working on a simple abstraction layer for some of these things.
Create `simple-activity.js` in your /app folder, with these contents:
/* simple-activity.js A simple way of returning activity data in the correct format based on user preferences. Callback should be used to update your UI. */ import clock from "clock"; import { today, goals } from "user-activity"; import { units } from "user-settings"; let activityCallback; export function initialize(granularity, callback) { clock.granularity = granularity; clock.addEventListener("tick", tickHandler); activityCallback = callback; } let activityData = { activeMinutes: getActiveMinutes(), calories: getCalories(), distance: getDistance(), elevationGain: getElevationGain(), steps: getSteps() } function tickHandler(evt) { activityCallback(activityData); } function getActiveMinutes() { let val = (today.adjusted.activeMinutes || 0); return { raw: val, pretty: (val < 60 ? "" : Math.floor(val/60) + "h,") + ("0" + (val%60)).slice("-2") + "m" } } function getCalories() { let val = (today.adjusted.calories || 0); return { raw: val, pretty: val > 999 ? Math.floor(val/1000) + "," + ("00"+(val%1000)).slice(-3) : val } } function getDistance() { let val = (today.adjusted.distance || 0) / 1000; let u = "km"; if(units.distance === "us") { val *= 0.621371; u = "mi"; } return { raw: val, pretty: `${val.toFixed(2)}${u}` } } function getElevationGain() { let val = today.adjusted.elevationGain || 0; return { raw: val, pretty: `+${val}` } } function getSteps() { let val = (today.adjusted.steps || 0); return { raw: val, pretty: val > 999 ? Math.floor(val/1000) + "," + ("00"+(val%1000)).slice(-3) : val } }
Then add this in your `index.js`.
import document from "document";
import * as simpleActivity from "./simple-activity";
let mySteps = document.getElementById("mySteps");
let myCalories = document.getElementById("myCalories");
function activityCallback(data) {
// work out the percentage width here
mySteps.width = 0 // data.steps;
myCalories.width = 0; //data.calories; }
simpleActivity.initialize(GRANULARITY, activityCallback);
I hope that helps.
03-28-2018 07:25 - edited 03-28-2018 07:27
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


03-28-2018 07:25 - edited 03-28-2018 07:27
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
I've been working on a simple abstraction layer for some of these things.
Create `simple-activity.js` in your /app folder, with these contents:
/* simple-activity.js A simple way of returning activity data in the correct format based on user preferences. Callback should be used to update your UI. */ import clock from "clock"; import { today, goals } from "user-activity"; import { units } from "user-settings"; let activityCallback; export function initialize(granularity, callback) { clock.granularity = granularity; clock.addEventListener("tick", tickHandler); activityCallback = callback; } let activityData = { activeMinutes: getActiveMinutes(), calories: getCalories(), distance: getDistance(), elevationGain: getElevationGain(), steps: getSteps() } function tickHandler(evt) { activityCallback(activityData); } function getActiveMinutes() { let val = (today.adjusted.activeMinutes || 0); return { raw: val, pretty: (val < 60 ? "" : Math.floor(val/60) + "h,") + ("0" + (val%60)).slice("-2") + "m" } } function getCalories() { let val = (today.adjusted.calories || 0); return { raw: val, pretty: val > 999 ? Math.floor(val/1000) + "," + ("00"+(val%1000)).slice(-3) : val } } function getDistance() { let val = (today.adjusted.distance || 0) / 1000; let u = "km"; if(units.distance === "us") { val *= 0.621371; u = "mi"; } return { raw: val, pretty: `${val.toFixed(2)}${u}` } } function getElevationGain() { let val = today.adjusted.elevationGain || 0; return { raw: val, pretty: `+${val}` } } function getSteps() { let val = (today.adjusted.steps || 0); return { raw: val, pretty: val > 999 ? Math.floor(val/1000) + "," + ("00"+(val%1000)).slice(-3) : val } }
Then add this in your `index.js`.
import document from "document";
import * as simpleActivity from "./simple-activity";
let mySteps = document.getElementById("mySteps");
let myCalories = document.getElementById("myCalories");
function activityCallback(data) {
// work out the percentage width here
mySteps.width = 0 // data.steps;
myCalories.width = 0; //data.calories; }
simpleActivity.initialize(GRANULARITY, activityCallback);
I hope that helps.
03-29-2018 06:58
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

03-29-2018 06:58
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Thanks Jon! Looks really robust. Just a quick question - in the index.js portion, do I simply just pass parameters into this function? If yes, what does that look like exactly for step count? Sorry for my lack of understanding, I'm still pretty new to JS. Thanks again!
simpleActivity.initialize(GRANULARITY, activityCallback);

03-29-2018 12:04
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


03-29-2018 12:04
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Sorry, looks like I missed a bit:
const GRANULARITY = "minutes"; // or seconds

03-31-2018 09:19
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

03-31-2018 09:19
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Great thanks Jon! It worked like a charm.

04-03-2018 14:46
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

04-03-2018 14:46
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi Jon,
Quick question-so the granularity is set to seconds. However, it appears that the callback is not retrieving new values for the "data" object that is created below. I can see the data object populating in the console every second but the step values are not updating every second. It appears that the data only refreshes when I switch to the Today app and then switch back to the clock face.
Is there any other adjustments that need to be made to the simple-activity.js? Thanks Jon!
function activityCallback(data) {
// work out the percentage height here
// barCalories.height = (data.calories.raw / data.goalCalories.raw)*348; // data.calories;
barSteps.height = (data.steps.raw / data.goalSteps.raw)*348; //data.steps;
barActiveMinutes.height = (data.activeMinutes.raw / data.goalActiveMinutes.raw)*348; //data.activeminutes;
// statCalories.text = data.calories.pretty;
statSteps.text = data.steps.pretty;
statActiveMinutes.text = data.activeMinutes.pretty;
// Begin monitoring the sensor
hrm.start();
console.log("Calories: " + JSON.stringify(data.calories.pretty));
console.log("Steps: " + JSON.stringify(data.steps.pretty));
console.log("Active Minutes: " + JSON.stringify(data.activeMinutes.pretty));
console.log("HR: " + MYHR.text);
};
simpleActivity.initialize(GRANULARITY, activityCallback);

06-07-2018 21:28
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-07-2018 21:28
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi Jon,
I tried running the code posted above and am not seeing any graph/updating data on the screen, am I missing something?

06-08-2018 01:29 - edited 06-08-2018 01:34
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-08-2018 01:29 - edited 06-08-2018 01:34
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
It looks like the 'activityData' is only initialised once (upon start), so the actual values contained are a 'snapshot' and not continually updated.
To get the values to update, activityData would need to be updated every clock tick.
I can't try this now (am at work), but in the tickHandler function, I think you'd need something like the following before the callback was called:
activityData.activeMinutes = getActiveMinutes(); activityData.calories = getCalories(); activityData.distance = getDistance(); activityData.elevationGain = getElevationGain(); activityData.steps = getSteps();
You could also wrap that code in another function and call that in the tickHandler to make it a bit more tidy.

06-10-2018 18:59
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-10-2018 18:59
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi Mark,
Thanks for the reply. I tried this and was still not successful.
Does it have something to do with the comment in the previous code. I never set the width anywhere except in the index.gui.
function activityCallback(data) { // work out the percentage width here mySteps.width = 0 // data.steps; myCalories.width = 0; //data.calories; }

06-14-2018 22:00
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-14-2018 22:00
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi Ramirez,
I'm wondering if you ever got this working, I have not been able to get Jon's code working? I believe it's an issue with setting the width.

06-26-2018 06:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

06-26-2018 06:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Move
let activityData = {...}
inside function tickHandler(evt) {...}
function tickHandler(evt) {
let activityData = {
activeMinutes: getActiveMinutes(),
calories: getCalories(),
distance: getDistance(),
elevationGain: getElevationGain(),
steps: getSteps()
}
activityCallback(activityData);
}

07-01-2018 13:34
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-01-2018 13:34
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Is there a simple way to switch the direction that the graph fills? I want it to fill to the left, but currently it is filling to the right.

07-01-2018 14:38
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-01-2018 14:38
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Envoyé de mon iPhone

07-01-2018 19:54
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-01-2018 19:54
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
What do you mean by X/Y positions. My index.js looks like this, which works but the bar chart fills from the 100 pixels down to 298 pixel. I'm hoping to switch this by filling the chart from the bottom up. I tried using negative numbers but that is not working.
myActiveMinutes.height = (data.activeMinutes.raw / 60)*196;
Here is my index.gui
<rect id= "myActiveMinutes" x="102" y="102" width="46" height="16" fill="teal" />

07-02-2018 05:23
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-02-2018 05:23
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
// In app/index.js
let rStep = document.getElementById("rStep");
rStep.height = ((goals.steps-today.local.steps)*96) / goals.steps;
rStep.height = rStep.height > 0 ? rStep.height :0;
rStep.y = 103 - rStep.height;
// In ressources/index.gui
<rect id="rStep" x="7" y="7" width="12" height="96" fill="black" />

