Spinning numbers on viewport - javascript

I have a spin function which makes the number rotates every 4 seconds. Now I need to start that function once when the numbers are on viewport, so when on viewport start function only once, I don't mean to rotate the numbers only once, just the function to start only once, and when numbers are not in the viewport anymore then do nothing and so on.
My problem comes when I play scrolling while numbers are visible, because that makes the function spin, to fire many times.
I kinda understand what is going on here, but just can't manage it in javascript, everytime I scroll, the scrolling listener fire multiple times so it also fires multiple times the .each() and also the spin function? If someone can explain what is the problem and how to solve it, would be nice.
If you have a fiddle to share would be nice.
Fiddle
var slots = $('.numbers').find('.slot');
if( slots.length ){
var isScrolling;
window.addEventListener('scroll', function ( event ) {
// Clear our timeout throughout the scroll
window.clearTimeout( isScrolling );
// Set a timeout to run after scrolling ends
isScrolling = setTimeout(function() {
slots.each(function(){
let slotHeight = $(this).height();
let animateTo = (-slotHeight + 21);
if( isElementInViewport( $(this)[0] ) ){
if( ! $(this).is(":animated") ){
spin($(this), animateTo);
}
else{
return false;
}
}
});
}, 200);
});
}
Thank you.

What you're seeing makes sense, because the scroll event triggers many, many times while scrolling (not just once when the scroll starts or ends or something like that).
If you'd like your behavior to be triggered less often, there are several options available to you. You could keep the scroll event listener and use a debounce or a throttle to reduce the number of triggers. Or you could listen to a different even altogether.
In your case, it sounds like you would like to trigger an action once an element comes into view, and then only once. For that, you could still run your scroll handler, but check if the element in question is visible, and then run the rest of your logic. Once that's done, you could de-register your event handler (scroll handlers are potentially expensive because they run so often).

Related

Mozilla scroll advice

I need a sticky bar to be visible and fixed after a certain scroll. I was going to use scroll event, then I met Mozilla page which advise to use window.requestAnimationFrame as the following :
var last_known_scroll_position = 0;
var ticking = false;
function doSomething(scroll_pos) {
// do something with the scroll position
}
window.addEventListener('scroll', function(e) {
last_known_scroll_position = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(function() {
doSomething(last_known_scroll_position);
ticking = false;
});
}
ticking = true;
});
I have a few questions :
1 - What is the logic behind ticking ?
2 - It seems to me that ticking will always be true since if statement doesn't return anything. This will lead to doSomething function will be called only once. I guess I am wrong, what am I missing?
mozilla link of scroll
Default browser behavior
On each scroll event (be it 1 pixel or more), the browser will repaint the layout. (for obvious layout purpose)
The performance problem
Your function doSomething() may not finish before two triggered scroll events. You can see it as a stack of doSomething functions because there will be more calls than your execution time can handle.
requestAnimationFrame()' solution
This function is defined in the window object by default. It tells the browser to wait the execution of the passed function before repainting the layout.
The idea of ticking
As you can see, ticking will only be false after doSomething(). It avoids the previous mentioned stack of events. It avoids executing the code of another scroll event before the function finished and the browser repainted the layout.
Conclusion
It adds performance to your scroll. I asked some days ago a question which illustrates this situation.

How to skip some Javascript events?

If you bind "mouseover" event for each table cell and move mouse from one corner to another - each event processed.
Usually event perform some visualization. If you move mouse fast I think there are no reason to drown in event handler on each element. Only on last where mouse stop.
But I don't understand how this can be achieved...
You need something to debounce your events (that is, ignore all events that occur close to eachother except for the last one), or something to throttle your events.
You can achieve this by using timeouts in your event handlers, such that they don't proceed if the event was raised within the last 100ms, for example.
There are ready-made solutions for jQuery out there, and Mootools More has a whole chunk of psuedo-events that will help you achieve the same thing.
Use a timer to delay the action, and cancel the timer when apropriate:
var timer;
var divs = document.querySelectorAll('div');
for(var i=0; i<divs.length; i++) {
divs[i].onmouseover = function() {
var div = this;
clearTimeout(timer);
timer = setTimeout(function() {
div.style.backgroundColor = 'green';
}, 200);
}
}
http://jsfiddle.net/B7uRV/

How do I stop onResize function executing its contents while resizing

I want the content of jQuery.fn.resize to only execute after i let go of the mouse button not while i am resizing the window.
I have tried putting onmousedown inside on resize but it didn't work.
$(window).resize(function(){
console.log("resizing")
});
You can't know what happens outside your document, and you're not notified when the resizing ends (a resizing can occur in many ways, not all of them mouse based).
But you could add a timer for the same effect :
(function(){
var timer;
$(window).resize(function(){
if (timer) clearTimeout(timer);
timer = setTimeout(function(){
// do the things
}, 200);
});
})();
This would add a slight delay (200 ms should be ok) but this would avoid most intermediate recomputing.
Note that you don't receive events when your javascript function is running, so you usually don't have to do this unless you really want the user to not see anything during the resizing.

Firing events in Twitter Bootstrap's Carousel

Once the carousel has slid, I want to add a value to an input outside of the ID myCarousel.
The function to implement an event once the carousel has slid is this:
$('#myCarousel').bind('slid', function() {
$('input[name=linkOnly]').val('Test')
}
I want to fire an event once a particular slide slides. I've tried something like $('#myCarousel li[data-slide-to=1]').bind('slid', function() ... but it doesn't register.
Any help appreciated, thanks.
You could just setup an event handler on the appropriate event and then choose to do anything based on which slide is .current. For example, to trigger some javascript when slide 1 cycles in:
$(document).on("slid", function(event) {
if ($(event.target).find(".active").data("slide-to") == 1) {
// do stuff
}
});
From a quick test, this doesn't seem to work unless it attached to an element above the carousel (you'd also need to change things a little if you had more than one carousel).
EDIT: After a quick look, the reason the above doesn't work if bound to the carousel itself is that the active class isn't added until immediately after the slid event is triggered (it seems that if the handler is added to a parent element, the active class gets added while the slid event bubbles up). You can get around this by using setTimeout to delay the triggered behaviour (works even with a timeout of 0):
$("#myCarousel").on("slid", function(event) {
var carousel = $(event.target);
setTimeout(function() {
if (carousel.find(".carousel-indicators .active").data("slide-to") === 1) {
// do stuff
}
}, 0);
});
Whether the extra code is worth it is up to you, although it may be a little more stable. It may even be worth putting in a small delay (instead of 0), just to make sure that things do work the way you expect them to.

auto scroll: stop jumps back to top of page

I have a page in which the user clicks one link to start scrolling down the page automatically for ease in reading. There is another link the user clicks to stop the scrolling. The former works perfectly, but the latter makes the page jump back to the top when clicked instead of stopping the scrolling at the that place on the page. Any ideas?
function pageScroll() {
window.scrollBy(0,1); // horizontal and vertical scroll increments
scrolldelay = setTimeout('pageScroll()',50); // scrolls every 100 milliseconds
}
function stopScroll() {
clearTimeout(scrolldelay);
}
I tried to add return false; to the second function from something I read on another post, but it didn't help. I don't fully understand the use of return anyhow. Thanks for any help.
I assume that you're doing something like this:
start
stop
The quickest fix is to return false from the onclick event handlers, like this:
start
stop
The idea is to stop the browser from doing the default action of the event (in this case, going to #, which scrolls to the top of the page). Nowadays, the more modern way is to bind an event handler function, then use e.preventDefault() in it, but return false; still works for old-style event attributes.

Categories

Resources