jQuery TopDistance animation start? - javascript

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');
}
});
});

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.
}
}

jQuery absolute sidebr scrolling, stop at the top of parent and at bottom

hi guys so i have this code ive done which when scrolling the sidebar moves up from bottom to top but im stuck with how to stop the scrolling once the sidebar hits the top of the main conatiner - can someone maybe help me with this?
code is:
$(window).bind('scroll', function () {
var scrolledY = $(window).scrollTop();
$('.parallax-sidebar').css('bottom', '+' + ((scrolledY * 1.3)) + 'px');
});
I have a fiddle example here: http://jsfiddle.net/06qwtgt6/1/
Many thanks!
$(document).ready(function () {
/********************************************************************************/
/* Parallax Scrolling */
// Cache the Window object
var $window = $(window);
$('[data-type]').each(function () {
$(this).data('offsetY', parseInt($(this).attr('data-offsetY')));
$(this).data('Xposition', $(this).attr('data-Xposition'));
$(this).data('speed', $(this).attr('data-speed'));
});
// For each element that has a data-type attribute
$('div[data-type="background"]').each(function () {
var $self = $(this),
offsetCoords = $self.offset(),
topOffset = offsetCoords.top;
$(window).bind('scroll', function () {
if (($window.scrollTop() + $window.height()) > (topOffset) &&
((topOffset + $self.height()) > $window.scrollTop())) {
var yPos = -($window.scrollTop() / $self.data('speed'));
if ($self.data('offsetY')) {
yPos += $self.data('offsetY');
}
var coords = '50% ' + yPos + 'px';
$self.css({ backgroundPosition: coords });
};
});
});
// For each element that has a data-type attribute
$('div[data-type="content"]').each(function () {
$(window).bind('scroll', function () {
var scrolledY = $(window).scrollTop();
$('.parallax-content').css('bottom', '+' + ((scrolledY * 1.3)) + 'px');
});
});
$(window).scroll(function(){
if ($(this).scrollTop() > 150) {
$('.sidebar').addClass('fixed');
} else {
$('.sidebar').removeClass('fixed');
}
});
});
CSS
.fixed {position:fixed; top:0;}
DEMO

How do I call a function only once during a specific scroll height?

I have a map on the bottom of my webpage and when a user scrolls down to the map, I want the google marker to drop and that specific time. I have this working already. The problem is that it keeps calling the function, how do I call it only once?
This is my JS code right now and I have tried to figure the bug out:
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 300 &&
$(window).scrollTop() <= $(document).height() - $(window).height() - 200
) {
var dropOnlyOnce = (function(){
dropped = false;
if (dropped == false) {
dropMarker(); // this is the function I'm calling
}
dropped = true;
})();
}
});
How can I get this to work or how can I just call the dropMarker function once?
You could remove the listener once the function has been called:
$(window).on('scroll', function(e) {
if( ...window at scrollTop ) {
$(window).off('scroll')
.... Drop your pin
}
})
Esteban Felix's Comment brings up a good point. This will remove all scroll handlers. If that's not something that works for you, you can move the function outside the handler, and only remove that:
var dropPinOnce = function() {
if( ... window at correct scrollTop ) {
... Drop pin here ...
$(window).off('scroll', dropPinOnce)
}
$(window).on('scroll', dropPinOnce)
Try
var callbacks = $.Callbacks("once")
, dropMarker = function() {
// do stuff
};
callbacks.add(dropMarker);
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 300 &&
$(window).scrollTop() <= $(document).height() - $(window).height() - 200
) {
var dropOnlyOnce = (function(){
dropped = false;
if (dropped == false) {
callbacks.fire() // call `dropMarker` "once"
}
dropped = true;
})();
}
});
See jQuery.Callbacks at "Possible Flags" -> "once"
var callbacks = $.Callbacks("once")
, dropMarker = function() {
console.log(123)
};
callbacks.add(dropMarker);
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 300 &&
$(window).scrollTop() <= $(document).height() - $(window).height() - 200
) {
var dropOnlyOnce = (function(){
dropped = false;
if (dropped == false) {
// dropMarker(); // this is the function I'm calling
callbacks.fire()
}
dropped = true;
})();
}
});
div {
height : 500px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>abc</div>
If you just unbind after your condition is met then your function will effectively only be called once.
$(window).scroll(function callOnceOnScroll() {
var $window = $(window),
$document = $(document);
if ($window.scrollTop() >= $document.height() - $window.height() - 300 &&
$window.scrollTop() <= $document.height() - $window.height() - 200) {
$window.off('scroll', callOnceOnScroll);
dropMarker(); // this is the function I'm calling
}
});

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.

Simplify functions so the code 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 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);
}
}

Categories

Resources