Что такое функция ослабления? - PullRequest
42 голосов
/ 29 ноября 2011

Что подразумевается под ослаблением функции в контексте анимации. Похоже, что в dojo, jquery, silverlight, flex и других системах пользовательского интерфейса есть функция замедления. Я не мог найти хорошее объяснение функций ослабления? Может кто-нибудь объяснить концепцию функций ослабления или дать хорошее объяснение их, меня интересует концепция, а не конкретные детали структуры?

Строгие ли строго используются для определения местоположения или это общее и может применяться к любому свойству объекта?

Ответы [ 5 ]

100 голосов
/ 30 ноября 2011

Функция замедления обычно представляет собой функцию, которая описывает значение свойства с учетом процента полноты. В разных фреймворках используются несколько разные вариации, но концепцию легко понять, как только вы ее поймете, но, вероятно, лучше посмотреть несколько примеров.

Сначала давайте посмотрим на интерфейс, который будут выполнять все наши функции замедления.

Наши функции замедления будут принимать несколько аргументов:

  • процентовПолный: (* ​​1008 * до 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

Это довольно прямолинейная (не каламбур) анимация. Это простая линейная интерполяция. Если бы вы рассчитывали значение в зависимости от времени, это была бы прямая линия:

Linear ease

Давайте взглянем на немного более сложную функцию замедления, квадратичная простота в:

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.

Если бы мы построили график этой функции, она бы выглядела примерно так:

Quad-Ease-In

Теперь давайте взглянем на простое упрощение:

var easeOutQuad = function (x, t, b, c, d) {
    return -c *(t/=d)*(t-2) + b;
};

Это, по сути, делает "противоположную" кривую ускорения замедления. Она начинается быстро, а затем замедляется до своего конечного значения:

Ease out

А затем есть функции, которые облегчают как вход, так и выход:

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;
};

EaseInOut

Эта функция запускается медленно и заканчивается медленно, достигая максимальной скорости в середине.

Существует несколько групп замедления / интерполяции, которые вы можете использовать: линейное, квадратичное, кубическое, квартовое, квинтовое, синусоидальное. И есть специальные функции замедления, такие как Bounce иastic, которые имеют свои собственные.

Например, упругая легкость в:

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;
},

Elastic ease in

Возможно, кто-то еще может объяснить фактическую математическую часть, стоящую за интерполяцией, потому что, честно говоря, я не математик. Но это основной принцип самих функций замедления.

Когда вы запускаете анимацию / анимацию, движок анимации запоминает начальные и конечные значения, которые вы хотите. Затем каждый раз, когда он обновляет, его цифры из того, сколько времени прошло. Он вызывает поставляемую функцию замедления со значениями, чтобы определить значение, которое должно быть установлено для свойства. Пока все функции замедления реализуют одну и ту же сигнатуру, их можно легко заменить, и ядро ​​анимации не должно знать различий. (Что делает для отличного разделения проблем).

Вы заметите, что я избегал явно говорить о x и y позициях, потому что замедление не имеет ничего общего с позицией как таковой . Функция замедления просто определяет переход между начальным и конечным значениями. Это могут быть x координаты, или цвет, или прозрачность объекта.

И фактически, теоретически, вы можете применять разные функции замедления для интерполяции для разных свойств.Надеюсь, это поможет пролить некоторый свет на основную идею.

А вот действительно классный пример (который использует немного другую подпись, но тот же принцип), с которым можно поиграть, чтобы получитьИдея о том, как ослабление относится к позиции.


Редактировать

Вот немного jsFiddle Я собрал вместе, чтобы продемонстрировать некоторые из основныхиспользования в JavaScript.Обратите внимание, что для свойства top используется анимация с использованием bounce, а для свойства left используется анимация с использованием квадрата.Используйте ползунок для имитации цикла рендеринга.

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

  • Изменяемое свойство
  • Начальное значение (или, если осталось undefined, то использовать его текущее значение)
  • Конечное значение
  • Длина анимации должна быть
  • Ссылка на функцию анимации, которую вы хотите использовать.

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

11 голосов
/ 29 ноября 2011

Функция замедления - это алгоритм, который управляет скоростью анимации для достижения желаемого эффекта (подпрыгивание, увеличение и замедление и т. Д.).

Посмотрите, что MSDN говорит о них , чтобы узнать немного подробнее.

2 голосов
/ 21 июля 2016

Я хотел бы опубликовать свой ответ на этот старый вопрос, даже если на него есть принятый ответ. 32bitkid дал необходимое объяснение.Я добавлю базовую практическую реализацию, потому что я не смог найти ее (которую я также опубликовал вопрос об этом).

Возьмем, к примеру, эту простую линейную анимацию.Я сомневаюсь, что это требует каких-либо объяснений, так как код не требует пояснений.Мы вычисляем постоянное значение приращения, которое не меняется со временем, и на каждой итерации мы увеличиваем положение блока.Мы изменяем переменную положения напрямую, а затем применяем ее к блоку.

JSFiddle

var box = document.getElementById("box");

var fps           = 60;
var duration	  = 2;                                   // seconds
var iterations	  = fps * duration;                      // 120 frames
var startPosition = 0;                                   // left end of the screen
var endPosition	  = window.innerWidth - box.clientWidth; // right end of the screen
var distance	  = endPosition - startPosition;         // total distance
var posIncrement  = distance / iterations;               // change per frame
var position	  = startPosition;                       // current position

function move() {
  position += posIncrement;              // increase position
  if (position >= endPosition) {         // check if reached endPosition
    clearInterval(handler);              // if so, stop interval
    box.style.left = endPosition + "px"; // jump to endPosition
    return;                              // exit function
  }
  box.style.left = position + "px";      // move to the new position
}

var handler = setInterval(move, 1000/fps); // run move() every 16~ millisecond
body {
	background: gainsboro;
}
#box {
	width: 100px;
	height: 100px;
	background: white;
	box-shadow: 1px 1px 1px rgba(0,0,0,.2);
	position: absolute;
	left: 0;
}
<div id="box"></div>

Теперь давайте добавим замедление.Мы начинаем с простого, используя linear (без ослабления).Это приведет к той же анимации, что и выше, но подход другой.На этот раз мы не будем напрямую изменять переменную позиции.Мы будем изменять время.

function linear(time, begin, change, duration) {
    return change * (time / duration) + start;
}

Сначала поговорим о параметрах.

  • time: прошедшее время
  • begin: начальное значение свойства (ширина, слева, поле, прозрачность и т. д.)
  • change: смещение, (конечное значение - начальное значение)
  • duration: общее времяанимация займет

time и duration имеют прямое отношение.Если у вас 2-секундная анимация, вы увеличиваете time и передаете ее в функцию замедления linear.Функция вернет позицию, которая указывает, что бокс должен быть в этой позиции в данный момент времени.

Скажем, я перемещаю бокс с 0 на 100 через 2 секунды.Если бы я хотел получить положение поля, скажем, в 700 миллисекундах, я бы вызвал функцию linear следующим образом:

linear(0.7, 0, 100, 2);

, которая вернула бы 35.По прошествии 700 миллисекунд после запуска анимации позиция блока будет на уровне 35 пикселей.Давайте посмотрим на это в действии.

JSFiddle

var box = document.getElementById("box");

var fps           = 60;
var duration	  = 2;                                   // seconds
var iterations	  = fps * duration;                      // 120 frames
var startPosition = 0;                                   // left end of the screen
var endPosition	  = window.innerWidth - box.clientWidth; // right end of the screen
var distance      = endPosition - startPosition;         // total distance
var timeIncrement = duration / iterations;
var position      = 0;
var time          = 0;

function move() {
	time += timeIncrement;
	position = linear(time, startPosition, distance, duration);
	if (position >= endPosition) {
		clearInterval(handler);
		box.style.left = endPosition + "px";
		return;
	}
	box.style.left = position + "px";
}

var handler = setInterval(move, 1000/fps);

function linear(time, begin, change, duration) {
	return change * (time / duration) + begin;
}
body {
	background: gainsboro;
}
#box {
	width: 100px;
	height: 100px;
	background: white;
	box-shadow: 1px 1px 1px rgba(0,0,0,.2);
	position: absolute;
	left: 0;
}
<div id="box"></div>

Часть, на которую нужно обратить внимание в этом коде:

var timeIncrement = duration / iterations;
var time = 0;

function move() {
    time += timeIncrement;
    position = linear(time, startPosition, distance, duration);
    // ...

В первой анимации мы непосредственноизменил переменную позиции.Нам нужно было постоянное значение приращения позиции.То, как мы рассчитали это posIncrement = distance / iterations.С помощью easing мы больше не изменяем переменную позиции, а переменную времени.Поэтому нам нужно значение приращения времени.Мы рассчитываем это так же, как и приращение позиции, только на этот раз мы делим duration на iterations.Мы увеличиваем время с приращением времени и передаем время функции замедления, и функция замедления возвращает нам следующую позицию, которую должен занять бокс.

total distance / iterations (frames) = position change per frame
total duration / iterations (frames) = time change per frame

Вот некоторый график для глаза.

Ease function graph


И, наконец, пример easeInOutQuad.

JSFiddle

var box = document.getElementById("box");

var fps           = 60;
var duration      = 2;                                   // seconds
var iterations    = fps * duration;                      // 120 frames
var startPosition = 0;                                   // left end of the screen
var endPosition   = window.innerWidth - box.clientWidth; // right end of the screen
var distance      = endPosition - startPosition;         // total distance
var timeIncrement = duration / iterations;
var time          = 0;
var position      = 0;

function move() {
  time += timeIncrement;
  position = easeInOutQuad(time, startPosition, distance, duration);
  if (position >= endPosition) {
    clearInterval(handler);
    box.style.left = endPosition + "px";
    return;
  }
  box.style.left = position + "px";
}

var handler = setInterval(move, 1000 / fps);

function easeInOutQuad(t, b, c, d) {
  if ((t /= d / 2) < 1) {
    return c / 2 * t * t + b;
  } else {
    return -c / 2 * ((--t) * (t - 2) - 1) + b;
  }
}
body {
	background: gainsboro;
}
#box {
	width: 100px;
	height: 100px;
	background: white;
	box-shadow: 1px 1px 1px rgba(0,0,0,.2);
	position: absolute;
	left: 0;
}
<div id="box"></div>
0 голосов
/ 27 июня 2014

Думает, что в реальной жизни не работают как компьютеры. Думает, что не включай и не выключай и не выключай сразу, как будто ты не можешь притворяться, что Твоя девушка будет любить тебя немедленно Поэтому ученые и компьютерщики (которые ничего не знают о Вашей девушке) изобрели функции ослабления. Это все равно, что применять или переключать такие вещи, как анимации, не сразу. Поэтому, если вы перемещаете прямоугольник слева направо, он движется не как робот: «начинайте, двигайтесь с постоянной скоростью и немедленно останавливайтесь», но «запускайте, постоянно увеличивайте скорость, постоянно уменьшайте скорость и, наконец, останавливайтесь». Таким образом, смягчение подобно тому, как некоторые анимации, функции, объекты или вещи ведут себя как вещи в реальной жизни. Каждый эффект легкости определяет поведение, поэтому у нас есть «упругие», «прыгающие» эффекты легкости и так далее.

0 голосов
/ 29 ноября 2011

Это свойство (размер, форма, местоположение) перехода из одного состояния в другое.

Вот некоторые аккуратные маленькие графики, описывающие функции замедления, предлагаемые jquery ui.

http://jqueryui.com/demos/effect/easing.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...