Simplify functions so the code does not get too big - javascript

I have this code so that each element make the scroll effect when done:
I keep repeating the function to each element, the problem that are 30 elements with different classes to add, the code would be very large.
jQuery:
$(window).scroll(function () {
$('.regalos').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass("stretchLeft");
}
});
$('.sprite-Layer-2').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass("slideLeft");
}
});
// ... must 28
});

I would use:
$(window).scroll(function () {
var topOfWindow = $(window).scrollTop();
function _checkOffset(className) {
return function () {
var $this = $(this),
imagePos = $this.offset().top;
$this.toggleClass(className, (imagePos < topOfWindow + 400));
};
}
$('.regalos').each(_checkOffset('stretchLeft'));
$('.sprite-Layer-2').each(_checkOffset('slideLeft'));
});
However, you might be better off re-thinking your structure to avoid adding different class names based on the offset.

You could create a HashMap of Key/Value pairs (key = ID / Class, value = your string inside of .addClass()). However, this would only work if you only had a single class that you wanted to add via addClass for each key that you had.
Or you could have a complex HashMap, where the value was a an array, that you further iterated through if you really wanted to....

You can use something like this, as a global function and you pass array via the items.
var fn = function(args) {
for (var i = 0; i < args.elements.length; i++) {
var el = args.elements[i];
$(el).each(function() {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass(args.cls);
}
});
}
};
$(window).scroll(function() {
fn({
elements: ['.regalos', '.sprite-layer-2']
cls: 'stretchLeft'
});
});

1st, create the function once:
var myfunction = function(that, whichway) {
var imagePos = $(that).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(that).addClass(whichway); }
};
Then call it as often as you'd like:
$('.regalos').each(myfunction(this, 'stretchLeft'));
$('.sprite-layer-2').each(myfunction(this, 'slideLeft'));

You can pass a list of classes to the jQuery selector.
$(window).scroll(function () {
$('.regalos, .sprite-Layer-2').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass("stretchLeft");
}
});
});
But, I would add one class to all the elements and access them by that.

How about the following, where the key in the rules object is the class to add and the value is the selector for the items to get the class:
var rules = {
"slideLeft": ".sprite-Layer-2",
"stretchLeft": ".regalos",
"someOtherClass" : ".abc, .def, .ghi" // Multiple elements get this class
};
$(window).scroll(function () {
$.each(rules, function( className, selector) {
$(selector).each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass(className);
}
});
});
});

try the code below:
$(window).scroll(function () {
var topOfWindow = $(window).scrollTop();
$('.regalos').each(function () {
foo(this, 'stretchLeft');
});
$('.sprite-Layer-2').each(function () {
foo(this, 'slideleft');
});
});
function foo(that, classToBeAdded){
var imagePos = $(that).offset().top;
if (imagePos < topOfWindow + 400) {
$(that).addClass(classToBeAdded);
}
}

Related

Can this jQueryJjavaScript snippet be re-written more efficiently?

I am trying to write this code more efficiently. I've tried about 25 different permutations and it only seems to break it.
Basically, I am adding various classes to elements to trigger a css/keyframes animation when the window width is 1025px or greater.
And then there is another class being adding when it is less than 1024px which is intended to reveal the element without the element.
<script type="text/javascript">
var width = $(window).width();
if(width >= 1025) {
$(window).scroll(function() {
$('#about .image img.flex').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("slideLeft"); }
});
$('#author .image img.flex').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("slideRight"); }
});
$('#feed .blog_01').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("oneUp"); }
});
$('#feed .blog_02').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("twoUp"); }
});
$('#feed .blog_03').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("thrUp"); }
});
$('#feed .more').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+1000) { $(this).addClass("moreUp"); }
});
});
}
else {
$('#about .image img.flex').addClass('visible');
$('#author .image img.flex').addClass('visible');
$('#feed .blog_01').addClass('visible');
$('#feed .blog_02').addClass('visible');
$('#feed .blog_03').addClass('visible');
$('#feed .more').addClass('visible');
}
</script>
EDIT
Maybe it would be better to visualize it like this:
Perhaps it would be better to say how can I make this portion more efficient...
var width = $(window).width();
if(width >= 1025) {
$(window).scroll(function() {
$('#about .image img.flex').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("slideLeft"); }
});
$('#author .image img.flex').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("slideRight"); }
});
$('#feed .blog_01').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("oneUp"); }
});
$('#feed .blog_02').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("twoUp"); }
});
$('#feed .blog_03').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("thrUp"); }
});
$('#feed .more').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+1000) { $(this).addClass("moreUp"); }
});'
#icicleking's answer looks pretty great, but if you need to preserve you addClasses, you could iterate over the important values.
DEMO
var width = $(window).width();
// Make an array of data objects
var data = [
{ el: '#about .image img.flex', plus: 600, newClass: "slideLeft" },
{ el: '#author .image img.flex', plus: 600, newClass: "slideRight" },
{ el: '#feed .blog_01', plus: 600, newClass: "oneUp" },
{ el: '#feed .blog_02', plus: 600, newClass: "twoUp" },
{ el: '#feed .blog_03', plus: 600, newClass: "thrUp" },
{ el: '#feed .more', plus: 1000, newClass: "moreUp" }
];
if(width >= 1025) {
$(window).scroll(function() {
// Loop over the array of data objects
data.forEach(function(d) {
// For each object, target the el attribute for more looping...
$(d.el).each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
// ...use the plus attribute in this condition...
if (position < (top + d.plus)) {
// ...and add the newClass attribute
$(this).addClass(d.newClass); }
});
});
});
} else {
data.forEach(function(d) {
$(d.el).addClass('visible');
});
}
Caveat, triggering animation directly on scroll events is not an efficient way of animating. Others have written much more than I can say about this. When you say "efficient", I'm assuming here that you mean shorter, easier to read.
You could try something like this, sorry I didn't transpose your classes.
$(window).scroll(function() {
var top = $(window).scrollTop();
$('.all, .the, .selectors, .belong, .to, .us').each(function(e) {
var position = $(this).offset().top;
if ($(this).hasClass('.all') && position < top+1000) {
$(this).addClass('.slideThisClass');
}
else if($(this).hasClass('.the') && position < top+600) {
$(this).addClass('.theOtherSlideClass');
}
// etc.
}
}

How to add many divs in JavaScript code

I've been designing a web infographic with some animations within the page. So I added some JavaScript code in order to trigger the animations as the user reaches them on screen.
My question is how to add many div names in a JavaScript sentence?
The name of the div is "box_info_a", I just need to add some more, but have no idea how.
This is the code:
$(function()
var $window = $(window),
win_height_padded = $window.height() * 1.1,
isTouch = Modernizr.touch;
if (isTouch) {
$('.revealOnScroll').addClass('box_info_a');
}
$window.on('scroll', revealOnScroll);
function revealOnScroll() {
var scrolled = $window.scrollTop(),
win_height_padded = $window.height() * 1.1;
// Showed...
$(".revealOnScroll:not(.box_info_a)").each(function () {
var $this = $(this),
offsetTop = $this.offset().top;
if (scrolled + win_height_padded > offsetTop) {
if ($this.data('timeout')) {
window.setTimeout(function() {
$this.addClass('box_info_a ' + $this.data('animation'));
}, parseInt($this.data('timeout'), 10));
} else {
$this.addClass('box_info_a ' + $this.data('animation'));
}
}
}); // Close Showed...
// Hidden...
$(".revealOnScroll.box_info_a").each(function (index) {
var $this = $(this),
offsetTop = $this.offset().top;
if (scrolled + win_height_padded < offsetTop) {
$(this).removeClass('box_info_a lightSpeedIn')
}
});
}
revealOnScroll();
});
Just do this:
$(document).ready(function () {
$('#trigger').click(function () {
$('#target').addClass("oneClassToAdd anotherClassToAdd");
});
});
All you have to do is put two classes in the parentheses.

Jquery typing effect on scroll bug

Hi I have some js code that do typing effect on my web page it start typing when you scroll down end of page. For first it work normally but when you start scroll faster down to up the typing effect goes crazy how can I fix that
demo page
code
$(window).scroll(function (e) {
var elem = $(".hello-page");
var scrollTop = $(window).scrollTop();
var blockTop = elem.offset().top;
var docHeight = $(document).height();
var windowH = $(window).height();
if (scrollTop >= blockTop) {
var helloPageA = $(".hello-page").find("a");
var text = helloPageA.attr("data-text");
helloPageA.text('');
$.each(text.split(''), function (i, letter) {
setTimeout(function () {
helloPageA.html(helloPageA.html() + letter);
}, 150 * i);
});
} else {
elem.find("a").text('');
}
});
jsfiddle example
Thanks for your help
So, here is the solution - http://jsfiddle.net/u3ojjx8r/1/
I borrowed initial structure of the code from previous answer here and it was removed unfortunately, therefore I can't mention one of the co-authors. Though the code looked quite similar to topic-starter's one.
The idea of the code below is to separate the queuing of characters to render and the actual rendering. Another important improvement is always have control over timeouts, i.e. never schedule more than one timeout. That allows you to cancel them any time without unpredicted/uncontrolled behavior.
var timeoutVar;
var queue = [];
var drawQueueTimeout = -1;
var helloPageA = $(".hello-page").find("a");
function pushQueue (element) {
console.log('pushQUeue', element.char);
queue.push(element);
checkQueue();
}
function flushQueue () {
console.log('flushQueue');
queue = [];
clearTimeout(drawQueueTimeout);
drawQueueTimeout = -1;
}
function checkQueue () {
console.log('checkQueue', queue.length, drawQueueTimeout);
if (queue.length > 0 && drawQueueTimeout < 0) {
console.log('schedule drawQueue');
drawQueueTimeout = setTimeout(drawQueue, 150);
}
}
function drawQueue () {
drawQueueTimeout = -1;
console.log('draw queue');
if (queue.length > 0) {
var element = queue.shift();
console.log('drawQueue', element.char);
helloPageA.html(helloPageA.html() + element.char);
}
checkQueue();
}
$(window).scroll(function (e) {
var elem = $(".hello-page");
var scrollTop = $(window).scrollTop();
var blockTop = elem.offset().top;
var docHeight = $(document).height();
var windowH = $(window).height();
if (scrollTop + windowH == docHeight) {
// Empty anything typed so far
helloPageA.empty();
flushQueue();
var text = helloPageA.attr("data-text");
helloPageA.text('');
$.each(text.split(''), function (i, letter) {
pushQueue({
char: letter,
index: i
});
});
} else {
helloPageA.empty();
flushQueue();
}
});

jQuery TopDistance animation start?

I have a little problem with the script that I wrote.
Well, for some reason, it not refers to TopDistance which is declared to 850. Just one clicked on the down arrow and the animation starts.
Can you help with this early boot animation?
$(window).on('scroll', function () {
var scrollTop = $(this).scrollTop();
$('.projekt').each(function () {
var topDistance = $(this).offset().top;
if ((topDistance - 850) < scrollTop) {
$(this).addClass("animated fadeInRight");
}
});
});
$(window).on('scroll', function () {
var scrollTop = $(this).scrollTop();
$('.projekt').each(function () {
var topDistance = $(this).offset().top;
if ((topDistance - 850) < scrollTop) {
$(this).removeClass("projekt");
}
});
});
Take a look at this jsfiddle.
I've made one function instead of two and it works.
$(window).on('scroll', function () {
var scrollTop = $(this).scrollTop();
$('.projekt').each(function () {
var topDistance = $(this).offset().top;
if ((topDistance - 850) < scrollTop) {
$(this).addClass("animated fadeInRight").removeClass('projekt');
}
});
});

Simplify functions so this does not get too big

I have this code so that each element make the scroll effect when done: I keep repeating the function to each element, the problem that are 8 elements with different classes to add functions, the code would be very large.
$(window).scroll(function () {
$('#section6').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 200) {
svgEstatua.start();
}
});
});
$(window).scroll(function () {
$('#section2').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 225) {
svgBrain.start();
}
});
});
// must 5
array:
var groupSvg = [svgManos, svgSuper, svgInnovation, svgEstatua, svgBrain, svgBalanza];
Take out the common code and do something like this
function common(selector, svgObject, offset) {
$(selector).each(function () {
var imagePos = $(this).offset().top,
topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + offset) {
svgObject.start();
}
});
}
$(window).scroll(function () {
common('#section6', svgEstatua, 200);
});
$(window).scroll(function () {
common('#section2', svgBrain, 225);
});
You can then use your array or an object to loop though.

Categories

Resources