2013-08-01 2 views
10

Возможно ли получить/установить текущий процент анимации анимации CSS3 @keyframes с использованием javascript, jQuery или каких-либо других средств?Получить/установить текущие процентные/ключевые ключевые слова в ключевых словах

Скажем, например, есть div с классом .spin, который просто крутится вокруг по кругу, используя ключевой кадр, также называемый spin.

  1. Я попытался получить текущее процентное значение анимации с использованием $('.spin').css('animation'), $('.spin').css('animation: spin'), и несколько других способов, но все они пустые оповещения

  2. Я также заинтересован в изменении исходной анимации на каждом предопределенном ключевом кадре%, и я пробовал такие вещи, как $('.spin').css('animation', '..new definition here...') и $('.spin').css('spin', '50%', '...new definition here...) безрезультатно.

Любые идеи?

ответ

12

Я достиг примерно того, что хотел, используя чистый javascript с моим CSS3.

Для моего эксперимента, чтобы найти способ сделать эти цели, я создал базовую анимацию CSS3, вращающую круг вокруг небольшого кругового пути. Моя цель состояла в том, чтобы, когда кнопка была нажата, изменить начало анимации на новое место

Для достижения первой цели получения процентного значения анимации я просто аппроксимировать текущий процент, используя следующую setInterval , который отображает приблизительный процент процента. Это выполняется каждые 40 миллисекунд, чтобы соответствовать продолжительности анимации (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); 

Примечание по этому решению:

  • Это не является совершенным из-за, потому что счетчик продолжает работать, когда еще одна закладка щелкнул, но анимация останавливается, поэтому они становятся несинхронизированными
  • Это также ошибка, когда кнопка нажата долго после последнего щелчка. Очевидно, что setInterval работает немного дольше, чем анимация, так что они становятся все меньше и меньше синхронизируются каждая итерация
  • Я искал везде для более совершенного решения, но не смог придумать один как еще

Для достижения второй цели определения нового значения для значения% анимации потребовалось немного более сложное решение.После заливки через десятки статей и веб-страниц (важные из них перечислены ниже), мне удалось придумать следующее решение:

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 включая комментарии, описывающие то, что каждая часть JavaScript делает

Замечания по этому решению:

  • Я попытался сделать функцию изменения как не жестко закодированы как можно
  • Он работает хорошо для аппроксимации тока @keyvalue процент
  • Переход от одной анимации к другой только сглажен, как только ближайшее ближайшее значение% анимации относится к текущему% анимации, поэтому добавление более% определений в анимацию будет сделать его еще более гладкой

в процессе пытается придумать решение для этой проблемы, я нашел эти полезные ресурсы:

  • RussellUresti's answer in this SO post и corresponding example был весьма влиятельным и очень помогло мое окончательное решение
  • Чтобы получить наиболее близкое значение на основе ввода и массив значений, я использовал метод paxdiablo в this SO post (спасибо)
  • This plugin, в то время как я не использовал его сам, казалось, достичь очень похожи (хотя, казалось бы, не совсем в настраиваемый) эффект в JQuery

--- EDIT ---

Если вы используете только CSS переходы или вы можете изменить анимацию, чтобы просто использовать переходы вместо этого, вы можете использовать this simpler approach. Вы можете приостановить переход, скопировав атрибуты, измененные в результате перехода, установив атрибуты для этих измененных атрибутов, а затем удалив класс, который его оживляет. Конечно, если вы используете один и тот же объект для анимации/паузы, вам нужно будет анимировать первый клик, а затем приостановить его следующим щелчком. Вы можете легко сделать Чистый JavaScript эквивалент, а

Примечание:!important в атрибуте CSS изменен, необходимо, если у вас есть более выровненный селектор для класса анимации, чем селектор JQuery, иначе что-то вроде div #defaultID.animationClass {, в отличие от только #defaultID.animationClass {. Поскольку #defaultID и #defaultID.animationClass оба один уровень, этот пример требует !important

--Another Edit--

Для получения дополнительной информации по этой теме, проверить my post on CSS-Tricks

Смежные вопросы