Animation pause issue in javascript - javascript

I have elements moving downwards which can be paused and resumed by pressing the P key. I tried every jQuery pause plugin out there, however once I pause the animation it won't resume. What am I doing wrong?
Spawning code:
$(document.createElement('img')).attr('src', source).
attr('class', 'snowflake').
css('left', x + 'px').
prependTo('body').animate({ bottom: '0' }, 5000, 'linear');
Pause function (called when the P key is pressed):
Snow.togglePause = function (label) {
'use strict';
if (Snow.paused) {
$('.snowflake').fadeIn(250);
$('.snowflake').each(function() {
$(this).resume();
});
Snow.paused = false;
} else {
$('.snowflake').fadeOut(250);
$('.snowflake').each(function() {
$(this).pause();
});
Snow.paused = true;
}
};
I also tried replacing the each function with just $('.snowflake').resume(); and it didn't work.
Edit: The solution was simple. I solved it in a couple of minutes when I sat down and did the math after Matthew pointed me to the right way. Here's the final formula.
http://i.stack.imgur.com/gs8mj.png
In my case the duration after resuming is DOCUMENT_HEIGHT * 5000 / ELEMENT.css('bottom'); Document height is the distance covered if not paused as the element will move from the top to the bottom. 5000 is the speed I chose at the start and the bottom property of the element is the distance the element will cover when resumed. This makes the speed constant and solves the problem. Thank you all for your help.
If you're a user trying to get the equation yourself, simply equate the speed at the start with the speed at the end and use v = d / t to get the formula.

It looks like to achieve this you will need to use queue and dequeue (and clearQueue):
There is some information on it here with a nice little demo:
http://api.jquery.com/clearQueue/
Essentially you are creating a queue for your animation and then dequeuing it when someone hits the pause button and queuing it up again when they hit resume.

If you using jQuery 1.8 and above, you can use progress function callback in animate method.
Link to animate documentation : http://api.jquery.com/animate/
You can save the state of the current animation in the element and restore it later.
Example (it's a draft, feel free to upgrade):
Link to the example : http://jsbin.com/egemaTA/2/edit
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
var $mydiv = $('div').animate({ bottom: '0' }, {
duration : 5000,
easing : 'linear',
progress : function(animation, progress, remainingMs){
$(this).data('stay', remainingMs);
}
});
$('#stop').click(function(ev){
$mydiv.stop();
});
$('#go').click(function(ev){
$mydiv.animate({ bottom: '0' }, {
duration : $mydiv.data('stay'),
easing : 'linear',
progress : function(animation, progress, remainingMs){
$(this).data('stay', remainingMs);
}
});
});
});
</script>
<style>
html, body{
height : 100%;
}
div{
position : absolute;
bottom : 100%;
width : 50px;
height : 50px;
background-color : lightblue;
}
</style>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<div></div>
<button id="stop">Stop !</button>
<button id="go">Go</button>
</body>
</html>

Related

returning the position of an element continuously

I have an object which is animated and falling from the top of the window to the bottom of the window. this works fine, but I would like to return the position of the element continuously.
At the moment I have this code
var pos = function() {
console.debug(jQuery('.element').position());
}
jQuery(window).on('mousemove', pos);
Which returns the position of the class "element" when the mouse is moving, I have also tried the event handler "live" but it is not working.
Is there any event handler I can use which will continuously return the position of them elemnt?
Thank you
Use .animate()'s step callback to track whatever you want, from position to timing:
var $test = $("span");
$("#element").animate({ top: 300 }, {
duration: 5000,
step: function(now, fx) {
$test.text( now );
}
});
#element{
position:absolute;
top: 0;
background:red;
width:40px;
height:40px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span></span> px
<div id="element"></div>
http://api.jquery.com/animate/
A small suggestion, if you don't want to lose your fingers writing jQuery all over the place....
jQuery(function( $ ){ // DOM ready and jQuery $ alias secured
// Free to use $ as you usually would
});
You could use setInterval to execute a function at given interval.
setInterval(function () {
// do something here
}, 1000); // each 1 sec, starts after 1s

How to adjust a Greensock.js tween based on browser scroll y position rather than by the time?

How would I go about adjusting the time manually based on the scroll position? What might that look like? To basically 'scroll' the tween? So that the tween reacts to the scrolling mouse's Y position rather than just trigger and execute based on a preset time?
IMHO, here is what you'll need to do:
You will need TimelineMax for sequencing your animations. Place
your animations in TimelineMax as you like them to be.
You'll need to figure out the maximum scroll position your window can scroll up to, beforehand. (This can also be re-calculated on browser resize as well but I haven't taken this into account in my example below). You can figure out with the
help of this answer. Also read the comments on that answer.
Upon scroll, you'll need to convert the current scroll position of
your window object into percentage that is: var currentScrollProgress=window.scrollY/maxScroll; such that your currentScrollProgress should always be between 0 and 1.
TimelineMax has a progress() method which takes values ranging
from 0 and 1 where 0 being the initial state of the animations
and 1 being the final state. Feed this currentScrollProgress
into it and you're done.
OR, you can tween the timeline itself that is: TweenMax.to(timeline,scrollTweenDuration,{progress:currentScrollProgress,ease:ease});.
Code used in my example is as follows:
HTML:
<div> </div>
<div> </div>
...
CSS:
html, body { margin: 0; padding: 0; }
div { width: 100%; height: 60px; margin: 2px 0; }
div:nth-child(odd) { background: #cc0; }
div:nth-child(even) { background: #0cc; }
JavaScript:
/*global TweenMax, TimelineMax,Power2*/
var myDIVs=document.querySelectorAll('div'),numDIVs=myDIVs.length;
var timeline=new TimelineMax({paused:true}),duration=.4,ease=Power2.easeOut,staggerFactor=.1,scrollTweenDuration=.4;
var scrollTimeout=null,scrollTimeoutDelay=20,currentScrollProgress=0;
var maxScroll=Math.max(document.body.scrollHeight,document.body.offsetHeight,document.documentElement.clientHeight,document.documentElement.scrollHeight,document.documentElement.offsetHeight)-window.innerHeight; //see [https://stackoverflow.com/a/17698713/3344111]
function init(){
initTimeline();
listenToScrollEvent();
onScroll();
}
function initTimeline(){
for(var i=0; i<numDIVs; i+=1){ timeline.fromTo(myDIVs[i],duration,{opacity:0},{opacity:1,ease:ease},i*staggerFactor); }
}
function listenToScrollEvent(){
(window.addEventListener)?window.addEventListener('scroll',debounceScroll,false):window.attachEvent('onscroll',debounceScroll);
}
function debounceScroll(){
clearTimeout(scrollTimeout);
scrollTimeout=setTimeout(onScroll,scrollTimeoutDelay);
}
function onScroll(){
currentScrollProgress=roundDecimal(window.scrollY/maxScroll,4);
//timeline.progress(currentScrollProgress); // either directly set the [progress] of the timeline which may produce a rather jumpy result
TweenMax.to(timeline,scrollTweenDuration,{progress:currentScrollProgress,ease:ease}); // or tween the [timeline] itself to produce a transition from one state to another i.e. it looks smooth
}
function roundDecimal(value,place){ return Math.round(value*Math.pow(10,place))/Math.pow(10,place); }
//
init();
Here is the resulting jsFiddle. Hope it helps.
T
While Tahir's answer is correct and sufficient, there's a lot of unnecessary code to show the example.
A more concise snippet is:
var max_scroll = document.body.offsetHeight - window.innerHeight;
win.addEventListener('scroll', function(){
var scroll_perc = parseFloat(Math.min(window.pageYOffset / max_scroll, 1).toFixed(2));
TweenMax.to(tl, 0, {
progress: scroll_perc
});
});
var tl = new TimelineMax({paused: true});
// the rest of your timeline....

Stuttering orbit animation when updating css through javascript over small interval

I'm trying to make some DOM element rotate smoothly around a fixed point. I'm writing this from scratch using jQuery and no matter what update speed I choose for the setInterval or how small I go with the amount of degrees the orbit advances on each loop, I get this janky staircase animation effect. I've tried using jquery's .animate instead of the .css hoping it would smooth things out but I cant seem to get it to work. Any help is appreciated.
In other words, it's not as smooth as rotating an image in HTML5 canvas. I want to make it smoother.
Here is a jsFiddle demonstrating the issue.
Notice how the animation is not quite smooth?
For reference, here is the code:
HTML
<div id="div"></div>
<div class="dot"></div>
<button class="stop">STOP</button>
<button class="start">START</button>
CSS
#div{
position:absolute;
height: 20px;
width: 20px;
background-color: #000;
}
.dot{
position:absolute;
width: 5px;
height: 5px;
background-color: #000;
}
button{
position:absolute;
}
.stop{
top:200px;
}
.start{
top:225px;
}
THE ALL IMPORTANT JAVASCRIPT
$(document).ready(function(){
$('#div').data('angle', 90);
var interval;
$('.stop').on('click', function(){
if(interval){
clearInterval(interval);
interval = undefined;
}
});
$('.start').on('click', function(){
if(!interval){
interval = setBoxInterval();
}
});
interval = setBoxInterval();
});
function drawOrbitingBox(degrees){
var centerX = 100,
centerY = 100,
div = $('#div'),
orbitRadius = 50;
//dot might not be perfectly centered
$('.dot').css({left:centerX, top:centerY});
//given degrees (in degrees, not radians), return the next x and y coords
function coords(degrees){
return {left:centerX + (orbitRadius * Math.cos((degrees*Math.PI)/180)),
top :centerY - (orbitRadius * Math.sin((degrees*Math.PI)/180))};
}
//increment the angle of the object and return new coords through coords()
function addDegrees(jqObj, degreeIncrement){
var newAngle = jqObj.data('angle') + degreeIncrement;
jqObj.data('angle', newAngle);
return coords(newAngle);
}
//change the left and top css property to simulate movement
// I've tried changing this to .animate() and using the difference
// between current and last position to no avail
div.css(addDegrees(div, degrees), 1);
}
function setBoxInterval(){
var interval = window.setInterval(function(){
drawOrbitingBox(-0.2); //This is the degree increment
}, 10); //This is the amount of time it takes to increment position by the degree increment
return interval;
}
I'd rather not resort to external libraries/plugins but I will if that's the accepted way of doing this kind of stuff. Thank you for your time.
That's because the value you set for top and left properties is rounded up. You should try using CSS Transforms.
Combining CSS Animations/Transitions and CSS Transforms you should also be able to get the animation without JavaScript.
Oh, I run into that myself!
There is actually nothing you can do, the stuttering you see is the pixel size. The pixel is the minimal step for css based animations, you can't do "half pixels" or "0.2 pixels". You will see that the same keeps happening with css3 animations.
The only solution is to speed up your animation, i'm afraid.
Also, cosndsider using rquestAnimationFrame instead of interval: https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame

Animated PNG background with Javascript, but without loop?

I need help with an animated PNG in Javascript.
I found how to animate a PNG background with Javascript here on Stack Overflow. But my problem is that I only need the animation onmouseover and onmouseout. And the animation should play only once, not in a loop, so when the user moves the mouse over a div the the animation in the background should play once and stop at the last frame, but when the user goes off the div, a reverse animation should play once and stop at the last (first) frame. The script I found here is:
The style:
#anim {
width: 240px; height: 60px;
background-image: url(animleft.png);
background-repeat: no-repeat;
}
The HTML:
<div id="anim"></div>
Javascript:
var scrollUp = (function () {
var timerId; // stored timer in case you want to use clearInterval later
return function (height, times, element) {
var i = 0; // a simple counter
timerId = setInterval(function () {
if (i > times) // if the last frame is reached, set counter to zero
i = 0;
element.style.backgroundPosition = "0px -" + i * height + 'px'; //scroll up
i++;
}, 100); // every 100 milliseconds
};
})();
// start animation:
scrollUp(14, 42, document.getElementById('anim'))
I hope anyone can help me, Thank you
To stop the animation after the first set of frames you do want to change the if condition to not reset the counter to zero but instead to clear the interval and stop it from reoccuring.
To only let it play when you enter an element you can attach the animation function as an event listener and play the whole thing in reverse with another function that you plug into your onmouseout event.
Depending on your target browser and since your question is fairly vague I can recommend two alternatives to you:
Use jQuery animate (all browsers, include ref to jquery)
//Animate to x,y where x and y are final positions
$('#anim').mouseenter(function(e) {
$(this).animate({background-position: x + 'px ' + y + 'px'}, 4200);
})
//Do same for mouseleave
Use a css3 animation (using -webkit browser here)
<style>
#-webkit-keyframes resize {
100% {
height: 123px;
}
}
#anim:hover {
-webkit-animation-name: resize;
-webkit-animation-duration: 4s;
}
I would choose option 2 if you are doing mobile development or can choose only css3 capable browsers.

Need help with animation on JavaScript without jQuery

I have got a div object for example (Simple Image), and I need my picture to move to right and left and backward without any frame and border. My picture will collide with end (right side of my page) and move backward to left and then action with right side too. This will be only on JavaScript.
Edit:
<html>
<head>
<script>
function dvig () {
var xx = 50;
var corner_left=200 +'px';
var corner_right=100 +'px';
var move; var move2;
var dv=document.getElementById("adam");
if(dv.style.left<=corner_right) {
move=1;
move2=1;
}
if(dv.style.left>=corner_left) {
move2=0;
move=0;
}
if(move=1) {
dv.style.left=parseInt(document.getElementById("adam").style.left)+xx;
}
if (move2=0) {
move=0;
dv.style.left=parseInt(document.getElementById("adam").style.left)-xx;
}
}
function chustro() {
setInterval("dvig()", 100);
}
</script>
</head>
<body onload="chustro()">
<img id="adam" style="position: absolute; top: 100px; left: 100px; width: 40px; height: 40px; background-color: red">
</body>
</html>
Your going to have to setup a iterative process that runs every X milliseconds. Each time its run you have to update the div's position a bit and check if it hits a side and reverse direction.
function doWork{
// move current direction a little
// check if past the left edge and change directions
// check if past the right edge and change direction
}
setInterval(doWork, 10);
Update:
Based on your code, check this example:
http://jsfiddle.net/HT9A4/

Categories