Reputation: 25954
Is it possible to get/set the current animation percentage of a CSS3 @keyframes
animation using javascript, jQuery, or some other means?
Say for example there is a div
with class called .spin
that simply spins around in a circle using a keyframe also called spin
.
I have tried to get the current percentage value of the animation using $('.spin').css('animation')
, $('.spin').css('animation: spin')
, and a couple other ways, but they all alert empty
I'm also interested in changing the original animation at each predefined keyframe % and I have tried things like $('.spin').css('animation', '..new definition here...')
and $('.spin').css('spin', '50%', '...new definition here...)
to no avail.
Any ideas?
Upvotes: 10
Views: 6684
Reputation: 125
Its never too late to get to a party.
//Animation pause at specific percentage, Example: pauseAnimationAt("myDiv",33,10)
function pauseAnimationAt(l,p,d){
percentage = p/d*1000;
function pauseAnimation(){
setTimeout(function(){ document.getElementById(l).style="animation-play-state: paused"; }, percentage);//l = Element ID, p = percentage when you wanna stopt animation, d = Duration of animation (Yes, you need to know that)
}
document.getElementById(l).addEventListener("animationstart", pauseAnimation());
}
Upvotes: -1
Reputation: 25954
I achieved roughly what I wanted using pure javascript with my CSS3.
For my experiment to come up with a way to do these objectives, I created a basic CSS3 animation rotating a circle around a small circular path. My goal was to, when a button was clicked, change the origin of the animation to the new location
To achieve the first goal of getting the percentage value of the animation I simply approximated the current percentage using the following setInterval
, which displays the approximated current percent. This runs every 40 milliseconds to correspond with the duration of the animation (milliseconds / 100)
var result = document.getElementById('result'), currentPercent = 0;
var showPercent = window.setInterval(function() {
if(currentPercent < 100)
{
currentPercent += 1;
}
else {
currentPercent = 0;
}
result.innerHTML = currentPercent;
}, 40);
Note on this solution:
To achieve the second goal of setting a new definition for an animation's % value it took a bit of a more complex solution. After pouring through dozens of articles and web pages (the important ones listed below), I managed to come up with the following solution:
var circle = document.getElementById('circle'),
button = document.getElementById('button');
var result = document.getElementById('result'),
totalCurrentPercent = 0,
currentPercent = 0;
var showPercent = window.setInterval(function() {
if(currentPercent < 100)
{
currentPercent += 1;
}
else {
currentPercent = 0;
}
result.innerHTML = currentPercent;
}, 40);
function findKeyframesRule(rule) {
var ss = document.styleSheets;
for (var i = 0; i < ss.length; ++i) {
for (var j = 0; j < ss[i].cssRules.length; ++j) {
if (ss[i].cssRules[j].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE && ss[i].cssRules[j].name == rule) { return ss[i].cssRules[j]; }
}
}
return null;
}
function change(anim) {
var keyframes = findKeyframesRule(anim),
length = keyframes.cssRules.length;
var keyframeString = [];
for(var i = 0; i < length; i ++)
{
keyframeString.push(keyframes[i].keyText);
}
var keys = keyframeString.map(function(str) {
return str.replace('%', '');
});
totalCurrentPercent += currentPercent;
if(totalCurrentPercent > 100)
{
totalCurrentPercent -= 100;
}
var closest = getClosest(keys);
var position = keys.indexOf(closest),
firstPercent = keys[position];
for(var i = 0, j = keyframeString.length; i < j; i ++)
{
keyframes.deleteRule(keyframeString[i]);
}
var multiplier = firstPercent * 3.6;
keyframes.insertRule("0% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 0) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 0) + "deg); background-color:red; }");
keyframes.insertRule("13% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 45) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 45) + "deg); }");
keyframes.insertRule("25% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 90) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 90) + "deg); }");
keyframes.insertRule("38% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 135) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 135) + "deg); }");
keyframes.insertRule("50% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 180) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 180) + "deg); }");
keyframes.insertRule("63% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 225) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 225) + "deg); }");
keyframes.insertRule("75% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 270) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 270) + "deg); }");
keyframes.insertRule("88% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 315) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 315) + "deg); }");
keyframes.insertRule("100% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 360) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 360) + "deg); }");
circle.style.display = "inherit";
circle.style.webkitAnimationName = anim;
window.clearInterval(showPercent);
currentPercent = 0;
showPercent = self.setInterval(function() {
if(currentPercent < 100)
{
currentPercent += 1;
}
else {
currentPercent = 0;
}
result.innerHTML = currentPercent;
}, 40);
}
button.onclick = function() {
circle.style.webkitAnimationName = "none";
circle.style.display = "none";
setTimeout(function () {
change("rotate");
}, 0);
}
function getClosest(keyframe) {
var curr = keyframe[0];
var diff = Math.abs (totalCurrentPercent - curr);
for (var val = 0; val < keyframe.length; val++) {
var newdiff = Math.abs(totalCurrentPercent - keyframe[val]);
if (newdiff < diff) {
diff = newdiff;
curr = keyframe[val];
}
}
return curr;
}
Check out the experiment itself here including comments describing what each part of the javascript is doing
Notes on this solution:
@keyvalue
percentageIn the process of trying to come up with a solution for the problem, I found these useful resources:
---EDIT---
If you are just using CSS transitions or you can change your animation to just use transitions instead, you can use this simpler approach. You can pause the transition by copying the attributes changed by the transition, setting the attributes to those changed attributes, and then removing the class that animates it. Of course if you are using the same object to animate/pause you will need to animate the first click then pause it the next click. You can easily do the pure javascript equivalent as well
Note: the !important
in the CSS changed attribute is necessary unless you have a more leveled selector for the animation class than the jQuery selector, aka something like div #defaultID.animationClass {
as opposed to just #defaultID.animationClass {
. Since #defaultID
and #defaultID.animationClass
are both one level, this example requires the !important
--Another Edit--
For more information on this topic, check out my post on CSS-Tricks
Upvotes: 15