I'm animating one circle which scales, collides with two circles nearby it, and causes those circles to be animated to a certain position. Everything works, except when those two circles are animated to their post-collision position they continue to move. If you run my fiddle you'll notice that afterwards the two circles which collide with the bigger circle will actually continue to inch very slowly away from the circle well after the animation is complete. I tried .stop(true,true) on the animate function for the middle circle, called 'boss', but that only makes it so the middle circle isn't shown to grow. I tried .finish() on the boss growth animation but that doesn't help the other circles which continue to inch away well after the animation is complete.
FIDDLE: http://jsfiddle.net/direlelephant/fMLKZ/2/
EDIT: This is true whether I set the position of the divs to fixed or to absolute.
EDIT: I also tried .clearQueue() and .stop(true, false) and stop(true). ClearQueue() did nothing to help the problem, stop(true,false) prevented the middle circle from animating, as did stop(true).
The problem is: you create animations within loop. Replace part of your code with
if ( distanceformula( xcoord3, xboss, ycoord3, yboss ) < ((boss.outerWidth() / 2) + (objectify3.outerWidth() / 2)) ) {
console.log(1)
$( objectify3 ).animate( {
left: xmove3 + "px",
top: ymove3 + "px"
}, {
duration:3000,
step: function() {
console.log(2)
}
});
}
and open console.
You will see, that you created ~1000 animations (console.log(1) executes 1000 times) $( objectify3 ).animate, and then jQuery run 1000 animations one after one. They will end in ~1000 * 3000 seconds.
I think you need a flag and run animations only once with first intersection.
Related
So I have two sections of content near the top of my page and I’d like for users who have scrolled down to near the top of the second section to get “scroll snapped” to the top of the second one once they have stopped scrolling.
I think it should be possible using jQuery but I haven’t been able to figure it out. Here are my examples:
Without my attempt: http://codepen.io/jifarris/pen/gaVgBp
With my broken attempt: http://codepen.io/jifarris/pen/gaVgQp
Basically I can’t figure out how to make it try scrolling to the spot only once, after scrolling has stopped. It’s kind of just freaking out.
I love how the recently introduced scroll snap points CSS feature handles scroll snapping and I’d almost prefer to use it – for the browsers that support it, at least – but it seems like it only works for items that take up 100% of the viewport height or width, and it seems like it’s for scrolling within an element, not the page itself.
The top section has a fixed height, so this really can be handled with pixel numbers.
And for reference, here’s the heart of the code from my attempt:
$(function() {
$(document).on('scroll', function() {
var top = $(document).scrollTop();
if (top > 255 && top < 455) {
$('html, body').animate({scrollTop: '356'}, 500);
$('body').addClass('hotzone');
} else {
$('body').removeClass('hotzone');
}
});
});
KQI's answer contains most of the steps required to create a well functioning section-scroll for use in your application/webpage.
However, if you'd just want to experiment yourself, developing your script further, the first thing you'll have to do is add a timeout handler. Otherwise your logic, and therefor scrollAnimation, will trigger every single pixel scrolled and create a buggy bouncing effect.
I have provided a working example based on your script here:
http://codepen.io/anon/pen/QjepRZ?editors=001
$(function() {
var timeout;
$(document).on('scroll', function() {
clearTimeout(timeout);
timeout = setTimeout(function() {
var top = $(document).scrollTop();
if (top > 255 && top < 455) {
$('body').animate({
scrollTop: '356'
}, 500);
$('body').addClass('hotzone');
} else {
$('body').removeClass('hotzone');
}
}, 50);
});
});
Good luck!
All right, there are couple of things you gonna have to deal with to get a good result: which are performance, call stack queue, easing.
Performance wise you should drop jQuery animate and use VelocityJs which gives a smoother transition, better frame per second (fps) to avoid screen glitches especially on mobiles.
Call stack: you should wrap whatever logic you have to animate the scrolltop with 'debounce' function, set the delay for let say 500mm and check the scrolling behavior. Just so you know, the 'scroll' listener your using is firing on each pixel change and your script will go crazy and erratic. (It is just gonna be a moment of so many calc at the same time. Debounce will fix that for you)
Easing: make the transition looks cool not just dry snappy movement.
Remember, 'easing' with Velocity starts with 'mina.' i.e.
'Mina.easingFnName'
Finally, your logic could be right, i am in my phone now cannot debug it but try to simplify it and work with a single problem at once, be like i.e.
If ( top > 380 ) // debounce(...)
I have a row of icons on my page and i want to create a wave animation effect when user hovers over them with the cursor.
I'm using this basic code for starters:
$('#icons > li')
.hover(function() {
$(this).animate({
'top': (-1 * hover_distance)
}, hover_speed);
}, function() {
$(this).animate({
'top': 0
}, hover_speed);
})
;
And it looks OK. But there is one issue: when you move your cursor frantically over the icons, the animation queue for every icon is becoming filled with lots of actions (up, down, up, down, up, down, etc) and icons is going up and down lots of times even if you stop to interact with the icons.
I want my icons to complete only one cycle (up and down) and then stop the animation. I'm looking for a most elegant (short, simple, light) solution for this.
PS: And you can't just use stop() because it will prevent the "wave effect" (i.e. when you move your cursor with one fast stroke over the icons and they move up and down in response, like a real wave).
PPS: Here's the JS-Fiddle:
http://jsfiddle.net/nZqLy/3/
You can use .stop() before the animations to stop the current animation or .stop(true) to cancel all animations in the queue. http://jsfiddle.net/nZqLy/9/
$('#icons > li').hover(function() {
$(this).stop(true).animate({
'top': (-1 * hover_distance)
}, hover_speed);
}, function() {
$(this).animate({
'top': 0
}, hover_speed);
});
I upvoted the answer by #jimjimmy1995, but just to provide an alternative way of doing the same animation which will be faster and more efficient:
$('#icons').on({
mouseenter:function(){
$(this).stop().animate({top:(-1*hover_distance)},hover_speed);
},
mouseleave:function(){
$(this).stop().animate({top:0},hover_speed);
}
},'li');
The only differences are:
The use of .on() is more transparent, but also allows for more extensibility (you can add more on events later, like mousemove or something, if you want)
Delegation of all li from #icons rather than making #icons > li the selector means the animation binding is only applied once, rather than many times (one time for each li) - this is the most important of the three changes
Using the native DOM name rather than the string (top vs 'top') is a best practice. It makes no difference for non-hyphenated words, but when you start dealing with marginTop vs 'margin-top' it makes a difference.
UPDATE
Found the solution:
$('#icons').on({
mouseenter:function(){
if(!$(this).is(':animated')){
$(this).animate({top:(-1*hover_distance)},hover_speed);
}
},
mouseleave:function(){
$(this).animate({top:0},hover_speed);
}
},'li');
Using the :animated selector checks if the item is in progress of being animated. The if logic will only perform the animation if it is not.
jsFiddle to prove it.
I have a row of images that are moving left or right with animate(). I am trying to make these images loop infinitely so when you click next the last image moves to the first position. Why doesn't $(this).css("left", "-320px"); work in the if statement below.
$("#right").click(function(){
$("#sliderWindow").find("img").each(function(i) {
var left = $(this).css("left");
$("#imageContainer" + i).animate({"left": "+=220px"}, "slow");
left = parseInt(left);
left += 220;
left = left + "px";
if(left === "1220px") {
//Why doesn't this work?
$(this).css("left", "-320px");
}
});
});
That code is pretty messed up. :P But I think your statement is working, if only for an instant.
I'm going to assume that the <img>s returned by find("img") are the same as your elements with ID "imageContainerN". In which case, the problem is probably that you are setting its position while it is in the middle of an animation. It probably ends up at -320px at that moment and remains there until the next animation tween which likely happens a few milliseconds later.
You could try something more like this (the important part is swapping the order of the animation and test)...
$("#right").click(function() {
$("#sliderWindow").find("img").each(function() {
if (this.offsetLeft >= 1220) {
$(this).css("left", "-320px");
}
$(this).animate({left: "+=220px"}, "slow");
});
});
Reason
Consider what happens when you set up an animation in jQuery.
1) jQuery sees you want to go +220px from current position
2) Let's say the image is currently at 100px... then jQuery says, "Okay, I'll take you from 100px to 320px over the course of, say 1 second
3) jQuery now forgets about the image's current position and just calculates where it should be to satisfy the original animation parameters on each tween
After the animation begins, you then do your if statement to reposition the element, so the following might be what happens over time...
1) Animation calculated based on parameters (current position 100px, desired position 320px)
2) After 10 millisecond, the image moves to 102.2
3) Your code executes (pretend it returned true for the current 102.2 position)
4) Your code repositions the image to -320px
5) The animation tweens again after 10ms and moves the image to 104.4px (it now appears that your image was never moved to -320px)
6) The animation tweens again and moves the image to 106.6px
7) The animation tweens again and moves the image to 108.8px
8) And so on until the image ends up at 320px
I hope that makes sense. I haven't actually looked at the jQuery animation code, but this is likely what was happening.
I'm using the jquery slider function for a timeline
$("#content-slider").slider({
min: 0,
max: 300,
step: 1,
change: handleSliderChange,
//start: getImageWidth,
slide: handleSliderSlide
});
function handleSliderSlide(event, ui) {
$("#content-scroll").prop({scrollLeft: ui.value * (maxScroll / 300) });
if (ui.value >= 7 && ui.value <= 13) {
$('#marker_10').animate({opacity: 'hide'}, 100, function () { $(this).parent('div').animate({marginTop: '100px'}, {duration:1000, queue:false }).addClass('up').find('p').animate({opacity: 'show'} ) })
}
if (ui.value > 13 || ui.value < 7 && ($('div#container_10').hasClass('up'))) {
$('div.up').stop(true)
$('#container_10').removeClass('up').find('p').fadeOut('fast').end().animate({marginTop:'165px'}, {duration:500, complete:function() {$(this).find('img.marker').fadeIn() }, queue:false})
}
}
http://asla.dev.1over0.com/html/slider/bacardi_last.html
It animates ok when I scroll left to right but when I scroll right to left then I get some issues where elements are fading out and displaying correctly
any information would be appreciated; this is all done on the front end currently
Thank you
I don't have a solution directly, but some notes that may help.
The down animation isn't triggered until the slider is past the left edge of the active content. To the right, it's triggered immediately after the slider moves off of the vertical line.
Several of the sections have content cut off the bottom - seems like a simple height issue?
When sliding right to left, the vertical line doesn't disappear.
You may want to add a "title" to "#content-slider a" as new users may not be sure what it does at first. A simple "Slide Me" would suffice :)
One additional note, when the browser window is small (around 800px or so, didn't check exactly), the content jumps below the slider bar.
Just thinking about how I'd approach this task; I'd setup animations in a function for animating up, then one for down. After I can verify they work on button press (or some non-slider trigger) I'd work on ensuring the "active" areas are setup correct on the time line (either the vertical line or the whole "active" content box, personally I'd do something in the middle). After those pieces are setup, should be an easy task to trigger the up movement function when the slider is in the "active" area and down when it leaves, making sure they don't run at the same time.
Hope it helps!
I have a somewhat difficult animation to do in JQuery, and I haven't found a good way to handle it. I have a mobile site with a scene on the screen which displays a series of choices. When a choice is made, the choices slide off screen, and simultaneously a new scene of a city is brought in (it's supposed to simulate driving) - and this scene, instead of stopping in the center of the screen, it passes all the way through the opposite end of the screen. The problem is, when it gets to the center, I want to trigger a new div to come in just behind it, matching the speed, etc, so everything appears in synch.
If I set the animation for the city scene to be in two parts, once to the center where it could trigger the new choice scene coming in, and once to go off screen, there is a noticeable jerk. And I haven't found a way to trigger a delay, because at the end of the delay I need to make a call to a custom function, not a jquery function. So this is my code:
Driving Scene (called when choices begin animating out):
$('#interlude').animate({marginLeft: -viewportW + "px"},3000,'linear',function(){
$('#interlude').remove();
displayScene(sceneID); //need to figure out how to call this at the halfway point
});
Use setTimeout() right before your animation to trigger the second animation halfway through the first animation.
var animateTime = 3000;
setTimeout("displayScene(" + sceneId + ")", animateTime / 2);
$('#interlude').animate({marginLeft: -viewportW + "px"},animateTime,'linear',function(){
$('#interlude').remove();
});