jQuery what is - el.moveDown() - javascript

based on this code in the link https://www.smashingmagazine.com/2014/08/how-i-built-the-one-page-scroll-plugin/
function init_scroll(event, delta) {
var deltaOfInterest = delta,
timeNow = new Date().getTime(),
quietPeriod = 500;
// Cancel scroll if currently animating or within quiet period
if(timeNow - lastAnimation < quietPeriod + settings.animationTime) {
event.preventDefault();
return;
}
if (deltaOfInterest < 0) {
el.moveDown()
} else {
el.moveUp()
}
lastAnimation = timeNow;
}
$(document).bind('mousewheel DOMMouseScroll', function(event) {
event.preventDefault();
var delta = event.originalEvent.wheelDelta || -event.originalEvent.detail;
init_scroll(event, delta);
});
What is el. part before it calls moveDown()? I'm new to jQuery and I'm not sure what it's called.
It can also be seen calling swipeEvents().
el.swipeEvents().unbind("swipeDown swipeUp");
Cheers

Looking at their example code shows:
var el = $(this)
Where this is the element that plugin is initialized on:
$(".main").onepage_scroll();
Putting a breakpoint in the init_scroll function and inspecting el shows:
[<div class="main onepage-wrapper" ... > ... </div>]
Which is indeed the jQuery selector over the element that the plugin was initialized on.

Related

Detecting Animation Elements in View

I am trying to add a class to an element when it is in the viewport. I have achieved this however it causes serious issues to the performance of my site when I scroll.
I currently have this JavaScript:
//Cache reference to window and animation items
var $animation_elements = $('.animation-element');
var $window = $(window);
$window.on('scroll resize', check_if_in_view);
$window.trigger('scroll');
function check_if_in_view() {
var window_height = $window.height();
var window_top_position = $window.scrollTop();
var window_bottom_position = (window_top_position + window_height);
$.each($animation_elements, function() {
var $element = $(this);
var element_height = $element.outerHeight();
var element_top_position = $element.offset().top;
var element_bottom_position = (element_top_position + element_height);
//check to see if this current container is within viewport
if ((element_bottom_position >= window_top_position) &&
(element_top_position <= window_bottom_position)) {
$element.addClass('in-view');
} else {
$element.removeClass('in-view');
}
});
}
So as you can see the check_if_in_view() function seems to be constantly firing as the page is being scrolled and I believe this might be the reason why the performance might be so bad.
Is there a more efficient way of adding a class when scrolling the page that wont cause performance issues on my site?
Use setTimeout to delay calling the function every time a scroll event is fired. In the following code (which I borrowed from Codrops), a flag is set to call the function every 60 milliseconds in the case of continous scrolling.
function Scroller(el) {
this.elements = Array.prototype.slice.call( el );
this._init();
}
Scroller.prototype = {
_init : function() {
//this flag prevents that the function _scrollPage is called
//every time the 'scroll' event is fired
this.didScroll = false;
window.addEventListener( 'scroll', this._scrollHandler.bind(this), false );
},
_scrollHandler : function() {
if( !this.didScroll ) {
this.didScroll = true;
setTimeout( function() { this._scrollPage(); }, 60 );
}
},
_scrollPage : function() {
this.elements.forEach( function( el, i ) {
if( inViewport(el) ) {
classie.add( el, 'i-am-in-the-viewport' );
}
else {
classie.remove( el, 'i-am-in-the-viewport' );
}
});
this.didScroll = false;
}
};
To use it call new Scroller( document.getElementsByClassName('elements-to-watch') );.
Check out the complete code on Codrops to see the implementation of the inViewPort() function. Classie.js is used to handle the assignation of class names.
Don't be afraid to ask for clarification if there's something you don't get!

animate when window.location.hash changes

so i'm trying to get a site gallery-like, i have the articles that spreads all across the page and my idea is that when i get an action from the user the site jumps to the next article.
I have done a lot of work so far and it's a couple of days i'm behind javascript, i'm using jquery and the code is this
$('body').ready(function () {
var tpScroll = 0;
var SelArticles = $('#content').find('.bgjs');
var NumArticles = SelArticles.length;
window.location.hash = SelArticles.first().attr('id');
$(window).bind('mousewheel', function (event, delta, deltaX, deltaY) {
event.preventDefault();
console.log(delta, deltaX, deltaY);
console.log(tpScroll);
if (delta < 0) {
if (tpScroll >= (NumArticles - 1)) {
tpScroll = 0;
} else {
tpScroll = tpScroll + 1;
}
var pgid = SelArticles.eq(tpScroll).attr('id');
window.location.hash = pgid;
} else {
if (tpScroll <= 0) {
tpScroll = (NumArticles - 1);
} else {
tpScroll = tpScroll - 1;
}
var pgid = SelArticles.eq(tpScroll).attr('id');
window.location.hash = pgid;
}
});
});
i managed to handle the mousewheel event to make the hash change, but i want to prevent the default scroll to the content adding a smooth animation.
I'm not a monster in javascript (neither jquery) as you can see , but it's kind of working, i don't even know if it's possible to prevend this behavior, or to work around it... any suggestion?
I just completely changed approach, i used wiselinks to handle history apis, turned out to be a great choice

setting scrollLeft within a timer doesn't work

Im having a very strange bug. Im trying to limit the amount of scroll calls within a jquery mousewheel function. I have set a timer to limit the calls but it doesnt seem to call the function scrollLeft. However, it works if its not wrapped in any timer. Is this some kind of native JS bug? or has anyone found a workaround for it?
$(document).ready(function() {
var scrpos=0;
var limitTimer;
var did= true;
$('html, body, *').bind('mousewheel', function(event,delta){
var BODY= this;
if (did){
did =false;
if (delta > 0) {
if (scrpos >= $(document).width() - $(window).width()){
}else{
scrpos += 100;
}
} else {
if (scrpos !== 0){
scrpos -= 100;
}
}
BODY.scrollLeft = scrpos;
console.log(scrpos);
var limitTimer = setTimeout(function(){
did=true;
clearTimeout(limitTimer);
}, 150);
}
//Works here when outside the call
//BODY.scrollLeft = scrpos;
});
});

Scrolling child div scrolls the window, how do I stop that?

I have a div, with a scroll bar, When it reaches the end, my page starts scrolling. Is there anyway I can stop this behavior ?
You can inactivate the scrolling of the whole page by doing something like this:
<div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>
Found the solution.
http://jsbin.com/itajok
This is what I needed.
And this is the code.
http://jsbin.com/itajok/edit#javascript,html
Uses a jQuery Plug-in.
Update due to deprecation notice
From jquery-mousewheel:
The old behavior of adding three arguments (delta, deltaX, and deltaY)
to the event handler is now deprecated and will be removed in later
releases.
Then, event.deltaY must now be used:
var toolbox = $('#toolbox'),
height = toolbox.height(),
scrollHeight = toolbox.get(0).scrollHeight;
toolbox.off("mousewheel").on("mousewheel", function (event) {
var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
return !blockScrolling;
});
Demo
The selected solution is a work of art. Thought it was worthy of a plugin....
$.fn.scrollGuard = function() {
return this
.on( 'wheel', function ( e ) {
var event = e.originalEvent;
var d = event.wheelDelta || -event.detail;
this.scrollTop += ( d < 0 ? 1 : -1 ) * 30;
e.preventDefault();
});
};
This has been an ongoing inconvenience for me and this solution is so clean compared to other hacks I've seen. Curious to know how more about how it works and how widely supported it would be, but cheers to Jeevan and whoever originally came up with this. BTW - stackoverflow answer editor needs this!
UPDATE
I believe this is better in that it doesn't try to manipulate the DOM at all, only prevents bubbling conditionally...
$.fn.scrollGuard2 = function() {
return this
.on( 'wheel', function ( e ) {
var $this = $(this);
if (e.originalEvent.deltaY < 0) {
/* scrolling up */
return ($this.scrollTop() > 0);
} else {
/* scrolling down */
return ($this.scrollTop() + $this.innerHeight() < $this[0].scrollHeight);
}
})
;
};
Works great in chrome and much simpler than other solutions... let me know how it fares elsewhere...
FIDDLE
You could use a mouseover event on the div to disable the body scrollbar and then a mouseout event to activate it again?
E.g. The HTML
<div onmouseover="disableBodyScroll();" onmouseout="enableBodyScroll();">
content
</div>
And then the javascript like so:
var body = document.getElementsByTagName('body')[0];
function disableBodyScroll() {
body.style.overflowY = 'hidden';
}
function enableBodyScroll() {
body.style.overflowY = 'auto';
}
As answered here, most modern browsers now support the overscroll-behavior: none; CSS property, that prevents scroll chaining. And that's it, just one line!
Here's a cross-browser way to do this on the Y axis, it works on desktop and mobile. Tested on OSX and iOS.
var scrollArea = this.querySelector(".scroll-area");
scrollArea.addEventListener("wheel", function() {
var scrollTop = this.scrollTop;
var maxScroll = this.scrollHeight - this.offsetHeight;
var deltaY = event.deltaY;
if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
event.preventDefault();
}
}, {passive:false});
scrollArea.addEventListener("touchstart", function(event) {
this.previousClientY = event.touches[0].clientY;
}, {passive:false});
scrollArea.addEventListener("touchmove", function(event) {
var scrollTop = this.scrollTop;
var maxScroll = this.scrollHeight - this.offsetHeight;
var currentClientY = event.touches[0].clientY;
var deltaY = this.previousClientY - currentClientY;
if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
event.preventDefault();
}
this.previousClientY = currentClientY;
}, {passive:false});
I wrote resolving for this issue
var div;
div = document.getElementsByClassName('selector')[0];
div.addEventListener('mousewheel', function(e) {
if (div.clientHeight + div.scrollTop + e.deltaY >= div.scrollHeight) {
e.preventDefault();
div.scrollTop = div.scrollHeight;
} else if (div.scrollTop + e.deltaY <= 0) {
e.preventDefault();
div.scrollTop = 0;
}
}, false);
If I understand your question correctly, then you want to prevent scrolling of the main content when the mouse is over a div (let's say a sidebar). For that, the sidebar may not be a child of the scrolling container of the main content (which was the browser window), to prevent the scroll event from bubbling up to its parent.
This possibly requires some markup changes in the following manner:
<div id="wrapper">
<div id="content">
</div>
</div>
<div id="sidebar">
</div>
See it's working in this sample fiddle and compare that with this sample fiddle which has a slightly different mouse leave behavior of the sidebar.
See also scroll only one particular div with browser's main scrollbar.
this disables the scrolling on the window if you enter the selector element.
works like charms.
elements = $(".selector");
elements.on('mouseenter', function() {
window.currentScrollTop = $(window).scrollTop();
window.currentScrollLeft = $(window).scrollTop();
$(window).on("scroll.prevent", function() {
$(window).scrollTop(window.currentScrollTop);
$(window).scrollLeft(window.currentScrollLeft);
});
});
elements.on('mouseleave', function() {
$(window).off("scroll.prevent");
});
You can inactivate the scrolling of the whole page by doing something like this but display the scrollbar!
<div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>
$this.find('.scrollingDiv').on('mousewheel DOMMouseScroll', function (e) {
var delta = -e.originalEvent.wheelDelta || e.originalEvent.detail;
var scrollTop = this.scrollTop;
if((delta < 0 && scrollTop === 0) || (delta > 0 && this.scrollHeight - this.clientHeight - scrollTop === 0)) {
e.preventDefault();
}
});
Based on ceed's answer, here is a version that allows nesting scroll guarded elements. Only the element the mouse is over will scroll, and it scrolls quite smoothly. This version is also re-entrant. It can be used multiple times on the same element and will correctly remove and reinstall the handlers.
jQuery.fn.scrollGuard = function() {
this
.addClass('scroll-guarding')
.off('.scrollGuard').on('mouseenter.scrollGuard', function() {
var $g = $(this).parent().closest('.scroll-guarding');
$g = $g.length ? $g : $(window);
$g[0].myCst = $g.scrollTop();
$g[0].myCsl = $g.scrollLeft();
$g.off("scroll.prevent").on("scroll.prevent", function() {
$g.scrollTop($g[0].myCst);
$g.scrollLeft($g[0].myCsl);
});
})
.on('mouseleave.scrollGuard', function() {
var $g = $(this).parent().closest('.scroll-guarding');
$g = $g.length ? $g : $(window);
$g.off("scroll.prevent");
});
};
One easy way to use is to add a class, such as scroll-guard, to all the elements in the page that you allow scrolling on. Then use $('.scroll-guard').scrollGuard() to guard them.
If you apply an overflow: hidden style it should go away
edit: actually I read your question wrong, that will only hide the scroll bar but I don't think that's what you are looking for.
I couldn't get any of the answers to work in Chrome and Firefox, so I came up with this amalgamation:
$someElement.on('mousewheel DOMMouseScroll', scrollProtection);
function scrollProtection(event) {
var $this = $(this);
event = event.originalEvent;
var direction = (event.wheelDelta * -1) || (event.detail);
if (direction < 0) {
if ($this.scrollTop() <= 0) {
return false;
}
} else {
if ($this.scrollTop() + $this.innerHeight() >= $this[0].scrollHeight) {
return false;
}
}
}

Scroll event firing too many times. I only want it to fire a maximum of, say, once per second

I have a page with "infinite scroll". It calculates the difference between the end of the page and the current page and loads more content if this difference is small enough. The code is soemthing like this using jQuery:
$(window).on('scroll', function() {
if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
# load more content via ajax
}
Now, the problem is that every time I scroll, this event fires multiple times per scroll. I would like fire at most every x milliseconds. How would I do this?
Check out the Underscore.js library's "throttle" method.
http://underscorejs.org/#throttle
The example it gives is exactly what you're asking about - limiting how often you have to handle scroll events.
One way to solve this problem is to define a time interval and only process a scroll event once within that time interval. If more than one scroll event comes in during that time interval, you ignore it and process it only when that time interval has passed.
var scrollTimer, lastScrollFireTime = 0;
$(window).on('scroll', function() {
var minScrollTime = 100;
var now = new Date().getTime();
function processScroll() {
console.log(new Date().getTime().toString());
}
if (!scrollTimer) {
if (now - lastScrollFireTime > (3 * minScrollTime)) {
processScroll(); // fire immediately on first scroll
lastScrollFireTime = now;
}
scrollTimer = setTimeout(function() {
scrollTimer = null;
lastScrollFireTime = new Date().getTime();
processScroll();
}, minScrollTime);
}
});
This will fire the first scroll event immediately and then get you a scroll event approximately once every 100ms while the scrollbar is being moved and then one final event after the scrollbar stops moving. You can adjust the frequency of the event by changing the argument to the setTimeout (what is currently set to 100).
There is a demo here: http://jsfiddle.net/jfriend00/EBEqZ/ which you need to open a debug console window, start moving the scrollbar in the content window and then watch the time of each scroll event in the debug console window. On my version of Chrome, they are set for a minimum spacing of 100ms and they seem to occur every 100-200ms.
There is a cool explanation from John Resig, the creator of jQuery to resolve this situation.
var outerPane = $details.find(".details-pane-outer"),
didScroll = false;
$(window).scroll(function() {
didScroll = true;
});
setInterval(function() {
if ( didScroll ) {
didScroll = false;
// Check your page position and then
// Load in more results
}
}, 250);
The source:
http://ejohn.org/blog/learning-from-twitter/
var isWorking = 0;
$(window).on('scroll', function()
{
if(isWorking==0)
{
isWorking=1;
if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
# load more content via ajax
setTimeout(function(){isWorking=0},1000);
}
}
var now = new Date().getTime();
$(window).scroll( function () {
if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
{
if (new Date().getTime() - now > 1000)
{
console.log("Task executed once per second");
now = new Date().getTime();
}
}
});
Or
You can use Throttling fonction calls:
throttling-function-calls
function throttle(fn, threshhold, scope) {
threshhold || (threshhold = 250);
var last,
deferTimer;
return function () {
var context = scope || this;
var now = +new Date,
args = arguments;
if (last && now < last + threshhold) {
// hold on to it
clearTimeout(deferTimer);
deferTimer = setTimeout(function () {
last = now;
fn.apply(context, args);
}, threshhold);
} else {
last = now;
fn.apply(context, args);
}
};
}
You can call it like this:
$('body').on('mousemove', throttle(function (event) {
console.log('tick');
}, 1000));
Here is a solution that doesn't require the use of an extra JS library or plugin, that aims for simplicity. It might not be as efficient as other implementations but it is definitely a step up from firing your main event every time you scroll.
This was taken from this blog post by Danny Van Kooten. Which I have used in delaying my onscroll() events for my back-to-top button on my blog.
var timer;
$(window).scroll(function() {
if(timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(function() {
// actual code here. Your call back function.
console.log( "Firing!" );
}, 100);
});
You can also further improve performance by moving out variables out of the callback function to avoid unnecessary recalculations, for example the value of $(window).height() or height of some static div element that won't change once the page is loaded.
Here's an example that is adapted from my use case.
var scrollHeight = $("#main-element").height(); //never changes, no need to recalculate.
$(window).on('scroll', function() {
if (timer)
window.clearTimeout(timer);
timer = window.setTimeout(function() {
var scrollPosition = $(window).height() + $(window).scrollTop();
if ($(window).scrollTop() < 500)
$(".toggle").fadeIn(800);
else
$(".toggle").fadeOut(800);
}, 150); //only fire every 150 ms.
});
This limits the actual function to only execute every 150ms, or else reset the timer back to 0 if 150ms has not passed. Tweak the value to suit what you need.
the scroll fire multiple times is correct and you should able to get the scroll position differently each time. I think you need to set a timer when you first get in the scroll event like you mentioned x milliseconds, and also record the time stamp, and then next time scroll event fire, check the last trigger time and ignore it if it's within x milliseconds, and do the real job in your Timer action.
One does not need a ton of local variables for a decent throttle function. The purpose of a throttle function is to reduce browser resources, not to apply so much overhead that you are using even more. As proof of evidence of this claim, I have devised a throttle function that has only 5 'hanging' variables referenes in its scope. Additionally, my different uses for throttle functions require many different circumstances for them. Here is my list of things that I believe 'good' throttle function needs.
Immediately calls the function if it has been more than interval MS since the last call.
Avoids executing function for another interval MS.
Delays excessive event firing instead of dropping the event altogether.
Updates the delayed event object on successive calls so that it doesn't become 'stale'.
And, I believe that the following throttle function satisfies all of those.
function throttle(func, alternateFunc, minimumInterval) {
var executeImmediately = true, freshEvt = null;
return function(Evt) {
if (executeImmediately) { // Execute immediatly
executeImmediately = false;
setTimeout(function(f){ // handle further calls
executeImmediately = true;
if (freshEvt !== null) func( freshEvt );
freshEvt = null;
}, minimumInterval);
return func( Evt );
} else { // Delayed execute
freshEvt = Evt;
if (typeof alternateFunc === "function") alternateFunc( Evt );
}
};
}
Then, to wrap this throttle function around DOM event listeners:
var ltCache = [];
function listen(obj, evt, func, _opts){
var i = 0, Len = ltCache.length, lF = null, options = _opts || {};
a: {
for (; i < Len; i += 4)
if (ltCache[i] === func &&
ltCache[i+1] === (options.alternate||null) &&
ltCache[i+2] === (options.interval||200)
) break a;
lF = throttle(func, options.alternate||null, options.interval||200);
ltCache.push(func, options.alternate||null, options.interval||200, lF);
}
obj.addEventListener(evt, lF || ltCache[i+3], _opts);
};
function mute(obj, evt, func, options){
for (var i = 0, Len = ltCache.length; i < Len; i += 4)
if (ltCache[i] === func &&
ltCache[i+1] === (options.alternate||null) &&
ltCache[i+2] === (options.interval||200)
) return obj.removeEventListener(evt, ltCache[i+3], options);
}
Example usage:
function throttle(func, alternateFunc, minimumInterval) {
var executeImmediately = true, freshEvt = null;
function handleFurtherCalls(f){
executeImmediately = true;
if (freshEvt !== null) func( freshEvt );
freshEvt = null;
};
return function(Evt) {
if (executeImmediately) { // Execute immediatly
executeImmediately = false;
setTimeout(handleFurtherCalls, minimumInterval);
return func( Evt );
} else { // Delayed execute
freshEvt = Evt;
if (typeof alternateFunc === "function") alternateFunc( Evt );
}
};
}
var ltCache = [];
function listen(obj, evt, func, _opts){
var i = 0, Len = ltCache.length, lF = null, options = _opts || {};
a: {
for (; i < Len; i += 4)
if (ltCache[i] === func &&
ltCache[i+1] === (options.alternate||null) &&
ltCache[i+2] === (options.interval||200)
) break a;
lF = throttle(func, options.alternate||null, options.interval||200);
ltCache.push(func, options.alternate||null, options.interval||200, lF);
}
obj.addEventListener(evt, lF || ltCache[i+3], _opts);
};
function mute(obj, evt, func, options){
for (var i = 0, Len = ltCache.length; i < Len; i += 4)
if (ltCache[i] === func &&
ltCache[i+1] === (options.alternate||null) &&
ltCache[i+2] === (options.interval||200)
) return obj.removeEventListener(evt, ltCache[i+3], options);
}
var numScrolls = 0, counter = document.getElementById("count");
listen(window, 'scroll', function whenbodyscrolls(){
var scroll = -document.documentElement.getBoundingClientRect().top;
counter.textContent = numScrolls++;
if (scroll > 900) {
console.log('Body scrolling stoped!');
mute(window, 'scroll', whenbodyscrolls, true);
}
}, true);
<center><h3>\/ Scroll Down The Page \/</h3></center>
<div style="position:fixed;top:42px"># Throttled Scrolls: <span id="count">0</span></div>
<div style="height:192em;background:radial-gradient(circle at 6em -5em, transparent 0px, rgba(128,0,0,.4) 90em),radial-gradient(circle at 10em 40em, rgba(255,255,255,.8) 0px, rgba(128,0,0,.02) 50em),radial-gradient(circle at 4em 80em, rgba(0,192,0,.75) 0px,rgba(0,128,0,.56) 10em,rgba(255,0,96,.03125) 30em),radial-gradient(circle at 86em 24em, rgba(255,0,0,.125) 0px,rgba(0,0,255,.0625) 60em,transparent 80em);"></div>
<style>body{margin:0}</style>
By default, this throttles the function to at most one call every 200ms. To change the interval to a different number of milliseconds, then pass a key named "interval" in the options argument and set it to the desired milliseconds.

Categories

Resources