I'm having a really hard time figuring out how to start and stop an animation and reverse it.
I've assigned an animation to the element.style.animation property and from what I've read, I decided to use:
element.style.animationPlayState = "running";
to start it and:
element.style.animationPlayState = "paused";
to stop it.
But it reports "running" all the time.
Has anyone figured out how to start and stop an animation?
I have a related question here. The related part is this block of code that I use to make animations start and stop:
var style = element.style;
var animation = null;
style.animationPlayState = "paused";
if (style.animation) {
animation = style.animation;
style.animation = null;
style.animationPlayState = "paused";
element.addEventListener("animationend", function(event) {
log("animation ended");
element.removeEventListener("animationend", arguments.callee);
});
setTimeout(function() {
style.animation = animation;
style.animationPlayState = "paused";
style.animationDirection = "reverse";
style.animationPlayState = "running";
}, 30);
}
The goal is simple:
Display a div when user presses button
div display is none, so set it to display: block
Fade in div
LATER - user presses a close button on div
Fade out div
After fade out set display: none
A method to do something like this:
fadeInElement(element)
fadeOutElement(element)
You can toggle classes with setTimeout, something like this maybe?
var theDiv = document.querySelectorAll('div')[0];
function showDiv() {
theDiv.setAttribute('class', 'fadeIn');
setTimeout(function(){ theDiv.style.opacity = '1'; }, 2000);
}
function hideDiv() {
theDiv.removeAttribute('class');
theDiv.setAttribute('class', 'fadeOut');
setTimeout(function(){ theDiv.style.opacity = '0' }, 2000);
}
div {height: 100px; height: 100px; background: black; opacity: 0;}
.fadeIn {animation: 2s fadein}
.fadeOut {animation: 2s fadeout}
#keyframes fadein { to {opacity: 1;} }
#keyframes fadeout { to {opacity: 0;} }
<div></div>
<button onclick="showDiv()">Show DIV</button>
<button onclick="hideDiv()">Hide DIV</button>
EDIT
I changed the above code to something like this, though i guess you are looking for more modern solution:
var theDiv = document.querySelectorAll('div')[0];
var anBtn = document.querySelector('#animateBtn');
var clicks = 1;
anBtn.addEventListener('click', function() {
anBtn.disabled = true;
if ((clicks/2) != (clicks/2).toFixed()) {
showDiv();
}
else {
hideDiv();
}
clicks += 1;
});
function showDiv() {
theDiv.setAttribute('class', 'fadeIn');
setTimeout(function(){ theDiv.style.opacity = '1'; anBtn.disabled = false; anBtn.textContent = 'Hide Div'; }, 2000);
}
function hideDiv() {
theDiv.removeAttribute('class');
theDiv.setAttribute('class', 'fadeOut');
setTimeout(function(){ theDiv.style.opacity = '0'; anBtn.disabled = false; anBtn.textContent = 'Show Div'; }, 2000);
}
div {height: 100px; height: 100px; background: black; opacity: 0;}
.fadeIn {animation: 2s fadein}
.fadeOut {animation: 2s fadeout}
#keyframes fadein { to {opacity: 1;} }
#keyframes fadeout { to {opacity: 0;} }
<div></div>
<button id="animateBtn">Show DIV</button>
With the Javascript Web Animations API you are able to use things like:
variable.play();
variable.pause();
it is a very powerful tool, here is the documentation
Also able to set the playback speed, including negative numbers which would play the animation in reverse. seems to address all of the issues that you brought up here.
Here is the polyfill which has proven to be very powerful, even works in IE
<script src="https://rawgit.com/web-animations/web-animations-js/master/web-animations.min.js"></script>
Attempting to solve my own question with help provided. This sort of seems to work. But seems to break the edit window console.log. Also seems to break after a few runs. Maybe unrelated.
var fadeInAnimation = "2s fadein";
var fadeOutAnimation = "2s fadein reverse";
function fadeIn() {
var element = document.getElementById('box');
//console.log("element", element);
element.style.animation = fadeInAnimation;
element.style.display = "block";
//element.style.animationPlayState = "running";
}
function fadeOut() {
var element = document.getElementById('box');
element.style.display = "block";
element.style.animationPlayState = "paused";
element.style.animation = fadeOutAnimation;
element.style.animationPlayState = "running";
element.addEventListener("animationend", function(event) {
element.style.display = "none";
console.log("animation ended");
element.removeEventListener("animationend", arguments.callee);
});
}
#box {
width: 100px;
height: 100px;
background: red;
opacity: 1;
display: none;
}
#keyframes fadein { from {opacity: 0 } to {opacity: 1;} }
#keyframes fadeout { from {opacity: 1 } to {opacity: 0;} }
<button onclick="fadeIn()">Fade In</button>
<button onclick="fadeOut()">Fade Out</button>
<div id="box">
</div>
Related
How will I add fadeout animation in this javascript code?
document.getElementById("mt-alerts").style.display="block";
setTimeout(function(){
document.getElementById("mt-alerts").style.display="none";
}, 2000);
Instead of using display, you need to start with opacity for this.
The idea is simply decrease the opacity of your element until it reaches the 0, then set its display as none. To fade in you can repeat the idea in reverse.
function js_fadeOut(targetID, intervalMs, fadeWeight) {
var fadeTarget = document.getElementById(targetID);
var fadeEffect = setInterval(function () {
if (!fadeTarget.style.opacity) {
fadeTarget.style.opacity = 1;
}
if (fadeTarget.style.opacity > 0) {
fadeTarget.style.opacity -= fadeWeight;
} else {
fadeTarget.style.display = "none";
clearInterval(fadeEffect);
}
}, intervalMs*fadeWeight);
}
<div id='target' style='padding:8px; background:lightblue;' onclick='js_fadeOut("target", 200, 0.1)'>Click to fadeOut</div>
You should make classses for every animations, and the JS should change only the classes of the items.
You can with this method, make your own animatsions.
const alertMsg = document.getElementById("mt-alerts");
const hide = document.getElementById("hide");
const red = document.getElementById("red");
hide.addEventListener("click", ()=> alertMsg.classList.toggle("hidden"));
red.addEventListener("click", ()=> alertMsg.classList.toggle("red"));
#mt-alerts {
opacity: 1;
transition: all 0.5s linear;
color: black;
}
.hidden {
opacity: 0!important;
}
.red {
color: red!important;
}
<div id="mt-alerts">My Alert</div>
<button id="hide">Hide/show</button>
<button id="red">Make it red</button>
I am trying to use JS to switch images, the code does what it is supposed to and switches the images, however, I want a fade out-fade in effect to the image transition. I tried to declare a CSS Transition for opacity and change the opacity first, which didn't work, then I tried to change the opacity with plain JS, however that didn't work either, what would be the best way to achieve this?
My Poorly Designed Image Change Code:
image = [
"image_1.png",
"image_2.png",
"image_3.jpeg"
];
updateImg = async() => {
console.log("Pulling Image Change")
var img = document.getElementById("img-pan");
console.log(`Got ${img} with current src ${img.src}`)
var exi_bool = false;
for(i = 0; i < image.length - 1; i++) {
if(img.src.endsWith(image[i])) { exi_bool = true; console.log(`Found current src to == image[${i}]`) ;break; }
}
if(!exi_bool) {
img.src = image[0];
}else {
if(i < image.length - 1) { i++ }else { i = 0 }
img.src = image[i];
}
}
If I understood well, before you replace the image add a class that define the opacity to 0.3 for example.
document.getElementById("MyElement").classList.add('MyClass');
when the image change you remove the class.
document.getElementById("MyElement").classList.remove('MyClass');
Note that your image has to be set on css as opacity: 1 and transition x seconds.
Will use css style animation, just change class name, is simple to use and build.
but when css animation start to change css property,no way could change same property but other css animation.
let imgArray = [
'https://fakeimg.pl/100x100/f00',
'https://fakeimg.pl/100x100/0f0',
'https://fakeimg.pl/100x100/00f'
];
let img = document.getElementsByTagName('img')[0];
//only two function
async function fadeOut(element) {
element.className = 'fade-out';
}
async function fadeIn(element) {
element.className = 'fade-in';
}
//
let i = 0;
function loop() {
img.src = imgArray[i % 3];
i++;
fadeIn(img).then(res => {
setTimeout(() => {
fadeOut(img).then(res => {
setTimeout(() => {
loop();
}, 1000);
})
}, 1000);
})
}
loop();
img {
position: relative;
left: 0; /* or use transform */
opacity: 1;
transition: 1s;
width: 100px;
display: block;
margin: auto;
}
.fade-in {
animation: fade-in 1s;
}
#keyframes fade-in {
0% {
left: 100px; /* or use transform */
opacity: 0;
}
100% {
left: 0; /* or use transform */
opacity: 1;
}
}
.fade-out {
animation: fade-out 1s both;
}
#keyframes fade-out {
0% {
left: 0; /* or use transform */
opacity: 1;
}
100% {
left: -100px; /* or use transform */
opacity: 0;
}
}
<img src="https://fakeimg.pl/100x100/#f00">
I need to set my .screens to be display: none until the point when its animation starts. Each one has a separate animation-delay so what I hope to achieve is that a function will check how long the animation delay is and that will then determine the length of the setTimeout function.
Example:
If .screens has an animation delay of 3 seconds, then after 3 seconds I want display to change from none to block.
Code of the function I have written so far is below:
var screens = document.getElementsByClassName('screen');
for (var i=0;i<screens.length;i++){
if (screens[i].style.animationDelay >=0){
setTimeout(function(){
this.style.display = "block";
}, this.style.animationDelay);
}
}
You can try this. (You can skip the first part, it is there just to generate screens with random animationDelay)
const generateScreens = () => {
for (let i = 0; i < 5; i++) {
let el = document.createElement('div');
el.className = 'screen';
el.style.animationDelay = Math.floor(Math.random() * 5) + 's';
document.body.appendChild(el);
}
}
generateScreens();
// code that you have asked for starts here
const screens = document.getElementsByClassName('screen');
[...screens].forEach(item => {
const delay = item.style.animationDelay.slice(0, item.style.animationDelay.length - 1);
setTimeout(() => {
item.style.display = 'block';
}, delay * 1000);
});
div.screen {
width: 40px;
height: 40px;
background: red;
border: 1px solid black;
display: none;
}
Since you cannot animate the state/value from none to block of the display property, you can instead do it with the visibility: hidden / visibility: visible pair, and of course you could also do it with the opacity: 0 / opacity: 1:
.screen {
visibility: hidden;
animation: animate forwards;
}
.screen:first-child {animation-delay: 1s}
.screen:nth-child(2) {animation-delay: 2s}
.screen:nth-child(3) {animation-delay: 3s}
#keyframes animate {
to {visibility: visible}
}
<div class="screen">1</div>
<div class="screen">2</div>
<div class="screen">3</div>
Then you can just target the .screen elements with the :nth-child or :nth-of-type selectors.
I have this simple jQuery logic, How would I convert that into pure JavaScript?
I have no clue where to start unfortunately. Any help would be extremely appreciated.
$(function() {
// OPACITY OF BUTTON SET TO 0%
$(".rollstate").css("opacity", "0");
// ON MOUSE OVER
$(".rollstate").hover(function() {
// SET OPACITY TO 70%
$(this).stop().animate({
opacity: .5
}, "fast");
},
// ON MOUSE OUT
function() {
// SET OPACITY BACK TO 50%
$(this).stop().animate({
opacity: 0
}, "slow");
});
});
EDIT: a CSS solution would probably work best here, but as a learning purpose I would like to see how the pure JS would work in this case.
You can try the code below. The best would be to declare some CSS and call those by javascript or only use CSS. But as you requested I tried a bit using vanilla javascript.
var element = document.getElementById('rollstate');
element.style.opacity = "0";
element.style.filter = 'alpha(opacity=0)';//for IE
document.getElementById("rollstate").onmouseover = function() {mouseOver()};
document.getElementById("rollstate").onmouseout = function() {mouseOut()};
function mouseOver() {
var element1 = document.getElementById('rollstate');
element1.style.opacity = "5";
element1.style.filter = 'alpha(opacity=5)';
element1.className += 'faded';
}
function mouseOut() {
var element2 = document.getElementById('rollstate');
element2.style.opacity = "0";
element2.style.filter = 'alpha(opacity=0)';
element2.className += 'faded';
}
#rollstate {
-webkit-transition: opacity 1s;
opacity: 1;
}
#rollstate.faded {
opacity: 0;
}
<html>
<body>
<p>hover Below</p>
<input type ="button" id="rollstate" value="click me"/>
</body>
</html>
I have the following code which is going to fade some images but I am interested if there is a way to handle this in CSS.
$("#top").stop(true, true).delay(0).fadeTo(fadeTime * 100, 0);
$("#back").stop(true, true).delay(0).fadeTo(fadeTime * 100, 1, function () {
if (curLoop < loops) {
if (curImg < imgNo) {
prevImg = curImg
curImg++
} else {
prevImg = imgNo
curImg = 1;
curLoop++console.log("LOOP");
}
document.getElementById("back").style.opacity = 0;
document.getElementById("top").style.opacity = 1;
document.getElementById("back").src = "frames/frame_" + curImg + ".jpg";
document.getElementById("top").src = "frames/frame_" + prevImg + ".jpg";
} else {
console.log("STOPPED");
window.clearInterval(myVarSTD);
}
if (!initialized) {
myVarSTD = setInterval(function () {
startAnimation()
}, delay * 1000);
initialized = true;
}
});
You can't loop through image sources in a pure CSS animation but the below fade effect is possible with CSS3 animations. Here the front and back images are absolutely positioned and using opacity animation they are faded in and out in an infinite loop. I have used 2 div with background-image but you could do the same for img element also.
Refer inline comments within the snippet for more explanation of the animation's CSS code.
.front,
.back {
position: absolute; /* absolute positioning puts them one on top of other */
height: 200px;
width: 200px;
animation: fade-in-out 10s linear infinite; /* first is animation keyframe's name, second is the duration of the animation, third is timing function and fourth is iteration count */
}
.front {
background-image: url(http://lorempixel.com/200/200/nature/1);
}
.back {
background-image: url(http://lorempixel.com/200/200/nature/2);
z-index: -1; /* keeps the element behind the front */
animation-delay: 5s; /* delay is equal to half the animation duration because the back has to fade-in once the front has faded-out at 50% */
}
#keyframes fade-in-out { /* animation settings */
0%, 100% {
opacity: 1; /* at start and end, the image is visible */
}
50% {
opacity: 0; /* at the mid point of the animation, the image is invisible */
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='front'></div>
<div class='back'></div>
Yes, it is. Your code capture some elements using getElementById as back and top.
You can use the following code to change CSS properties of those elements:
$('#back').css({'opacity':'1'});
Implemented in your code:
$("#top").stop(true, true).delay(0).fadeTo(fadeTime*100, 0);
$("#back").stop(true, true).delay(0).fadeTo(fadeTime*100, 1, function(){
if(curLoop<loops){
if(curImg<imgNo){
prevImg = curImg
curImg++
}else{
prevImg = imgNo
curImg = 1;
curLoop++
console.log("LOOP");
}
$('#back').css({'opacity':'0'});
$('#top').css({'opacity':'1'});
document.getElementById("back").src = "frames/frame_"+curImg+".jpg";
document.getElementById("top").src = "frames/frame_"+prevImg+".jpg";
}else{
console.log("STOPPED");
window.clearInterval(myVarSTD);
}
if(!initialized){
myVarSTD = setInterval(function(){startAnimation()},delay*1000);
initialized = true;
}
});
jQuery Transit is an awesome plugin which mimics jQuery's animation functions but in CSS. You get a much higher framerate using CSS too!