Web Animations API - varying animation durations? - javascript

I'm experimenting with the Web Animations API which currently works only in Webkit browsers. As one can imagine, the documentation is a bit sparse:
Here's a blog post I found on it
Here's the spec
I'm trying to do two things:
Reverse the animation at a random point in time before the animation ends.
Stagger the duration of the effects in the animation. For example, for a 3 second animation, the first portion of it should be 1.25s and the second portion should be 1.75s.
Here's a working example which uses the Web Animation API. My concern is that the 3 animations are spaced evenly among the 3 seconds. How can I space them out differently without instantiating multiple animationPlayer objects?
$('.box').click(function() {
var animationPlayer = this.animate([{
transform: 'translateX(0px)'
}, {
transform: 'translateX(600px)'
}, {
transform: 'translate(600px, 200px)'
}], 3000);
animationPlayer.onfinish = function(e) {
console.log('complete!');
}
// wiggle wiggle wiggle
setTimeout(function() {
animationPlayer.reverse();
setTimeout(function() {
animationPlayer.reverse();
}, 250);
}, 750);
});
.box {
background-color: red;
width: 200px;
height: 200px;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='box'></div>

About your first question, looks like Chrome implementation still hasn't the reverse function. This is consistent with the documentation that you have linked. May be in Canary, but I haven't checked.
Correction: reading an update in your linked blog, looks like it has been added to Chrome. However, it isn't working for me ...
About your second question, specify an offset in your second keyframe
If the first transform must run for 1.25 s, for a total of 3 s, this is 1.25 / 3 = .416, so
$('.box').click(function() {
var animationPlayer = this.animate([{
transform: 'translateX(0px)'
}, {
transform: 'translateX(600px)', offset: 0.416
}, {
transform: 'translate(600px, 200px)'
}], 3000);
animationPlayer.onfinish = function(e) {
console.log('complete!');
}
// wiggle wiggle wiggle
setTimeout(function() {
animationPlayer.reverse();
setTimeout(function() {
animationPlayer.reverse();
}, 250);
}, 750);
});
.box {
background-color: red;
width: 200px;
height: 200px;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='box'></div>

Related

Using JS how can I get the animation end value in the documents timeline

I have a document with multiple CSS animations and I need to get the total running length that can be seen in chrome dev tools (Animations timeline) as per screenshot
I have thought of a few ways but not sure what's 1. the most accurate and 2. most efficient
PS the CSS animation classes are added dynamically on load so sometimes it maybe longer and other times shorter
FYI I have considered using JS document.getAnimations() to get an array but not sure
where to go from there since they all have similar:
array:
start time and current time
end total value:
I think you can get this using a combination of the animationstart and animationend events. Here's a modified version of MDN's example, here using two different elements that we start the animation on at random times:
const activeElements = new Map();
function handleAnimationStart({target}) {
const now = Date.now();
console.log(`Started on ${target.getAttribute("data-label")} at ${now}`);
activeElements.set(target, now);
}
function handleAnimationEnd({target}) {
const now = Date.now();
const start = activeElements.get(target);
if (typeof start === "number") {
activeElements.delete(target);
console.log(`Ended on ${target.getAttribute("data-label")} at ${now}, duration = ${now - start}`);
}
}
function startAnimation(element) {
element.classList.toggle("active");
element.addEventListener("animationstart", handleAnimationStart);
element.addEventListener("animationend", handleAnimationEnd);
}
const elements = document.querySelectorAll("p.animation");
setTimeout(() => {
startAnimation(elements[0]);
}, Math.floor(Math.random() * 1000));
setTimeout(() => {
startAnimation(elements[1]);
}, Math.floor(Math.random() * 2000));
.container {
height: 3rem;
}
.event-log {
width: 25rem;
height: 2rem;
border: 1px solid black;
margin: 0.2rem;
padding: 0.2rem;
}
.animation.active {
animation-duration: 2s;
animation-name: slidein;
}
#keyframes slidein {
from {
transform: translateX(100%) scaleX(3);
}
to {
transform: translateX(0) scaleX(1);
}
}
<div class="animation-example">
<div class="container">
<p class="animation" data-label="0">You chose a cold night to visit our planet.</p>
</div>
<div class="container">
<p class="animation" data-label="1">You chose a cold night to visit our planet.</p>
</div>
</div>

web animations api, resetting 1st animation at end of chain

I'm experimenting with the web animations API for the first time, and trying to chain some values together. I'm a little confused as for this simple animation, where it will translate 200px along the X axis, then 200px down along the Y axis once the first animation is complete.
However, at the end of the animation, it resets the X value of the initial animation. I've tried playing around with 'both' | 'forwards' for the fill mode property, as well as setting translateX to 0/200 in the second transform declaration. Feel like I'm missing something quite simple here.
const box = document.getElementById('box');
const animateRight = box.animate(
[{ transform: 'translateX(0)' }, { transform: 'translateX(200px)' }],
{
fill: 'forwards',
easing: 'ease-in-out',
duration: 2000,
}
);
animateRight.finished.then(() => {
box.animate([{ transform: 'translateY(0)' }, { transform: 'translateY(100px)' }], {
composite: 'add',
fill: 'both',
duration: 1500,
});
});
#box {
width: 100px;
height: 100px;
border: 1px solid black;
}
<div id="box"></div>

Why do we need to clear the animation when running it multiple times in JavaScript?

Yesterday I asked a question (original question) that was promptly answered, but even though a solution was found, I don't understand why this is working the way it is. I can duplicate this solution for other things I need to do but before I continue on I would like to understand why this works the way it does.
So basically I made three functions that called each other. The 1st called the second upon "animationend" and the second called the third upon an "animationend" and the finally the third function called the first to start the cycle all over again - BUT My original code though lacked;
document.getElementById("rightBoxTwo").style.animation = "none";
which was needed in-order for the third function to call the first so the cycle starts all over again. Without the above code in each function the three functions would work only once and then stop. The answer that StackOverFlow user; ScientiaEtVeritas gave me included a CodePen which had a working example of what I needed and a brief explanation
So, I think you have several options: What could work is that you
reset the the animation of rightBox in function runTwo with
animation: none. If you assign scrollTextTwo 10s back to the
rightBox it should start again. Equivalent for the other ones.
So finally my question is WHY does the animation need to be cleared, and why does the .style.animation = "none"; accomplish this?
below is the working code after a solution was presented...
<body onload="runOne()">
function runOne() {
var x = document.getElementById("rightBox");
x.addEventListener("animationend",runTwo);
document.getElementById("rightBox").style.animation = "scrollTextTwo 10s";
document.getElementById("rightBoxTwo").style.animation = "none";
}
function runTwo() {
var x = document.getElementById("rightBoxTwo");
x.addEventListener("animationend",runThree);
document.getElementById("rightBoxTwo").style.animation =
"scrollTextTwo 10s";
document.getElementById("rightBoxThree").style.animation = "none";
}
function runThree() {
var x = document.getElementById("rightBoxThree");
x.addEventListener("animationend",runOne);
document.getElementById("rightBoxThree").style.animation =
"scrollTextTwo 10s";
document.getElementById("rightBox").style.animation = "none";
}
The simplest reason is because setting the animation to the same thing twice (or more times) in a synchronous manner like a for loop is the same as doing it once:
let box = document.getElementById('box');
// animation happens once
for (let i = 0; i < 5; i++) {
box.style.animation = 'fade .5s';
}
#keyframes fade {
from {
opacity: 1
}
to {
opacity: 0
}
}
#box {
height: 200px;
width: 200px;
margin: 50px;
background: #018bbc;
}
<div id="box"></div>
The behavior is the same even if you delay the animation so each time it runs after a possible render:
let box = document.getElementById('box');
// animation still happens once
for (let i = 0; i < 5; i++) {
setTimeout(function() {
box.style.animation = 'fade .5s';
}, i * 1000);
}
#keyframes fade {
from {
opacity: 1
}
to {
opacity: 0
}
}
#box {
height: 200px;
width: 200px;
margin: 50px;
background: #018bbc;
}
<div id="box"></div>
But if I reset the animation before each step, the engine has to re-set the animation, which in a way means to "install the animation again", meaning it will be animated again:
let box = document.getElementById('box');
box.addEventListener('animationend', function() {
box.style.animation = 'none';
});
// animation now happens every time
for (let i = 0; i < 5; i++) {
setTimeout(function() {
box.style.animation = 'fade .5s';
}, i * 1000);
}
#keyframes fade {
from {
opacity: 1
}
to {
opacity: 0
}
}
#box {
height: 200px;
width: 200px;
margin: 50px;
background: #018bbc;
}
<div id="box"></div>
You don't really need javascript for something like this. Keyframes let you define styles by percent complete. Using that you can time 2 animations for a similar result:
#keyframes progress {
0% { width: 0px;}
50% { width: 600px;}
100% {width: 600px;}
}
#keyframes progress2 {
0% { width: 600px;}
49% { width:600px;}
50% { width: 0px;}
100% {width: 600px;}
}
div {
width:600px;
height:50px;
background-color:black;
}
#rightBox {
animation: progress 4s infinite;
}
#rightBoxTwo {
animation: progress2 4s infinite;
}
<div id="rightBox"></div>
<div id="rightBoxTwo"></div>

How to make that animation passed linearly? without slowing down at the start and the finish?

I need to get a picture crawling smoothly without slowing down at the start and finish.
setInterval(function runIt() {
$(".bffffg").animate({
backgroundPositionX: 300
}, 8000);
$(".bffffg").animate({
backgroundPositionX: 0
}, 0);
}, 1);
.bffffg {
display: block;
position: absolute;
width: 100%;
height: 100%;
background: url(http://www.dejurka.ru/wp-content/uploads/2015/06/watercolor-patterns4.jpg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="bffffg"></div>
How to apply a linear effect to the animation?
And even apply different effects to it?
If you are looking for setting easing parameter, you may pass it as a separate argument like here:
$('your-selector').animate({
'your-property': 'value'
}, 8000, 'linear');
...or with options object like here:
$('your-selector').animate({
'your-property': 'value'
}, {
duration: 8000,
easing: 'linear'
});
Here is DOC for jQuery .animate() :)

How to set the time to each content should be shown after the site have already loaded?

I'm looking for some plugin (js/ajax) or tutorial which let me set the time to each content should be shown after the site have already loaded.
For example:
I want my website with a loader and after that display the menu navigation (e.g. slide right to left effect), after the logotype, after the main image of home, etc.).
This website is a good reference for what I want: http://www.smog-bicyclettes.com/
Do you know something like this?
Try using set timeout
setTimeout(function(){
/* Your Function */
},2000);
I'm delegating deciding which animation to run to a single function doAnimation which maintains a counter of the last animation that ran.
We don't need to use setTimeout here because we're relying only on the jQuery animation callbacks to ensure one animation happens when another finishes.
Working example here (updated): http://jsfiddle.net/av8ZA/7/
HTML
<div id="element1"></div>
<div id="element2"></div>
<div id="element3"></div>
<div id="element4"></div>
<div id="element5"></div>
<div id="element6"></div>
CSS
div {
height:100px;
width 200px;
display:none;
}
#element1 {
background: red;
}
#element2 {
background: green;
}
#element3 {
background: blue;
}
#element4 {
background: magenta;
}
#element5 {
background: black;
}
#element6 {
background: yellow;
}
jQuery/Javascript
(function ($) {
var currentCall = 0,
animations = [{
element: "#element1",
type: "slide",
options: {},
time: 1000
}, {
element: "#element2",
type: "blind",
options: {}
}, {
element: "#element3",
}, {
element: "#element4",
type: "size",
time: 300
}, {
element: "#element5",
}, {
element: "#element6",
type: "bounce"
}],
defaults = {
type: "fade",
time: 300,
options: {}
};
function doAnimation() {
if (animations[currentCall] != undefined) {
var anim = animations[currentCall];
$(anim.element).show(
anim.type || defaults.type,
anim.options || defaults.options,
anim.time || defaults.time,
doAnimation);
currentCall++;
}
}
$(document).ready(doAnimation);
})(jQuery);
Of course this is no good if you want concurrent animations, but you didn't state that in the question.
EDIT: I've cleaned up by javascript and defined an array of animations now where you can set options for each animation individually. For all animation types see the jQuery UI documentation for show. I've also defined some default that will be used if you don't specify one of the options for an animation.

Categories

Resources