Reversing an Animation

How to reverse an infinate animation in Web Animation API?

The behavior of reverse(), like play(), is that if the animation is at the "end", it jumps back to the start and begins playing.

For reverse() this means that if the current time is zero when you call it (as in your example), then it should jump back to the beginning. However, if your animation has an infinite length, that would mean jumping to infinity!

If you simply want to run the animation's keyframes backwards, you can use the direction property.

For example:

animation.effect.updateTiming({ direction: 'reverse' });

Note, however, that unlike reverse(), updating the direction while an animation is in progress can cause it to jump position.

If you want to be able to change the animation direction backwards and forwards while it is in progress and make it repeat forever, you can either:

  1. Set a very long iteration count and start the animation in the middle of that range, or

  2. Use updateTiming({ direction: 'reverse' }) and adjust the currentTime so that it doesn't jump. Something like the following might work:

     const ct = animation.effect.getComputedTiming();
    animation.currentTime =
    ct.currentInteration * ct.duration +
    (ct.duration - ct.localTime % ct.duration);

Note further that even using updateTiming as in (2) can cause the animation to jump a little if the animation is running asynchronously (e.g. most transform and opacity animations) since there can be some small lag between the timing on the main thread where your Javascript runs and the thread/process where the animation is being run.

Using reverse() as in (1) (or updatePlaybackRate()) avoids that problem since it synchronizes any async animations before updating them.

Proper way of reversing an animation with Vanilla JS?

It's because both .grow and .reverse attached to .inner and that's messing things up. You have to remove .grow before adding .reverse. However, this time when you remove .grow animation, the div's height will decrease to 52px again, so you must keep its height before you apply .reverse. However(again), you need to decrease .inner's height after running .reverse, otherwise it won't lose its height. So you can do something like this:

reverse.addEventListener('click', function() {
inner.classList.remove('grow');
inner.style.height = '100%';

// You need setTimeout() idk why
setTimeout(function() {
inner.classList.add('reverse');
inner.style.height = '52px';
}, 10);
})

How to do reverse animation from the animated position in android?

Usually reversing your 'from' and 'to' float parameters f.e. :

ObjectAnimator.ofFloat(fingerPrintImage, "scaleX", 1, 1.3f) // forward

ObjectAnimator.ofFloat(fingerPrintImage, "scaleX", 1.3f, 1) //backward

gives you an backward effect.

For animations like this, I strongly recommend ViewPropertyAnimator. It is super concise and has less code, no need for AnimationSets (which are often buggy), and you can chain different animations in one line :

private void rotateImage(boolean isReverse) {
if(isReverse){
fingerPrintImage.animate().rotationBy(-60).scaleXBy(0.3f).scaleYBy(0.3f).setDuration(5000);
} else {
fingerPrintImage.animate().rotationBy(60).scaleXBy(-0.3f).scaleYBy(-0.3f).setDuration(5000);
}

Maybe you have to tweak your values a bit, but this should be all you need.

Even shorter and more dynamic would be passing all float values through function parameters :

private void rotateImage(View view, float rotate, float scaleY, float scaleX, long duration) {
view.animate().rotationBy(rotate).scaleXBy(scaleX).scaleYBy(scaleY).setDuration(duration);
}

which then can be called like :

rotateImage(fingerPrintImage, 60, 0.3f, 0,3f, 5000); // forward
rotateImage(fingerPrintImage, 60, -0.3f, -0.3f, 5000) //backwards

this minimizes code, gets rid of the isReverse boolean, and you are also able to reuse the method with different parameters for further animations.

Reverse a CSS animation

If it were a simple color change, I would've also recommended CSS transitions like in Martin's answer but as you've explained that it is something more complex, Osama8DZ's answer is your best solution. But that doesn't give an answer to your question, which states the following (emphasis is mine):

And I want to reverse the animation when I click on the small button but what I did doesnt work and I don't understand why.

Reason:

When you click on the button which causes the reverse animation to trigger, the class name changes and so the original animation is replaced with the reverse animation. This is actually two steps - first is removal of the original animation and second is addition of the reverse.

Whenever an animation that exists on an element is removed, the element immediately snaps to what was its original state (which is, the one before the animation). Here the element had red background in its original state. Thus the element immediately gets a red background and then the reverse animation has no visual effect because it is animating from a red background to a red background.

You can see a sample of what I mean in the below snippet. I added a left and top margin to the original state of the element and changed it during the forward animation. As soon as the reverse button click is performed, the shape immediately goes back to original state and then applies the left, top margins provided within the reverse animation.

var div = document.getElementById('fab');
function anim() { div.className = "anim";}
function animrev() { div.className = "animrev";}
html,body {  height: 100%;  width: 100%;}#content {  height: 100%;  width: 100%;  display: flex;  align-items: center;  justify-content: center;}#fab {  margin-right: 30px;  color: white;  font-size: 45px;  outline: 0;  border: 0;  height: 150px;  width: 150px;  border-radius: 75px;  text-align: center;  background-color: red;  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);    /* added these for demo */  margin-left: 20px;  margin-top: 10px;}.anim {  animation-name: example;  animation-duration: 1s;  animation-fill-mode: forwards;}@keyframes example {  100% {    background-color: green;    left: 0px;    top: 0px;        /* added these for demo */    margin-left: 40px;    margin-top: 20px;  }}@keyframes exampleux {  100% {    background-color: red;    left: 0px;    top: 0px;
/* added these for demo */ margin-left: 30px; margin-top: 15px; }}.animrev { animation-name: exampleux; animation-duration: 1s; animation-fill-mode: forwards;}
<div id="content">  <button onclick="anim()" id="fab">+</button>  <button onclick="animrev()" id="fab2">+</button></div>

How do I reverse the animation of a drawing in P5JS (more details in post)

There's no automatic way to rewind an animation like this. You could do something very memory intensive such as saving every frame of the animation as an image and then playing the whole thing backward, but this would use a lot of memory. Instead you can just reverse the logic that animates the various shapes:

let masks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // Create Masks for Artwork Background
let switches = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // To switch on each background line

let mainMask = 400; // Create Main mask to reveal artwork

let cityActiveState = 0; // To determine if the current artwork is active or erased -- either 0 or 1.

let sunXPos = 0; // To Move the sun around
let sunYPos = -100;

let rods = -100; // Animate lightning rods for city

function setup() {
createCanvas(180, 216);
frameRate(60);

console.log(`${switches.length} Swithces`);
console.log(`${masks.length} Masks`);
}

function draw() {
let beige = color(251, 242, 224);
let red = color(245, 105, 96);
let blue = color(96, 152, 190);
let green = color(124, 167, 122);
let headBlack = color(60, 60, 59);
let textBlack = color(112, 111, 111);

background(beige);

push();
scale(0.2);
translate(50, 240);
citySkyline(red, beige);
pop();
}

function citySkyline(color1, color2) {
// Animate artwork
if (cityActiveState == 0) {
sunXPos = 650;
if (!switches[0]) {
switches[0] = 1;
}
let animating = false;
for (let i = 0; i < switches.length; i++) {
if (switches[i] == 1) {
if (masks[i] < 800) {
masks[i] += 20;
animating = true;
}
if (masks[i] >= 300) {
if (i + 1 < switches.length) {
switches[i + 1] = 1;
}

if (i == 12) {
// Only increase these once masks[12] reaches 300
if (mainMask < 1500) {
mainMask += 10;
animating = true;
}

if (rods < 371) {
rods += 15;
animating = true;
}

if (sunYPos < 140) {
sunYPos += 7.5;
animating = true;
}
}
}
}
}
if (!animating) {
console.log("city is now active");
cityActiveState = 1;
}
} else if (cityActiveState == 1) {
// Reverse animation
let animating = false;
if (mainMask > 400 || rods > -100 || sunYPos > -100) {
animating = true;
if (mainMask > 400) {
mainMask -= 10;
}

if (rods > -100) {
rods -= 15;
}

if (sunYPos > -100) {
sunYPos -= 7.5;
}
} else {
if (switches[switches.length - 1]) {
switches[switches.length - 1] = 0;
}
for (let i = switches.length - 1; i >= 0; i--) {
if (switches[i] == 0) {
if (masks[i] > 0) {
masks[i] -= 20;
animating = true;
}
if (masks[i] <= 300) {
// Begin reversing the next bar
switches[i - 1] = 0;
}
}
}
}
if (!animating) {
console.log("city is now inactive");
cityActiveState = 0;
}
}

// draw actual artwork
push();
noStroke();
fill(color1);
translate(225, 285);
rect(50, 0, 250, 20);
rect(0, 55, 350, 10);
rect(0, 95, 350, 10);
rect(0, 135, 350, 50);
rect(0, 215, 350, 30);
rect(0, 275, 350, 10);
rect(0, 315, 350, 40);
rect(0, 385, 350, 60);
rect(0, 475, 350, 40);
pop();

// reveal artwork
push();
noStroke();
fill(color2);
rectMode(RADIUS);
rect(mainMask, 400, 400, 400);
pop();

push();
noStroke();
fill(color1);
rect(0, 0, masks[0], 100);
rect(0, 110, masks[1], 70);
rect(0, 190, masks[2], 50);
rect(0, 250, masks[3], 35);
rect(0, 315, masks[4], 25);
rect(0, 370, masks[5], 10);
rect(0, 410, masks[6], 10);
rect(0, 490, masks[7], 10);
rect(0, 550, masks[8], 10);
rect(0, 590, masks[9], 10);
rect(0, 660, masks[10], 10);
rect(0, 750, masks[11], 10);
pop();

// draw lighting rods
push();
noStroke();
fill(color2);
translate(0, 100);
rect(rods + 30, 0, 20, 140);
translate(0, 40);
rect(rods, 0, 10, 100);
pop();

// draw sun
push();
noStroke();
fill(color2);
circle(sunXPos, sunYPos, 143);
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>


Related Topics



Leave a reply



Submit