Velocity.js - Buggy looping animation? - javascript

I have been testing a theory design for an animated mouse to indicate that the user of a website can scroll downwards. It's not complicated, and I've come up with a design which should be re-usable...
However for some reason if I try to clone the element and append it, it no longer get animated visually? However if I $.click() with jQuery, it fixes after one iteration.
Perhaps this is just a browser render issue? Please let me know if you cannot replicate the problem! Cheers
jsfiddle: https://jsfiddle.net/xw39e0bs/4/

Turns out that velocity calculates the start point based on current CSS values. So if you clone a moving element mid-motion, that will become the new start point. Therefore, one way to fix this is to provide forcefeeding.
Working example:
function mouse(){
$(".mouse .ball").velocity({
top: ["45%","25%"] //[TARGET_VAL,START_VAL]
},{
duration: 800,
easing: "swing",
}).velocity("reverse",{
delay: 2000,
complete: function(){
mouse();
}
});
}
mouse();
$("#clone").click(function(){
$(".mouse").last().clone().appendTo("#mice");
});
https://jsfiddle.net/xw39e0bs/5/

In this version we're reassigning the selector to bring in the cloned items. All of the clones then animate as expected.
complete: function(){
sel = $(".mouse .ball");
mouse();
}

Related

Javascript - how to animate scrollIntoView

I was only able to get a div on click into view with the scrollIntoView function, and it works as it should, just the way I want it, but I wonder is there a way to somehow animate it, and make it a bit slower?
I have tried with a suggestion from here:
function scroll(element, parent){
$(parent)[0].scrollIntoView(false);
$(parent).animate({
scrollTop: $(parent).scrollTop() + $(element).offset().top - $(parent).offset().top,
duration: 500,
easing: 'swing'
});
}
But it pushes the element to far up, it is not pushing it as it is on just:
$('#drawer')[0].scrollIntoView(false);
scroll = function(element, parent, time) {
$(parent).animate({
scrollTop: $(element)[0].offsetTop - $(parent)[0].offsetTop,
}, time, "swing");
}
You might want to add scrollIntoView, i don't know what that is for.
This works in jQuery 3.1.1 .
Check this out: http://demos.flesler.com/jquery/scrollTo/
Lots of options, I've used it several times with good results.

Interval doesn't clear immediately after repeating for a while

I have a bouncing arrow on my website that I created with Jquery and setInterval, like this:
bouncing = setInterval(function() {
$("div").animate({
top:"30px"
},100,"easeInCubic",function() {
$("div").animate({
top:"0px"
},100,"easeOutCubic");
});
console.log("bounced");
},200);
You can see this in place in a codepen here: http://codepen.io/mcheah/pen/wMmowr
I made it run faster than i needed because its easier to see the issues quicker. My issue is that after leaving the interval running for a few seconds, you'll notice that instead of bouncing back up or down immediately, the bouncing element will stop for half a second and then just hang there, before beginning again. If you leave it running even longer (20 seconds) and then clear the interval, you'll notice that it takes a few seconds to stop bouncing.
My questions are these:
Why does the bouncing go out of sync occasionally?
Why does the clear interval take a while to clear if it's been repeating for a while?
Is there a better way to have a bouncing arrow? Are CSS transitions more reliable?
Thanks for your help!
Your are trying to perfectly coordinate a setInterval() timer and two jQuery animations such that the two come out perfectly coordinated. This is asking for trouble and the two may drift apart over time so it is considered a poor design pattern.
If, instead, you just use the completion of the second animation to restart the first and make your repeat like that, then you have perfect coordination every time.
You can see that here in another version of your codepen: http://codepen.io/anon/pen/NxYeyd
function run() {
var self = $("div");
if (self.data("stop")) return;
self.animate({top:"30px"},100, "easeInCubic")
.animate({top:"0px"}, 100, "easeOutCubic", run);
}
run();
$("div").click(function() {
// toggle animation
var self = $(this);
// invert setting to start/stop
self.data("stop", !self.data("stop"));
run();
console.log("toggled bouncing");
});
It's not a good idea to mix animate() with timers this way. There's NO chance you can synchronize something like this. And there's no need to. You can simply append a function into the animation queue, look here: https://stackoverflow.com/a/11764283/3227403
What animate() does is put an animation request into a job queue which will be processed later, when the right time comes. When you break the interval the stuff that accumulated in the queue will still be processed. There's a method to clear the queue and stop all animation immediately.
The JQuery animation functions actually manipulate CSS, and there is nothing beyond it in HTML. Another option would be using a canvas, but it is a completely different approach and I wouldn't recommend it. With JQuery's animation your already at the best choice.
This is a simple solution to your problem:
function bounce()
{
$("div")
.animate({
top: "30px"
}, 100, "easeInCubic")
.animate({
top: "0px"
}, 100, "easeOutCubic", bounce); // this loops the animation
}
Start bouncing on page load with:
$(bounce);
Stop bouncing on click with:
$("div").click(function() {
$("div").stop().clearQueue().css({ top: "0px" });
// you want to reset the style because it can stop midway
});
EDIT: there were some inaccuracies I corrected now. The running example is on codepen now.
If you want to use javascript for animation you can use something better like the greensock tween library
http://greensock.com/docs/#/HTML5/GSAP/TweenMax/to/
something like this:
var tween = TweenMax.to($("div"), 100, {y: "100px", yoyo: true, repeat: -1});
You could wrap your interval code with:
if(!$("div").is(":animated"))
This will initiate your animation only if your previous one is finished.
The reason why it was bouncing weird is that your animations are queued.
You can check how it works now:
http://codepen.io/luminaxster/pen/XKzLBg
I would recommend using the complete callback when the second animation ends instead and have variable to control a bounce recursive call in this version:
http://codepen.io/luminaxster/pen/qNVzLY

jQuery animation code only running first instruction?

I'm fairly certain I'm being massively stupid here, but how can I run multiple jQuery animation instructions one after the other. The code below causes my box to move away from the left hand side correctly, but does not cause it to expand down.
click : function(){
$(this).not(".break").animate({left: '100%'}, 300);
$(this).slideDown(300);
},
You can split them into two:
$(this).not(".break").animate({left: '100%'}, 300);
$(this).children().slideDown(300).hide();

Animate/Slow down elements filling space left by removed element

Here is my example: http://jsfiddle.net/MT5xS/
When you click the first picture, it is removed and all the following images move back to fill the space left by it. But they move too fast and you don't even get the notion that they moved.
My question is, how do I make these elements move smoothly? Basically like an iPhone when you move or delete an icon, like this http://youtu.be/-r7K4LTbI4A?t=27s
I'm not worried about IE6/7/8 or any other compatibility issues.
The most common solution I know off is to animate hide(), then in the callback function remove your image.
$('.user-pic').live('click', function() {
var $item = $(this).closest('li');
$item.hide('slow', function(){ $item.remove(); });
});​
DEMO - Animate element removal
Take a look at this jQuery plugin: http://razorjack.net/quicksand/
It does what I think you are describing. You could use it or take a look under the covers to see how its being done. I believe they're using position: absolute on all the grid items.
Another option is to fadeTo 0, animate() the image width to 0, then remove().
http://jsfiddle.net/MT5xS/2/
Instead of removing the element on click, you want to fade the target element out and then remove the element. Note this cannot be accomplished by chaining remove after the desired animation.
If you chose to rely on old school setTimeout() you have to remember about correct variable scoping. Alternatively you could add a callback to be executed upon animation completion:
var $el = $(this).closest('li'); //no need to operate directly on img imo
$el.animate({
opacity: 0 //plus any other animation you want... height:0, width:0, ...
}, 1000, function() {
$el.remove();
});
Fiddled
I think what you want is to...
$(element).css("visibility", "hidden");
$(element).animate({"width": 0}, "slow", function() {
$(this).remove();
});
Here is the fiddle http://jsfiddle.net/MT5xS/4/
Try this it will slide up and then remove
$('.user-pic').live('click', function() {
$(this).closest('li').slideUp('slow', function() {
$(this).remove();
});
});​

JQuery animated banner

So I previously asked a question about how to create a banner like the one shown here and I got a really good answer to start me off. I have been working on it since and I'm having a lot of problems getting the animation to slide back to it's original position.
Here is my animation: http://jsfiddle.net/43nCF/ (don't click the green block first)
Issue: After the first time you toggle a block, clicking another block will not move it to the left.
I also have some other minor issues which I would be grateful if someone helped me with.
How do I get the width and the moving of the blocks to animate simultaneously like in the banner animation I am trying to replicate?
How do I get the block to slide back to the original position instead of just kind of 'transporting' there?
I am only beginner at jQuery so any help would be amazing.Thanks.
As for the positioning problem: you need to drop the left declaration in your second function.
Regarding making the animation act simultanous: animate both the right and the width property for each element, in one call:
function() {
var position = $.data(this, 'position');
var ind = $(this).index();
//moves image back to original position
$('#container div').each(
function() {
$(this).animate({
right: "",
width: 100
});
});
});
Working example here.
I see you have a response.
In case this version is of any help to you:
http://jsfiddle.net/vCbcz/
Instead of altering the divs other than the one being affected, I wrapped them all in a #slider div and adjusted that one's left margin to push it to the left.
$('#slider').animate({
marginLeft: '-' + ind * 105 + 'px'
});
and back
$('#slider').animate({
marginLeft: 0 + 'px'
});
There is a much easier way altogether of doing this. By using jQuery's scrollTo plugin, this can be done in a mere few lines of code, without using indices, calculations, or anything of that nature.
Live Demo http://jsfiddle.net/Jaybles/WEzny/

Categories