Intersection Observer API: How to have each circular progress bar fill when they are in viewport?

Sorry if the formatting is horrible. My first time asking a question! I am creating a stat module for the user to input a value and that value will get taken into a circular progress bar that fills up when the progress bar is in the viewport. I have it working partially BUT I am now stuck. When I have 3 x 2 lay out. All the stats will fill up twice. Once when the first row is in the viewport and another time when second row is in the viewport. Another issue I am running into is when the stats are stacked on mobile - once the first stat is in the viewport it fires for all the stats to fill up at the same time. I would like for the stat bar to fill up as each stat comes into view for mobile and once each time on desktop/tablet. What am I missing here? I can share code as well. Thank you!
28 Replies
Choo♚𝕂𝕚𝕟𝕘
You are probably observing the container that holds all the stats instead of observing the container/element for individual stats.
Rägnar O'ock
Rägnar O'ock16mo ago
I think they are observing them individually but updating them all at once. @rnkwill could you provide a minimal reproduction of your issue in a codepen
rnkwill
rnkwillOP16mo ago
https://codepen.io/rnkwill/pen/OJrzroj First time using codepen to post something so let me know if that link works.
ἔρως
ἔρως16mo ago
restarting animations is actually hell
rnkwill
rnkwillOP16mo ago
Tell me about it. I've been at this for 3 days now and it's my first time really trying somethihng like this 😦
ἔρως
ἔρως16mo ago
im trying to understand what exactly you want to do so, basically, you want to animate it going from 0 to some %? and when you scroll away, you want to restart it?
rnkwill
rnkwillOP16mo ago
No. I have the animation going from 0 to whatever value the user inputs. What I am trying to do is have the animation fire whenever each circular stat is in the viewport. At the moment it does that BUT once the second div is intersecting ALL 6 of the stat modules will animate again instead of just the second row. Additionally when I have them stacked in a single column whenever the first stat is intersecting - all of the stats fire when I want each to fire once they are in viewport Let me know if that makes sense
Rägnar O'ock
Rägnar O'ock16mo ago
Ok i see
ἔρως
ἔρως16mo ago
easy you're not handling the target on the intersection entry you're handling all 6 entries at once your mistake starts on line 15
Rägnar O'ock
Rägnar O'ock16mo ago
So basically, you just have to remove the for loop that is in your observer callback and use the entry object it is giving you to choose which element to start the animation on
ἔρως
ἔρως16mo ago
correction: the entry target you literally just remove the for loop
Rägnar O'ock
Rägnar O'ock16mo ago
Yes
ἔρως
ἔρως16mo ago
let container = statContainer[i]; replaced by let container = entry.target; and it should work it's literally what i did and it works
rnkwill
rnkwillOP16mo ago
WOW! Thanks for the assist! Also another question.. when I change the value in the HTML to a decimal such as 99.9
Rägnar O'ock
Rägnar O'ock16mo ago
(and please rename the parameter of the forEach loop at the bottom, you are shadowing the main statContainer and it makes the code hard to read)
rnkwill
rnkwillOP16mo ago
the circular value doesn't stop increasing at all. How would I be able to rewrite it to make it stop at 99.9? or any decimal value for that matter
Rägnar O'ock
Rägnar O'ock16mo ago
For the decimal issue there's 2 ways Either using a decimal increments in the set interval and use <= instead of ==
ἔρως
ἔρως16mo ago
i wouldn't even think about decimals
Rägnar O'ock
Rägnar O'ock16mo ago
Or using an interpolation. Basically remapping the 0 to value animation to 0% to 100% of the value. That way no matter the actual value the animation takes the same time.
ἔρως
ἔρως16mo ago
to be honest, i wouldn't even make the text change, i would just use a transition or something, to move it to the end
Rägnar O'ock
Rägnar O'ock16mo ago
(the first way is easier but the second one gives you more control and can work with requestAnimationFrame that you should use when doing animations with JS
ἔρως
ἔρως16mo ago
^ this, and you can get the information timming to interpolate the animation just remember that floating numbers are a pain
rnkwill
rnkwillOP16mo ago
Ugh yeah that sounds super annoying. I do like that second option with interpolation but I have never even done that before lol I'm a junior still But having the animations take the same time to fill up regardless of value would be the best and I know that might come up during review.
ἔρως
ἔρως16mo ago
by the way remember that adding floats is weird as hell 0.1 + 0.2 won't be 0.3 (but javascript massages it to be 0.3) it's actually closer to 0.1000000000000000055511151231257827021181583404541015625 + 0.200000000000000011102230246251565404236316680908203125 = 0.3000000000000000444089209850062616169452667236328125 but 0.3 is actually 0.299999999999999988897769753748434595763683319091796875
Rägnar O'ock
Rägnar O'ock16mo ago
For the interpolation you should look up lerp (short for linear interpolation) first then try some other timing function to change how the animation plays. (Usually for this kind of stuff you want it fast at the start and slow at the end, or "ease-out") It don't want to give it all away because searching yourself makes it so you 'll understand and remember it better. But feel free to ask questions (here or in another post)
rnkwill
rnkwillOP15mo ago
Thanks for the help! I'll try giving this a shot and hopefully I won't have to post another question lol This really helped a lot. Can I PM either one of you guys for some help on this? I tried looking up lerp and doing a bunch of other things but the decimal thing is really going over my head
Rägnar O'ock
Rägnar O'ock15mo ago
Just put it here or open a new thread
ἔρως
ἔρως15mo ago
do your calculations in integers, then divide by however much you want if you want 7 decimals of accuracy, then make it between 0 and 10000000. then, divide the number by 10000000 and you're done
Want results from more Discord servers?
Add your server