01-17-2021 17:41
01-17-2021 17:41
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.
01-18-2021 12:25
01-18-2021 12:25
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
Fitbit Developers oversee the SDK and API forums. We're here to answer questions about Fitbit developer tools, assist with projects, and make sure your voice is heard by the development team.
01-18-2021 05:27
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.
Best Answer01-18-2021 12:25
01-18-2021 12:25
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);