Each time a css3 animation loops I'd like to change a variable in the style.
For example the following css drops a group of parachutes from the top to the bottom of the screen:
#-webkit-keyframes fall {
0% { top: -300px; opacity: 100; }
50% { opacity: 100; }
100% { top: 760px; opacity: 0; }
}
#parachute_wrap {
-webkit-animation-name: fall;
-webkit-animation-iteration-count: infinite;
-webkit-animation-duration: 70s;
-webkit-animation-timing-function: linear;
}
Ideally however, at the end of each loop I'd like to throw in a random X position.
The default style of the group is:
#parachute_wrap {
position: absolute;
top: -300px;
left: 50%;
margin-left: 140px;
}
So after 70 seconds, I would like to change the margin-left or left attribute anywhere between -200px and 200px.
I understand I could do something like this with jquery and everytime():
$('#parachute_wrap').everyTime ( 70000, function (){
$("#parachute_wrap").css({left: Math.floor(Math.random() * 51) + 5 + '%'},0);
});
But is there a way to tie the css loop to js to do this? i.e. is there a return call of any kind which js can listen to for perfect syncing with the animation? I fear that if I use JS on a 70s timer whats going to happen is the timing is going to not sync right, and half way through the css animation the js will do its timed loop and the parachutes are going to jump around the place half way through the animation.
How would you approach this?
CSS3 animations have an animationEnd event fired when the animation completes.
You can bind that event to your animated element thus triggering that left change at the end of each animation:
$('#parachute_wrap').on('webkitAnimationEnd mozAnimationEnd msAnimationEnd oAnimationEnd animationEnd', function(e) {
$(this).css({left: Math.floor(Math.random() * 51) + 5 + '%'},0);
});
This way, you know exactly when the animation ends and the left change is applied correctly.
There is also an animationiteration event fired at the start of every new animation iteration, i.e. every iteration except the first.
$('#parachute_wrap').on('animationiteration webkitAnimationIteration oanimationiteration MSAnimationIteration', function(e) {
$(this).css({left: Math.floor(Math.random() * 51) + 5 + '%'},0);
});
http://www.w3.org/TR/css3-animations/#animationiteration
Related
I am using transition: opacity 5s; property. I want to show different alert or console message when my opacity value is 0.4 or 0.6 or .2 . on button click I am doing transition but I want to know opacity progress so that i will show those message ?
is there any way to do this
var btn = document.querySelector("button");
var par = document.querySelector("#parId");
btn.addEventListener("click", (e) => {
par.classList.add("removed");
});
par.addEventListener("transitionend", () => {
par.remove();
});
#parId {
transition: opacity 5s;
}
.removed {
opacity: 0;
}
we are getting transitionend callback if there any progress callback where I will check opacity value ?
There is no event that can be listened to to give what you want - unless you are going to use a linear transition. In that case you can carve your changes of opacity up into 0.2s slots, changing opacity on transitionend to the next value down - 0.8, 0.6 etc.
Your code however takes the default for the transition-timing-function property which is ease - not linear - so transitionend is of no use to you.
This snippet polls the opacity changes every tenth of a second and writes the current opacity to the console so you can see what is happening.
A couple of points: you will have to check for when the opacity goes just less than one of your break points, you are unlikely every to hit it just at exactly 0.6s or whatever; also notice that the console carries on being written to after the element has totally disappeared. The timing will not be exact, things are happening asynchronously.
<style>
#parId {
transition: opacity 5s;
width: 50vw;
height: 50vh;
background: blue;
opacity: 1;
display: inline-block;
}
.removed {
opacity: 0;
}
</style>
<div id="parId"></div>
<button>Click me</div>
<script>
var btn = document.querySelector("button");
var par = document.querySelector("#parId");
btn.addEventListener("click", (e) => {
let interval = setInterval(function () {
const opacity = window.getComputedStyle(par).opacity
console.log(opacity);
if (opacity == 0) {clearInterval(interval);}
}, 100);
par.style.opacity = 0;
});
</script>
You could potentially check periodically like this, although your interval will need to be at least the speed of the opacity animation or be quicker than it to catch the values.
var par = document.querySelector("#parId");
setInterval(function() {
console.log(window.getComputedStyle(par).opacity);
}, 100)
#parId{
opacity: 0.2;
transition: opacity 3s ease-in-out;
}
#parId:hover {
opacity: 1;
}
<div id="parId">
test
</div>
Take a look in this example
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/animationend_event
You could define your animation stages as diferent ranimations on css then call them in chain via javascript. Before, you must set an event listener for the animationend event, and every time the event is fired you check the #parId opacity.
You could do it.with jQuery to, totaly in javascript
I have a problem with looped fade-in/fade-out image source changing in JS and CSS and using SetTimeout() callback.
The problem is, that the sequence is working strange: sometimes the image changes before the transition starts, sometimes it works fine, and sometimes in the other way.
Here is my JS:
const animationTime = 5000;
const transitionTime = 500;
function nextImage() {
let img = document.getElementById('img1');
img.classList.remove('hidden');
setTimeout(function () {
img.classList.add('hidden');
},animationTime-transitionTime);
img.src=randomize();
setTimeout(nextImage, animationTime);
}
randomize() function just gets a random image path from array.
Here is HTML:
<div class="some-class">
<img class="some-image" id="img1" src="1.png">
</div>
And here is CSS:
.some-image {
transition: opacity 0.5s linear;
-webkit-transition: opacity 0.5s linear;
-o-transition: opacity 0.5s linear;
-moz-transition: opacity 0.5s linear;
-moz-border-radius: 15px;
}
.hidden {
opacity: 0;
}
Upd.
So I have edited CSS file:
.some-image {
width: 370px;
height: 190px;
animation: fade-out;
animation-duration: 1s;
}
.hidden {
animation: fade-out;
animation-duration: 1s;
}
#keyframes fade-in {
from {opacity: 0;}
to {opacity: 1;}
}
#keyframes fade-out {
from {opacity: 1}
to {opacity: 0}
}
And JS-file:
function nextImage() {
let img = document.getElementById('img1');
img.classList.remove('hidden');
setTimeout(function () {
img.classList.add('hidden');
},animationTime-1000);
img.src=randomize();
}
setTimeout(nextImage, animationTime);
}
And, somehow, it works perfectly on a local machine, but on a dedicated website animation sometimes fades-in before the image source changed.
I think the problem is about timing. The setTimeout function didn't guarantee to execute exactly time as argument set. So there is a possibility that you change the src of image before/after it add/remove hidden class. These delay is rarely happens that might be the reason why it works on your machine.
So this problem can solve by every time you change the image you must have to make sure the image is completely hide.
const nextImage = function () {
let img = document.querySelector('img')
img.classList.add('hidden')
setTimeout(() => {
img.style.visibility = 'hidden'
img.src = randomImage()
// skip to next frame, may be this not necessary to use setTimeout
setTimeout(() => {
img.style.visibility = ''
img.classList.remove('hidden')
}, 10)
}, animationDuration)
setTimeout(nextImage, intervalDuration + animationDuration)
}
The new cycle will be: fade image out, wait for animation then change image (with set visibility to hidden) and then fade in. And loop.
With this approach. If setTimeout is early execute before the image has completely fade out the visibility will be set hidden. If it's delayed, the image will be hide a bit longer.
Live example here. In that code I add a little bit noise with random time to test.
Unfortunately, After I spent an hour to see my answer is right I still feel it's not perfect anyway and it will be worse if you image is large. I would recommend you try two or more img tags instead.
You should try using css animations instead. You can easily implement the above with it, and it will save you the trouble of handling animations in your code.
When my webpage is first loaded, my starting div rotates using this CSS code:
#keyframes rotate
{
from { transform:rotate(0deg);
-ms-transform:rotate(0deg);
-webkit-transform:rotate(0deg); }
to { transform:rotate(360deg);
-ms-transform:rotate(360deg);
-webkit-transform:rotate(360deg); }
}
#-webkit-keyframes rotate
{
from { transform:rotate(0deg);
-ms-transform:rotate(0deg);
-webkit-transform:rotate(0deg); }
to { transform:rotate(360deg);
-ms-transform:rotate(360deg);
-webkit-transform:rotate(360deg); }
}
After the rotation, this code is useless.
I would like it so when a button is clicked, it will make this rotation again.
To do this I need to be able to put this css code into a javascript/jQuery function so I can call it at any time.
Is this possible?
TRY THIS
$({deg: 0}).animate({deg: d}, {
duration: 2000,
step: function(now){
elem.css({
transform: "rotate(" + now + "deg)"
});
}
});
Look at JSFIDDLE DEMO
You can wrap your animation behavior into a class like:
.rotate{
-webkit-animation: rotate 4s;
/* more prefixes if you want to */
animation: rotate 4s;
}
Then you can apply that class on click of your button like:
$('#myButton').click(function(){
$('#myElementToAnimate').addClass('rotate');
});
To remove the class once your animation has finished you have to listen for the animationend event like:
$('#myButton').click(function(){
// all the different event names are due to the fact that this isn't fully standardized yet
$('#myElementToAnimate').addClass('rotate').on('animationend webkitAnimationEnd oanimationend MSAnimationEnd', function(){
$(this).removeClass('rotate');
});
});
This should give you smoother results than using JavaScript based animation. See this demo fiddle
by simply applying the CSS properties and the desired values to jQuery
DEMO
$(' #box ').css({
transition: '2s linear',
transform: 'rotate(360deg)'
});
P.S: jQuery will handle all those -browser-specific prefixes for you.
I'm trying to learn how transitionend is used with my CSS3 transitions so I have a set of images that are sized into a grid as well as the opacity changed from 0 - 1, ideally what I want to do is wait until all those images have finished and the final transitionend event has fired off before carrying on with my next code. At the moment I'm simply trying to log out a message when transitionend fires but I'm getting nothing which means I'm probably using this wrong. Can anyone advise how I could do this?
JS Fiddle: http://jsfiddle.net/mWE9W/2/
CSS
.image img {
position: absolute;
top: 0;
left: 0;
opacity: 0.01;
-webkit-transition: all 1s ease-in;
-webkit-transform: scale(0);
height: 150px;
width: 150px;
display:block;
}
.inner.active .image img {
-webkit-transform: scale(1);
top: 0;
left: 0;
opacity: 1;
}
JS
$('.image img').on('webkitTransitionEnd', function(e) {
console.log('this ran')
$('h2').fadeIn();
}, false);
1) You don't need last argument false in .on method call. Your callback never called because of that.
2) Once you'll remove that unneeded argument you'll notice that callback is actually called 16 times. This happens because you have 4 images with 4 transition proporties. Animating each property causes callback to be called. So you need to make some sort of check that image transition is complete, and only after all transitions are done call your .fadeIn() method. The code will look like following:
var imageCount = $('.image img').length, animatedCount = 0, animCompleteImages = $();
$('img').imagesLoaded(function() {
$('.inner').addClass('active').on('webkitTransitionEnd', 'img', function(e) {
if(!animCompleteImages.filter(this).length) {
animCompleteImages = animCompleteImages.add(this);
animatedCount++;
if(animatedCount === imageCount) {
$('h2').fadeIn();
}
}
});
});
Working JS fiddle available here.
I'm using CSS3 Animations, and I want to be able to move to a specific spot in the animation. For instance, if the CSS looks like this (and pretend that I used all the proper prefixes):
#keyframes fade_in_out_anim {
0% { opacity: 0; }
25% { opacity: 1; }
75% { opacity: 1; }
100% { opacity: 0; }
}
#fade_in_out {
animation: fade_in_out_anim 5s;
}
then I would like to be able to stop the animation, and move it to the 50% mark. I guess that the ideal JavaScript would look something like this:
var style = document.getElementById('fade_in_out').style;
style.animationPlayState = 'paused';
// Here comes the made up part...
style.animation.moveTo('50%'); // Or alternately...
style.animationPlayPosition = '50%';
Does anyone know of a way to make this happen (hopefully in Webkit)?
We can use the animation-delay property. Usually it delays animation for some time, and, if you set animation-delay: 2s;, animation will start two seconds after you applied the animation to the element. But, you also can use it to force it to start playing animation with a specific time-shift by using a negative value:
.element-animation{
animation: animationFrames ease 4s;
animation-delay: -2s;
}
http://default-value.com/blog/2012/10/start-css3-animation-from-specified-time-frame/