Hey guys I'm back with another question. I'm using the code below to add a bouncing effect to a div on my site. It works fine right now but the div has to be clicked in order for the effect to start. I would like to modify it so that when the user is scrolling down the page and reaches that section it triggers the effect automatically. How can I modify the code below to trigger the effect when the user scroll's down and reaches that section of the site?
Here is the code I' using
$(".servi-block").click(function () {
doBounce($(this), 2, '10px', 150);
});
function doBounce(element, times, distance, speed) {
for (i = 0; i < times; i++) {
element.animate({
marginTop: '-=' + distance
}, speed)
.animate({
marginTop: '+=' + distance
}, speed);
}
}
$(window).scroll(function(event){
isElementVisible = inViewport($(".servi-block"));
if(isElementVisible)
{
doBounce($(this), 2, '10px', 150);
}
});
function inViewport (el)
{
var r, html;
if ( !el || 1 !== el.nodeType ) { return false; }
html = document.documentElement;
r = el.getBoundingClientRect();
return ( !!r
&& r.bottom >= 0
&& r.right >= 0
&& r.top <= html.clientHeight
&& r.left <= html.clientWidth
);
}
This should help you out: http://api.jquery.com/scroll/
$( "#target" ).scroll(function() {
$( "#log" ).append( "<div>Handler for .scroll() called.</div>" );
});
Also utilize this
$('#target').on("mousewheel", function() {
alert($(document).scrollTop());
});
Those two together should get you the ability to figure out you are scrolling, and when you reach position X, do something.
EDITED
Let's go at it this way -
var targetPos = "500px";
$( document ).scroll(function() {
if ($(document).scrollTop() == targetPos) {
doBounce($(this), 2, '10px', 150);
}
});
You can simply check to see when the element comes into view by taking the element's offset and subtracting that element's parent height and scrollTop value.
Here's an example:
$(document).ready(function() {
$(document).on('scroll', function() {
var offset = $('.element').offset().top,
scroll = $(document).scrollTop(),
height = $(document).height(),
inViewDown = ((offset - scroll - height) <= 0) ? true : false;
if (inViewDown) {
// Do some stuff
}
});
});
Here's a working example: http://jsfiddle.net/ughEe/
Related
I'm really curious about this situation. I have a single page, and every page scrolled down has height of 1080px, but I can't calculate properly the scrollTop degree..
When I use a small monitor it fades in before div enters the monitor
$(window).scroll( function() {
if ( $(window).scrollTop() > 300 ) {
loadDiv2(); /* calls loadDiv2 Function below */
}
});
function loadDiv2() {
$('#hakkimizda').fadeIn('slow', function() {
$(this).fadeTo("slow", 1);
});
}
I solved with this code, thanks a lot.
function scrollfadein(selector, offset)
{
$(selector)
.css('opacity', 0)
.each(function(){
var el = $(this);
var fun = function()
{
offset = (offset == undefined) ? 0 : (offset < 1 ? offset*el.height() : offset);
if ( $(window).scrollTop() > el.offset().top - $(window).height() + offset )
{
el.animate({'opacity':1},1500);
$(window).off('scroll', fun);
}
};
$(window).on('scroll', fun);
});
}
scrollfadein('#hakkimizda,#yil_wrap', 0.3);
scrollfadein('#baklava', 0.9);
scrollfadein('#baklava_2', 0.5);
scrollfadein('#baklava_3', 0.9);
});
I have this javascript function I use that when clicked goes a certain distance. This is used within a scroller going left to right that uses about 7 divs. My question is how do I get the click to go the full distance first before the click can be used again? The issue is if the user rapidly clicks on the arrow button it resets the distance and sometimes can end up in the middle of an image instead of right at the seam. What code am I missing to accomplish this?
$(function () {
$("#right, #left").click(function () {
var dir = this.id == "right" ? '+=' : '-=';
$(".outerwrapper").stop().animate({ scrollLeft: dir + '251' }, 1000);
});
});
I would've thought that the easiest way would be to have a boolean flag indicating whether or not the animation is taking place:
$(function () {
var animating = false,
outerwrap = $(".outerwrapper");
$("#right, #left").click(function () {
if (animating) {return;}
var dir = (this.id === "right") ? '+=' : '-=';
animating = true;
outerwrap.animate({
scrollLeft: dir + '251'
}, 1000, function () {
animating = false;
});
});
});
works for me: http://jsfiddle.net/BYossarian/vDtwy/4/
Use .off() to unbind the click as soon as it occurs, then re-bind it once the animation completes.
function go(elem){
$(elem).off('click'); console.log(elem);
var dir = elem.id == "right" ? '+=' : '-=';
$(".outerwrapper").stop().animate({ left: dir + '251' }, 3000, function(){
$("#right, #left").click(go);
});
}
$("#right, #left").click(function () {
go(this);
});
jsFiddle example
You can see in this simplified example that the click event is unbound immediately after clicking, and then rebound once the animation completes.
Use an automatic then call like this
var isMoving = false;
$(function () {
$("#right, #left").click(function () {
if (isMoving) return;
isMoving = true;
var dir = this.id == "right" ? '+=' : '-=';
$(".outerwrapper").stop().animate({ scrollLeft: dir + '251' }, 1000).then(function(){isMoving = false}());
});
});
I think that you miss the fact that when you make stop() you actually position the slider at some specific point. I.e. if your scroller is 1000px and you click left twice very quickly you will probably get
scrollLeft: 0 - 251
scrollLeft: -2 - 251
So, I think that you should use an index and not exactly these += and -= calculations. For example:
$(function () {
var numberOfDivs = 7;
var divWidth = 251;
var currentIndex = 0;
$("#right, #left").click(function () {
currentIndex = this.id == "right" ? currentIndex+1 : currentIndex-1;
currentIndex = currentIndex < 0 ? 0 : currentIndex;
currentIndex = currentIndex > numberOfDivs ? numberOfDivs : currentIndex;
$(".outerwrapper").stop().animate({ scrollLeft: (currentIndex * divWidth) + "px" }, 1000);
});
});
A big benefit of this approach is that you are not disabling the clicking. You may click as many times as you want and you can do that quickly. The script will still works.
This will work perfectly fine:
var userDisplaysPageCounter = 1;
$('#inventory_userdisplays_forward_button').bind('click.rightarrowiventory', function(event) {
_goForwardInInventory();
});
$('#inventory_userdisplays_back_button').bind('click.leftarrowiventory', function(event) {
_goBackInInventory();
});
function _goForwardInInventory()
{
//$('#inventory_userdisplays_forward_button').unbind('click.rightarrowiventory');
var totalPages = $('#userfooterdisplays_list_pagination_container div').length;
totalPages = Math.ceil(totalPages/4);
// alert(totalPages);
if(userDisplaysPageCounter < totalPages)
{
userDisplaysPageCounter++;
$( "#userfooterdisplays_list_pagination_container" ).animate({
left: "-=600",
}, 500, function() {
});
}
}
function _goBackInInventory()
{
//$('#inventory_userdisplays_back_button').unbind('click.leftarrowiventory');
if(userDisplaysPageCounter > 1)
{
userDisplaysPageCounter--;
$( "#userfooterdisplays_list_pagination_container" ).animate({
left: "+=600",
}, 500, function() {
});
}
}
I second BYossarian's answer.
Here is a variation on his demo, which "skips" the animation when the user clicks several times quickly on the buttons :
$(function () {
var targetScroll = 0,
outerwrap = $(".outerwrapper");
$("#right, #left").click(function () {
// stop the animation,
outerwrap.stop();
// hard set scrollLeft to its target position
outerwrap.scrollLeft(targetScroll*251);
if (this.id === "right"){
if (targetScroll < 6) targetScroll += 1;
dir = '+=251';
} else {
if (targetScroll > 0) targetScroll -=1;
dir = '-=251';
}
outerwrap.animate({ scrollLeft: dir }, 1000);
});
});
fiddle
When you get to the limit of document, you can keep scrolling and can see an background behing the document before it bounces back (overscrolling).
How can I force the window to overscroll like this with javascript?
This is not the ultimate solution since I think the animation is imperfect and it's really only for desktops, but it can at least get you started. What I have done is increase the height of the body for animation on scroll.
$(document).on('scroll mousewheel', function (e) {
//Check for mousewheel scrolling down (or not used at all)
if (!e.originalEvent || !e.originalEvent.wheelDeltaY
|| e.originalEvent.wheelDeltaY < 0) {
if ($(window).height() + $(this).scrollTop() == $(this).height()) {
//Prevent simultaneous triggering of the animation
if (!$("body").data('bouncing')) {
$("body").height(function (_, h) { return h + 15; })
.data('bouncing', true);
$("body, html").animate({
'scrollTop': '+=15'
}, 125).animate({
'scrollTop': '-=15'
}, {duration: 125, complete: function () {
$(this).height(function (_, h) { return h - 15; })
.data('bouncing', false);
}});
}
}
}
}).on('keydown', function (e) {
//The "down" arrow; still bounces when pressed at the bottom of the page
if (e.which == '40') {
$(this).trigger('scroll');
}
});
I've been playing with this version that imitates the effect using a div, that slides in and out of view at the bottom of the page. If you have a high res monitor, you may need to increase the height of the main div to test it.
<div id="main" style="background:#f5f5f5;height:1000px"></div>
<div id="overscroll" style="background:#666666;height:120px"></div>
<script type="text/javascript">
var $doc = $(document);
$doc.ready(function () {
var $wnd = $(window),
$oscroll = $('#overscroll'),
block = false;
$wnd.bind('scroll', function () {
if (!block) {
block = true;
var scrollTop = $wnd.scrollTop(),
wndHeight = $wnd.height(),
docHeight = $doc.height();
try {
if (scrollTop + (wndHeight + 120) > docHeight) {
$oscroll.slideUp('slow');
}
else if ($oscroll.css('display') === 'none'
&& (scrollTop + (wndHeight + 120) < docHeight)) {
$oscroll.slideDown();
}
} finally {
block = false;
}
}
});
});
</script>
I've implemented an animation for my photo blog. I still have big problem because the 'body' element is activating the animation twice.
I think the problem stems from the $('body').animate. Because I think that when the body is animating, the scroll event would be activated again and thus triggering the event twice.
The problem of my code is scrolling the page up. When I scroll the page upwards. The scrollAnimatePrev will trigger and then $('body') element will animate itself. After the animation the animating variable is set to false. But the $('body') element triggers the scroll event because I guess when I set the scrollTop the scroll event is triggered. So once again currentPos is set to the $(window).scrollTop() then currentPos > previousPos returns true and !animating returns true so it will trigger the scrollAnimate.
Now I want to fix this. How?
$(function() {
var record = 0;
var imgHeight = $(".images").height();
var offset = $(".images").eq(0).offset();
var offsetHeight = offset.top;
var previousPos = $(window).scrollTop();
var animating = false;
var state = 0;
$(window).scroll(function() {
var currentPos = $(window).scrollTop();
console.log(currentPos);
if(currentPos > previousPos && !animating) {
record++;
scrollAnimate(record, imgHeight, offsetHeight);
animating = true;
} else if (currentPos < previousPos && !animating) {
record--
scrollAnimatePrev(record, imgHeight, offsetHeight);
animating = true;
}
previousPos = currentPos;
console.log(previousPos)
})
function scrollAnimate(record, imgHeight, offsetHeight) {
$('body').animate(
{scrollTop: (parseInt(offsetHeight) * (record+1)) + (parseInt(imgHeight) * record)},
1000,
"easeInOutQuart"
)
.animate(
{scrollTop: (parseInt(offsetHeight) * (record)) + (parseInt(imgHeight) * (record))},
1000,
"easeOutBounce",
function() {
animating = false;
}
)
}
function scrollAnimatePrev(record, imgHeight, offsetHeight) {
$('body').animate(
{scrollTop: ((parseInt(imgHeight) * record) + (parseInt(offsetHeight) * record)) - offsetHeight},
1000,
"easeInOutQuart"
)
.animate(
{scrollTop: ((parseInt(imgHeight) * record) + (parseInt(offsetHeight) * record))},
1000,
"easeOutBounce",
function() {
animating = false;
}
)
}
})
I think it might be firing that callback twice. I had a similar problem recently.
I had something similiar to
$('#id, #id2').animate({width: '200px'}, 100, function() { doSomethingOnceOnly(); })
It was calling my doSomethingOnceOnly() twice, and I thought it must have been the dual selectors in the $ argument. I simply made it 2 different selectors and it worked fine. So like this
$('#id').animate({width: '200px'}, 100);
$('#id2').animate({width: '200px'}, 100, function() { doSomethingOnceOnly(); );
Using a flag to control the trigger did the trick for me.
var targetOffset = 0;
var allow_trigger = true;
$('html,body').animate({scrollTop: targetOffset}, 'slow', function() {
if (allow_trigger) {
allow_trigger = false;
doSomethingOnlyOnce();
}
});
example page
I have a floating menu that i've built to the left side (green),
and i've made it start moving after 200 pixels. and now i need to to stop
and not go over the footer (blue) area.
any ideas how to make my JS better?
this thing is, I cannot check this on the scroll event, because of the animation
going on after i scroll, so it needs to be done someway else.
so how to make the animation stop at the end just before the footer?
I've resolved the issue perfectly (hope so)
with the help of you guys, and released
a jQuery plugin for floating sticky boxes:
http://plugins.jquery.com/project/stickyfloat
$.fn.menuFloater = function(options) {
var opts = $.extend({ startFrom: 0, offsetY: 0, attach: '', duration: 50 }, options);
// opts.offsetY
var $obj = this;
$obj.css({ position: 'absolute' /*, opacity: opts.opacity */ });
/* get the bottom position of the parent element */
var parentBottomPoint = $obj.parent().offset().top + $obj.parent().height() ;
var topMax = $obj.parent().height() - $obj.innerHeight() + parseInt($obj.parent().css('padding-top')); //get the maximum scrollTop value
if ( topMax < 0 ) {
topMax = 0;
}
console.log(topMax);
$(window).scroll(function () {
$obj.stop(); // stop all calculations on scroll event
// console.log($(document).scrollTop() + " : " + $obj.offset().top);
/* get to bottom position of the floating element */
var isAnimated = true;
var objTop= $obj.offset().top;
var objBottomPoint = objTop + $obj.outerHeight();
if ( ( $(document).scrollTop() > opts.startFrom || (objTop - $(document).scrollTop()) > opts.startFrom ) && ( $obj.outerHeight() < $(window).height() ) ){
var adjust;
( $(document).scrollTop() < opts.startFrom ) ? adjust = opts.offsetY : adjust = -opts.startFrom + opts.offsetY;
// and changed here to take acount the maximum scroll top value
var newpos = ($(document).scrollTop() + adjust );
if ( newpos > topMax ) {
newpos = topMax;
}
$obj.animate({ top: newpos }, opts.duration, function(){ isAnimated = false } );
}
else {
$obj.stop();
}
});
};
In the $(window).scroll function have you checked whether the bottom position of the floating div is less than or equal to the top position of the footer element.