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!
Related
Say I have an animation defined in css like so:
#keyframes my-animation {
0% {
// effect here
}
...
100% {
// effect here
}
}
I can use it in a div like so:
#container {
animation: my-animation 10s linear ;
}
Is there any way I can use javascript to programmatically set the percentage of the animation at any point instead? Something along the lines of:
function() {
let container = document.getElementById('container');
while (some condition && container.percentage < 100) {
container.percentage += 10; // Here I would like to set the animation percentage to one of the percentages defined in the keyframe animation
}
}
This is so I don't have to explicitly set the duration of the animation beforehand as it is unknown at runtime. I should add that I am aware that it currently is not possible to retrieve the percentage value of an animation but perhaps there is a way to manipulate it?
EDIT:
From what I understand from the comment by lupz:
.animation0 { /* 0% */
}
.animation10 { /* 10% */
}
...
.animation100 { /* 100% */
}
Then I can change the class of the element to whichever percentage I need.
You can the JS animation API - Element.animate(), and then you can control the percentage (the offset property) directly via JS:
const container = document.querySelector('.container');
const animate = (offset = 1) => {
const height = container.getBoundingClientRect().height;
const animation = container.animate([
{
transform: 'translateY(0px)',
offset: 0
},
{
transform: `translateY(calc(100vh - ${height}px))`,
offset
}
], {
duration: 1000,
});
if(offset > 0) {
animation.finished
.then(() => animate(offset - 0.1));
}
};
animate();
html, body {
margin: 0;
}
.container {
width: 100px;
height: 100px;
background: silver;
}
<div class="container"></div>
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 have a Javascript code to change the background image randomly and works fine, but is very rough. I would like to make some kind of transition between images, I would like to use fadeIn(slow) but don't know how to incorporate it to my code, can someone help me? Cheers!
JAVASCRIPT
window.onload = function () {
// Array of Images
var backgroundImg=["https://image1.com",
"https://image2.com",
"https://image3.com",
"https://image4.com"
]
setInterval(changeImage, 5000);
function changeImage() {
var i = Math.floor((Math.random() * 3));
document.getElementById("sectionAbout").style.backgroundImage = "url('"+backgroundImg[i]+"')";
}
}
Easy solution is to pass the transition handling to your browser, and all you should care about is the background changing.
Say we want to animate the body background.
Here's working example with colors, but can be done with images as well just use backgroundImage insead of backgroundColor
var arr = ['blue', 'red', 'pink', 'yellow', 'brown']
var i = 0;
document.getElementById('l').addEventListener('click', function() {
document.body.style.backgroundColor = arr[i];
i++
if (i == arr.length)
i = 0;
});
body {
transition: background ease 2s;
}
<button id="l">OK</button>
EDIT : In case of Images, You would want to avoid, the jerky animations caused by the images not being loaded.
var arr = ["https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRyB57zuc4bms-hDtWMa-4BZvscIlJDm4r7a9WLaO4SAxUvKM-DDA", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQBinSpWOvAtkxjmkf709O3rjH2ObRbWAEn9s0JcWaeL6LMtCbOrQ", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRKY4J2qIFqkuDnABMzeypywbMSZL1cleS8vpySz0KD02wOYORU1g", "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcRQkdQT0zN0xDVP-VuvwojSbS5dOstX14eZvJCOWNPxKJ5dWTIc"];
var i = 1;
var img = new Image();
img.onload = function() {
document.body.style.backgroundImage = 'url(' + img.src + ')';
i++;
if (i == arr.length)
i = 0;
setTimeout(function() {
img.src = arr[i];
}, 5000);
};
img.src = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRyB57zuc4bms-hDtWMa-4BZvscIlJDm4r7a9WLaO4SAxUvKM-DDA";
body {
transition: background ease 2s;
}
Try to use https://greensock.com/gsap, it is really efficient in transitions and animation handling. Many experts use it for efficient transition or animation management.
When you change the backgroundImage via javascript the image is loaded the moment the script is executed, so there will be a noticable lag. A solution is to load the images in css or to preload via js.
In below solution I added the images via css so there is no lag. Because Firefox doesn't support transition of background-image the script z-indexes the images in the right order and fades them (with a css animation on opacity).
html:
<div id="sectionAbout">
<div class="img"></div>
<div class="img"></div>
<div class="img"></div>
<div class="img"></div>
</div>
css:
#sectionAbout {
height: 100vh;
}
.img {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-size: cover;
}
.fadeIn {
animation: fadeIn 2s;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.img:nth-of-type(1) {
z-index: 1;
background-image: url(http://picsum.photos/400/300?image=1);
}
etc..
js:
var imgDivs = document.querySelectorAll(".img");
setInterval(changeImage, 2000);
var i = 0;
function changeImage() {
i++;
el = imgDivs[i%4];
el.classList.remove("fadeIn");
// force css animation restart
// (https://css-tricks.com/restart-css-animation/)
void el.offsetWidth;
el.style.zIndex = i;
el.classList.add("fadeIn");
}
For a working example see here:
https://jsfiddle.net/tfc0kyp3/3/
The delelement code is working fine but I want to delete the element after the css animation is finished for "delorean", then I need the animation to start again every time the button is clicked, how can I use my "delelement" code to achieve this? thanks.
function touchDelorean(event) {
event.preventDefault();
if (showDelorean == true) {
delorean();
}
}
function delorean() {
var image = document.createElement("img");
image.id = "delorean";
image.src = "Images/delorean/" + where + ".png";
document.getElementById("deloreanContainer").appendChild(image);
// delelement("deloreanContainer");
}
function delelement(elem) {
var element = document.getElementById(elem);
while (element.firstChild) { element.removeChild(element.firstChild); }
}
CSS
#delorean {
position: absolute;
top: 0%;
left: 0%;
width: 29%;
height: 9.8%;
opacity: 1.0;
-webkit-animation: delorean_anim 10s linear;
-webkit-animation-direction: normal, horizontal ;
-webkit-animation-timing-function: cubic-bezier(1, 0, 1, 0);
}
#-webkit-keyframes delorean_anim {
0% { -webkit-transform: translate(-24vw, 0vw) scale(0.6, 0.6) rotate(0deg) }
20% { -webkit-transform: translate(137vw, 36vw) scale(3.5, 3.5) rotate(0deg) }
100% { -webkit-transform: translate(137vw, 36vw) scale(3.5, 3.5) rotate(0deg)}
}
Use setTimeout() and do a time equal or greater to that of your CSS Transition time... so if:
transition: all 3s ease;
then...
function delorean() {
var image = document.createElement("img");
image.id = "delorean";
image.src = "Images/delorean/" + where + ".png";
document.getElementById("deloreanContainer").appendChild(image);
setTimeout( function { delelement("deloreanContainer"); }, 3000 );
}
function delelement(elem) {
var element = document.getElementById(elem);
while (element.firstChild) { element.removeChild(element.firstChild); }
}
On the element that runs the animation, given that it is image you can add an eventlistener..
// Chrome, Safari and Opera
image.addEventListener('webkitAnimationEnd', function() {
image.remove()
});
// Standard syntax
image.addEventListener('animationend', function() {
image.remove()
});
If you're dealing with a css transition and not a css animation then you're looking for transitionend. These events can however be unreliable sometimes so if you know the length of the animation, you're better off with setTimeout as suggested above.
In react.js the infamous CSSTransitionGroup component had many problems due to the transition event not fireing as expected. They "solved" the problem by requiring specifying transition timeout values for the component..
I tried the CSS route but all new to me and learning still but cannot seem to work it out. My JS below switches the background position to show a new image in the sprite every 1 second but wondering if anyone knew how I can kind of give it a small scale effects so when it changes grows a little then back to normal size before change to the next background position?
JS:
// Avatar animations
var avatarInterval;
function startAvatarAnimation() {
var i = 0;
var avatarSpeed = 500;
var avatarCount= 11;
var avatarHeight = 250;
var avatarTotalHeight = 2750;
avatarInterval = setInterval(function(){
i++;
if(i > 11){
i = 0;
}
$(".avatars").css({'background-position' : '0 -' + (i*avatarHeight) + 'px' });
$(".avatars").toggleClass('scaleIn', 'scaleOut');
}, avatarSpeed);
return false;
}
function stopAvatarAnimation(){
clearInterval(avatarInterval);
$(".avatars").css({'background-position' : '0 0' });
return false;
}
JS below switches the background position to show a new image in the
sprite every 1 second but wondering if anyone knew how i can kind of
give it a small scale effects so when it changes grows a little then
back to normal size before change to the next background position?
Try utilizing transition at css , setting duration to half of avatarSpeed or half of total duration of background-position effect ; setting transitionend event at .one() to prevent recursive call to transitionend handler , .removeClass() , .addClass() to toggle scale effect defined at css
css
.avatars {
transition: transform 500ms ease-in-out;
width: 100px;
height: 100px;
background-image: url(/path/to/background-image);
}
.avatars.scaleIn {
transform: scale(1.1, 1.1);
}
.avatars.scaleOut {
transform: scale(1.0, 1.0);
}
js
// Avatar animations
var avatarInterval;
function startAvatarAnimation() {
var i = 0;
var avatarSpeed = 500;
var avatarCount= 11;
var avatarHeight = 250;
var avatarTotalHeight = 2750;
avatarInterval = setInterval(function(){
i++;
if(i > 11){
i = 0;
}
$(".avatars").css({'background-position' : '0 -' + (i*avatarHeight) + 'px' })
.removeClass("scaleOut").addClass("scaleIn")
.one("transitionend", function() {
$(this).removeClass("scaleIn").addClass("scaleOut");
});
}, avatarSpeed);
return false;
}
$(".avatars").on("click", function() {
$(this).removeClass("scaleOut").addClass("scaleIn")
.one("transitionend", function() {
$(this).removeClass("scaleIn").addClass("scaleOut");
})
})
.avatars {
transition: transform 500ms ease-in-out;
width: 100px;
height: 100px;
background-image: url(http://lorempixel.com/100/100/nature);
}
.avatars.scaleIn {
transform: scale(1.1, 1.1);
}
.avatars.scaleOut {
transform: scale(1.0, 1.0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div class="avatars"></div>