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
You are probably observing the container that holds all the stats instead of observing the container/element for individual stats.
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
https://codepen.io/rnkwill/pen/OJrzroj
First time using codepen to post something so let me know if that link works.
restarting animations is actually hell
Tell me about it. I've been at this for 3 days now and it's my first time really trying somethihng like this 😦
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?
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
Ok i see
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
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
correction: the entry target
you literally just remove the for loop
Yes
let container = statContainer[i];
replaced by let container = entry.target;
and it should work
it's literally what i did and it worksWOW! Thanks for the assist!
Also another question.. when I change the value in the HTML to a decimal such as 99.9
(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)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
For the decimal issue there's 2 ways
Either using a decimal increments in the set interval and use
<=
instead of ==
i wouldn't even think about decimals
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.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
(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
^ this, and you can get the information timming to interpolate the animation
just remember that floating numbers are a pain
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.
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
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)
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
Just put it here or open a new thread
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