Я достиг примерно того, что хотел, используя чистый 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
процент
- Переход от одной анимации к другой только сглажен, как только ближайшее ближайшее значение% анимации относится к текущему% анимации, поэтому добавление более% определений в анимацию будет сделать его еще более гладкой
в процессе пытается придумать решение для этой проблемы, я нашел эти полезные ресурсы:
--- 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