01-17-2021 17:41
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-17-2021 17:41
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
The fact that positions can be specified as percentages in the svg markup for a watchface / app is great, but if you take advantage of this feature then at runtime document elements set from percentages all report 0 for their value.
After wasting hours of my life, I eventually I found this post mentioning that you can't use percentages for document element attributes in javascript (https://dev.fitbit.com/build/guides/user-interface/javascript/#interacting-with-elements)
This is SUPER frustrating, and though the solution is actually pretty simple it took me a long time to work it out.
Here's a snippet of my SVG code to help illustrate:
<svg id="root" viewport-fill="fb-black">
<svg id="targeting" x="2%" y="2%" width="96%" height="60%">
<g id="leftLine" pointer-events="visible" transform="translate(5%,0%)">
<line x1="0" y1="0" x2="0" y2="100%" fill="red" stroke-width="4"/>
</g>
<g id="rightLine" pointer-events="visible" transform="translate(97%,0%)">
<line x1="0" y1="0" x2="0" y2="100%" fill="red" stroke-width="4"/>
</g>
</svg>
</svg>
I want to procedurally animate leftLine and rightLine positions; I need to do this in pixels as we now know, I also need to do this relative to their parent node (possibly because I've used the <g> node?), and helpfully all the attributes I set in the svg are all returning 0...
Turns out you can just grab the on-screen bounding box of any element using .getBBox() which returns a DOMRect that gives you the screen position, width etc. of the element.
By grabbing the bounds of the parent element in the svg I can now position leftLine halfway across the svg element "targeting" I specified entirely with percentages!
let targeting = document.getElementById("targeting");
let bbox = targeting.getBBox();
Hope this saves someone else a few hours of their life 🙂
FWIW - I've literally just started messing with the fitbit SDK today and have lost several hours of my life because of bad documentation / terrible out of date questions & answers.
I found a couple of posts on this site whilst trying to get to the bottom of this and either the "solutions" was unhelpful or just plain wrong - here they are so you can avoid them...
https://community.fitbit.com/t5/SDK-Development/Setting-height-width-percentages/td-p/2239180
Answered! Go to the Best Answer.
Accepted Solutions
01-18-2021 12:25
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-18-2021 12:25
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
No worries - thanks for getting back to me...
I really just wanted to make sure that whoever came along next after me would have more clues than I did, very few things are more frustrating than unanswered or incorrect forum posts so once I get a solution I always ask the question I was stuck with and post my own answer 🙂
I actually meant to edit the code I posted, but apparently you can't edit posts...
So here's how I got it working.
With this svg markup:
<svg id="root" viewport-fill="fb-black">
<svg id="targeting" x="2%" y="2%" width="96%" height="60%">
<g id="leftLine" pointer-events="visible" transform="translate(5%,0%)">
<line x1="0" y1="0" x2="0" y2="100%" fill="red" stroke-width="4"/>
</g>
<g id="rightLine" pointer-events="visible" transform="translate(97%,0%)">
<line x1="0" y1="0" x2="0" y2="100%" fill="red" stroke-width="4"/>
</g>
</svg>
</svg>
I managed to get leftLine and rightLine to move relative to their parent like this:
let targeting = document.getElementById("targeting");
let leftLine = document.getElementById("leftLine");
let rightLine = document.getElementById("rightLine");
let bbox = targeting.getBBox();
let halfTargetWidth = bbox.width / 2;
let propOfMinute = today.getSeconds() / 60;
leftLine.groupTransform.translate.x = halfTargetWidth * propOfMinute;
rightLine.groupTransform.translate.x = bbox.width - (halfTargetWidth * propOfMinute);
01-18-2021 05:27
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


01-18-2021 05:27
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Sorry that you had this experience. We're still aiming to resolve this discrepancy between the SVG and JS attributes, but unfortunately it wasn't a quick fix.

01-18-2021 12:25
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-18-2021 12:25
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
No worries - thanks for getting back to me...
I really just wanted to make sure that whoever came along next after me would have more clues than I did, very few things are more frustrating than unanswered or incorrect forum posts so once I get a solution I always ask the question I was stuck with and post my own answer 🙂
I actually meant to edit the code I posted, but apparently you can't edit posts...
So here's how I got it working.
With this svg markup:
<svg id="root" viewport-fill="fb-black">
<svg id="targeting" x="2%" y="2%" width="96%" height="60%">
<g id="leftLine" pointer-events="visible" transform="translate(5%,0%)">
<line x1="0" y1="0" x2="0" y2="100%" fill="red" stroke-width="4"/>
</g>
<g id="rightLine" pointer-events="visible" transform="translate(97%,0%)">
<line x1="0" y1="0" x2="0" y2="100%" fill="red" stroke-width="4"/>
</g>
</svg>
</svg>
I managed to get leftLine and rightLine to move relative to their parent like this:
let targeting = document.getElementById("targeting");
let leftLine = document.getElementById("leftLine");
let rightLine = document.getElementById("rightLine");
let bbox = targeting.getBBox();
let halfTargetWidth = bbox.width / 2;
let propOfMinute = today.getSeconds() / 60;
leftLine.groupTransform.translate.x = halfTargetWidth * propOfMinute;
rightLine.groupTransform.translate.x = bbox.width - (halfTargetWidth * propOfMinute);
