Ответ 1
Функция замедления обычно представляет собой функцию, которая описывает значение свойства с учетом процента его полноты. В разных платформах используются несколько разные варианты, но концепцию легко понять, как только вы ее поймете, но, вероятно, лучше посмотреть несколько примеров.
Сначала давайте посмотрим на интерфейс, который будут выполнять все наши функции замедления.
Наши функции замедления будут принимать несколько аргументов:
- процентное завершение: (от
0.0
до1.0
). - elaspedTime: количество миллисекунд, в течение которых запускалась анимация
- startValue: значение, с которого нужно начинать (или значение, когда процент выполнения равен 0%)
- endValue: значение, которое заканчивается в (или значение, когда процент завершения равен 100%)
- totalDuration: общая требуемая длина анимации в миллисекундах.
И вернет число, представляющее значение, на которое должно быть установлено свойство.
Примечание: это та же сигнатура, которую jQuery использует для своих функций замедления, которые я заимствую для примеров.
Самым простым для понимания является линейная легкость:
var linear = function(percent,elapsed,start,end,total) {
return start+(end-start)*percent;
}
А теперь, чтобы использовать это:
Допустим, у нас была анимация, которая собиралась работать в течение 1000 миллисекунд и должна была начинаться с 0 и заканчиваться на 50. Передача этих значений в нашу функцию замедления должна сказать нам, каким должно быть действительное значение:
linear(0, 0, 0,50, 1000) // 0
linear(0.25, 250, 0, 50, 1000) // 12.5
linear(0.5, 500, 0, 50, 1000) // 25
linear(0.75, 750, 0, 50, 1000) // 37.5
linear(1.0, 1000, 0, 50, 1000) // 50
Это довольно прямолинейный (не каламбур) подросток. Это простая линейная интерполяция. Если бы вы представляли график зависимости от времени, это была бы прямая линия:
Давайте взглянем на немного более сложную функцию замедления, квадратичную простоту в:
var easeInQuad = function (x, t, b, c, d) {
return c*(t/=d)*t + b;
}
И давайте посмотрим на те же результаты, используя те же входные данные, что и раньше:
easeInQuad(0, 0, 0, 50, 1000) // 0
easeInQuad(0.25, 250, 0, 50, 1000) // 3.125
easeInQuad(0.5, 500, 0, 50, 1000) // 12.5
easeInQuad(0.75, 750, 0, 50, 1000) // 28.125
easeInQuad(1, 1000, 0, 50, 1000) // 50
Обратите внимание, что значения сильно отличаются от нашей линейной легкости. Он начинается очень медленно, затем ускоряется до конечной точки. При завершении анимации на 50% она достигла значения 12,5, что составляет четверть фактического расстояния между указанными start
и end
значениями.
Если бы мы построили график этой функции, она бы выглядела примерно так:
Теперь давайте взглянем на простое упрощение:
var easeOutQuad = function (x, t, b, c, d) {
return -c *(t/=d)*(t-2) + b;
};
Это, по сути, делает "противоположную" кривую ускорения легкостью. Она начинается быстро, а затем замедляется до конечного значения:
И затем есть функции, которые облегчают как вход, так и выход:
var easeInOutQuad = function (x, t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
};
Эта функция начинается медленно и заканчивается медленно, достигая максимальной скорости в середине.
Вы можете использовать несколько видов ослабления/интерполяции: линейное, квадратичное, кубическое, квартовое, квинтовое, синусоидальное. И есть специальные функции смягчения, такие как Bounce и эластичные, которые имеют свои собственные.
Например, упругая легкость в:
var easeInElastic = function (x, t, b, c, d) {
var s=1.70158;var p=0;var a=c;
if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
if (a < Math.abs(c)) { a=c; var s=p/4; }
else var s = p/(2*Math.PI) * Math.asin (c/a);
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
},
Возможно, кто-то еще может объяснить фактическую математическую часть, стоящую за интерполяцией, потому что, честно говоря, я не математик. Но это основной принцип ослабления самих функций.
Когда вы запускаете анимацию/анимацию, механизм анимации запоминает начальные и конечные значения, которые вы хотите. Затем каждый раз, когда он обновляет, его цифры из того, сколько времени прошло. Он вызывает поставляемую функцию замедления со значениями, чтобы определить значение, которое должно быть установлено для свойства. Пока все функции замедления реализуют одну и ту же сигнатуру, их можно легко заменить, и ядро анимации не должно знать различий. (Что делает для отличного разделения проблем).
Вы заметите, что я избегал явно говорить о позициях x
и y
, потому что замедление не имеет ничего общего с позицией как таковой. Функция замедления просто определяет переход между начальным и конечным значениями. Это могут быть координаты x
, цвет или прозрачность объекта.
И на самом деле, теоретически, вы можете применять разные функции замедления для интерполяции для разных свойств. Надеюсь, это поможет пролить свет на основную идею.
И вот действительно крутой пример (который использует немного другую сигнатуру, но тот же принцип), с которым можно поиграть, чтобы понять, как ослабление связано с позицией.
редактировать
Вот небольшой jsFiddle, который я собрал, чтобы продемонстрировать некоторые основные способы использования javascript. Обратите внимание, что свойство top
изменяется с помощью bounce, а свойство left
- с помощью quad. Используйте ползунок для имитации цикла рендеринга.
Поскольку все функции в объекте easing
имеют одинаковую сигнатуру, вы можете поменять любую из них друг на друга. Прямо сейчас большинство этих вещей жестко запрограммированы (такие как начальные и конечные значения, используемые функции анимации и длина анимации), но в реальном примере помощника по анимации вы захотите передать в следующих свойствах:
- Свойство, которое будет изменено
- Начальное значение (или, если оно оставлено
undefined
используйте его текущее значение) - Конечное значение
- Длина анимации должна быть
- Ссылка на функцию анимации, которую вы хотите использовать.
Анимационный движок будет отслеживать эти настройки на протяжении всей анимации и в течение каждого цикла обновления будет использовать аргумент анимации для вычисления нового значения свойств.