Setting timeout function based on animation delay - javascript

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.

Related

How to add animation?

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>

How to fade in / fade out a button on scrolling down / up respectively

I am working on my portfolio website and I am a complete beginner in Javascript.
I would like a button which has its position fixed, to slowly fade in when I scroll down (suppose when I scroll to >=20px from the top of the document, it should fade in) and when I scroll back up to the original position, it should gradually fade out.
I have already tried my hand and written a code for this. It is working perfectly when you scroll down and up. But when you quickly scroll and stop scrolling in the mid-way, it behaves pretty abnormally (suddenly appears or disappears).
HTML:
<div class="a_large_page">
<div class="enclose bordar black" id="bottomtoup">hello</div>
</div>
JS:
mybutton = document.getElementById("bottomtoup")
// initially, the button stays hidden
visible = false
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {
scrollFunction()
};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
if (!visible) { // if the button is not visible,
unfade(mybutton); // function to gradually fadein button
visible = true; // button is visible so, set visible = false to true.
}
} else {
if (visible) { // if the button is visible,
fade(mybutton); // function to gradually fadeout button
visible = false; // set visible = true back to false
}
}
}
function unfade(element) {
var op = 0.1; // initial opacity
element.style.display = 'flex';
var timer = setInterval(function() {
if (op >= 1) {
clearInterval(timer);
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op += op * 0.1;
}, 10);
}
function fade(element) {
var op = 1; // initial opacity
var timer = setInterval(function() {
if (op <= 0.1) {
clearInterval(timer);
element.style.display = 'none';
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op -= op * 0.1;
}, 50);
}
Here is the fiddle: https://jsfiddle.net/P0intMaN/Lmp6u5ft/23/
My code is pretty substandard for sure. That's why it is behaving in this way. Hence, I am looking for an efficient way to achieve this. I have seen people making use of JQuery to do this, but I don't know JQuery at all. So, it would be much appreciated if the code is in pure JS.
I've changed your code and removed setInterval usage. This can be solved with it but may be harder to understand for newer coders.
There are also flags to keep track of whether you are currently fading or unfading to ensure you do not stack or "overlap" timeout/intervals.
mybutton = document.getElementById("bottomtoup")
// initially, the button stays hidden
var visible = false
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {
scrollFunction()
};
function scrollFunction() {
var threshold = 20;
var below_threshold = document.body.scrollTop > threshold || document.documentElement.scrollTop > threshold;
if (below_threshold) {
if (!visible) { // if the button is not visible,
unfade(mybutton); // function to gradually fadein button
}
return;
}
if (visible) { // if the button is visible,
fade(mybutton); // function to gradually fadeout button
}
}
var current_opacity = 0.1;
var is_unfading = false;
var is_fading = false;
function unfade(element) {
if(!visible){
element.style.display = 'flex';
visible = true;
}
is_fading = false;
is_unfading = true;
unfade_step(element);
}
function unfade_step(element){
element.style.opacity = current_opacity;
element.style.filter = 'alpha(opacity=' + current_opacity * 100 + ")";
if (current_opacity >= 1){
// end
is_unfading = false;
current_opacity = 1;
return;
}
current_opacity += 0.01;
if(is_unfading){
setTimeout(function(){
unfade_step(element);
}, 10);
}
}
function fade(element) {
if(!visible){
return;
}
is_fading = true;
is_unfading = false;
fade_step(element);
}
function fade_step(element) {
element.style.opacity = current_opacity;
element.style.filter = 'alpha(opacity=' + current_opacity * 100 + ")";
if (current_opacity <= 0.001){
// end
is_fading = false;
visible = false;
current_opacity = 0.1;
element.style.display = 'none';
return;
}
current_opacity -= 0.01;
if(is_fading){
setTimeout(function(){
fade_step(element);
}, 10);
}
}
There is no need to have so much JS when you can do in so little:
If you feel to change the timing of
// Set a function onscroll - this will activate if the user scrolls
window.onscroll = function() {
// Set the height to check for
var appear = 20
if (window.pageYOffset >= appear) {
// If more show the element
document.getElementById("bottomtop").style.opacity = '1'
document.getElementById("bottomtop").style.pointerEvents = 'all'
} else {
// Else hide it
document.getElementById("bottomtop").style.opacity = '0'
document.getElementById("bottomtop").style.pointerEvents = 'none'
}
}
.a_large_page{
background-color: gray;
height: 2000px;
}
.enclose{
height: 40px;
width: 40px;
position:fixed;
margin-right: 20px;
margin-bottom: 20px;
right:0;
bottom:0;
pointer-events:none;
opacity:0;
justify-content: center;
align-items: center;
color:white;
/* This determines how fast animation takes place, you can change it as per your choice. */
transition:all 0.6s;
}
.enclose:hover{
cursor: pointer;
}
<div class="a_large_page">
<div class="enclose bordar black" id="bottomtop">hello</div>
</div>
There is no need to sense the scroll event in more modern browsers as you can use IntersetionObserver to tell you when scrolling has gone past 20px;
You can do this by placing a tiny element at the top of the page with height 20px. You then ask the system to tell you when this has gone out of, or comes back into, the viewport. At these points you can set the opacity of the Hello to 1 or 0 as appropriate.
The extra bonus is that you get rid of a lot of code and there isn't the possible clash between set intervals as we use transition on the opacity to do the gradual fade in/out.
// See MDN for more info on IntersectioObserver
let callback = (entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
mybutton.style.opacity = 0;
} else {
mybutton.style.opacity = 1;
}
});
};
const mybutton = document.getElementById("bottomtoup")
const observer = new IntersectionObserver(callback);
const observed = document.getElementById("observed");
observer.observe(observed);
.a_large_page {
background-color: gray;
height: 2000px;
position: relative;
}
#observed {
position: absolute;
top: 0;
left: 0;
height: 20px;
width: 10px;
z-index: -999;
}
.enclose {
height: 40px;
width: 40px;
position: fixed;
margin-right: 20px;
margin-bottom: 20px;
right: 0;
bottom: 0;
justify-content: center;
align-items: center;
color: white;
opacity: 0;
transition: opacity 1s linear;
}
<div class="a_large_page">
<div id="observed"></div>
<div class="enclose bordar black" id="bottomtoup">hello</div>
</div>

Softly Transition HTML Images with Javascript

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">

How can I repeat an animation after changing the text inside the element?

I have an text element (HTML) that plays an animation when the page loads and I'm trying to create a script to change the original text to a different one and then play the same animation. Here is part of my code:
setTimeout(function typewriter() {
let txt;
let themes = document.getElementById("themes");
txt = "Games";
themes.innerText = txt;
themes.classList.add("changer");
}, 4000);
.typewriter h1 {
color: #ffffff;
background-color: #000000a8;
border-radius: 5px;
padding: 10px;
font-family: monospace;
font-size: 35px;
overflow: hidden; /* Ensures the content is not revealed until the animation */
border-right: .15em solid #333333; /* The typwriter cursor */
white-space: nowrap; /* Keeps the content on a single line */
margin: 0 auto; /* Gives that scrolling effect as the typing happens */
animation:
typing 2s steps(30, end),
blink-caret .5s step-end infinite;
}
.changer {
animation: typing 2 s steps(30, end),blink - caret .5 s step - end infinite;
}
/* The typing effect */
#keyframes typing {
from { width: 0 }
to { width: 100% }
}
/* The typewriter cursor effect */
#keyframes blink-caret {
from, to { border-color: transparent }
50% { border-color: #333333 }
}
<div class="typewriter">
<h1 id="themes">Science</h1>
</div>
The problem is that after 4 seconds when the text changes I can't play the animation again. Can anyone help me, please? Thank you.
First, you are using setTimeout (This is wrong)
If you want it to repeat the function, you should use setInterval.
Second, you are changing the same "Text" every time you call the function, which is "Games". If you want it to change to a certain text, you need to store it first in an array,
var texts = [];
//Add a counter
var curr = 0;
//Store in array
texts.push("Games");
texts.push("Science");
setInterval(function() {
let txt;
//Change the texts array value with curr variable (the Counter)
txt = texts[curr];
let themes = document.getElementById("themes");
themes.innerText = txt;
themes.classList.add("changer");
//Change the counter variable
curr += 1;
//Change the counter to the start of the array
if(curr >= texts.length) curr = 0;
}, 4000);
In my case, the animation doesn't work. But if you want to change the text for every 4s, this code will help you.
You can add any number of text that you want.
I found a solution using JavaScript to increase the width of the element from 1% to 100%!
Here is my JavaScript code:
var texts = [];
//Add a counter
var curr = 0;
//Store in array
texts.push("Games");
texts.push("Science");
setInterval(function() {
let txt;
//Change the texts array value with curr variable (the Counter)
txt = texts[curr];
let themes = document.getElementById("themes");
themes.innerText = txt;
var width = 0;
var id = setInterval(frame,10);
function frame(){
if(width >= 100){
clearInterval(id);
} else {
width++;
themes.style.width = width + "%";
}
}
//Change the counter variable
curr += 1;
//Change the counter to the start of the array
if(curr >= texts.length) curr = 0;
}, 4000);
Thank you for the help!

Changing css animation in javascript

I have a blinking red box in my html it uses css animations. I want to to be able to change it from blinking red and white to green and white. I know this can be done on id elements by using getElementbyId but how would get access to the green aminated box in the css.
The red box looks like this:
#-webkit-keyframes 'noConnection'
{
1% { background-color: red; }
33% { background: white; }
66% { background: red; }
100% { background: white; }
}
The green is this:
#-webkit-keyframes 'Connection'
{
1% { background-color: green; }
33% { background: white; }
66% { background: green; }
100% { background: white; }
}
The animate looks like this:
#animate {
height: 15px;
width: 15px;
}
.cssanimations #animate {
-webkit-animation-direction: normal;
-webkit-animation-duration: 5s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-name: Connection;
-webkit-animation-timing-function: ease;
and I think I have to change the attribute -webkit-animation-name: from javascript to do this but I dont know how to get a handle on it to change it.
Or would I be better off creating a duplicate #animate and renaming it using the getElementById?
Here is a simple web page that demonstrates how to use Javascript to modify a CSS animation. It contains a simple div, and a little Javascript causes the div to move randomly around the page.
In your specific case, you just need to touch up the line that calls "insertRule" to insert your new blinking rule.
<html><head><style></style></head>
<body>
<div id="mymovingdiv">
<h1>Moving Div</h1>
<p>And some little text too</p>
</div>
<script>
function animatedMove(id, xStart, yStart, xEnd, yEnd, secs)
{
// Remove any CSS rules inserted by a previous call to this method
let rulename = `AnimMove${id}`;
let ss = document.styleSheets; // all stylesheets
for (let i = 0; i < ss.length; ++i) { // for each stylesheet...
for (let j = ss[i].cssRules.length - 1; j > 0; j--) { // for each rule...
if (ss[i].cssRules[j].name === rulename) { // does the name match?
ss[i].deleteRule(j);
}
}
}
// Insert a CSS rule for this animation
document.styleSheets[0].insertRule(`#keyframes ${rulename} { 0% { left: ${xStart}px; top: ${yStart}px; } 100% { left: ${xEnd}px; top: ${yEnd}px } }`);
// Remove any CSS rules inserted by a previous call to this method
for (let i = 0; i < ss.length; ++i) { // for each stylesheet...
for (let j = ss[i].cssRules.length - 1; j > 0; j--) { // for each rule...
if (ss[i].cssRules[j].name === rulename) { // does the name match?
ss[i].deleteRule(j);
}
}
}
// Insert a CSS rule for this animation
document.styleSheets[0].insertRule(`#keyframes ${rulename} { 0% { left: ${xStart}px; top: ${yStart}px; } 100% { left: ${xEnd}px; top: ${yEnd}px } }`);
// assign the animation to our element
let el = document.getElementById(id);
el.style.position = 'absolute';
el.style.animation = `${rulename} ${secs}s`;
// Make the element stay where the animation ends
el.style.left = `${xEnd}px`;
el.style.top = `${yEnd}px`;
// Re-clone the element, to reset the animation
el.parentNode.replaceChild(el.cloneNode(true), el);
}
let x = 0;
let y = 0;
function randomMove()
{
let newX = Math.floor(Math.random() * 800);
let newY = Math.floor(Math.random() * 600);
animatedMove('mymovingdiv', x, y, newX, newY, 1);
x = newX;
y = newY;
}
setInterval(randomMove, 1000);
</script>
</body>
</html>
The easiest way to do this is to created two classes in CSS and then toggle between the two.
So something like:
.connection {
animation: 'Connection' 5s ease infinite
}
.no-connection {
animation 'noConnection' 5s ease infinite
}
And then use Javascript to toggle between the two
function toggleConnectionStatus(){
var element = document.getElementById('animate');
if(/* connection is active */) element.className = 'connection';
else element.className = 'no-connection'
}

Categories