什么是宽松功能?

时间:2011-11-29 19:56:12

标签: jquery silverlight flex animation dojo

动画上下文中的缓动功能是什么意思。似乎dojo,jquery,silverlight,flex和其他UI系统都具有缓和功能的概念。我找不到缓和功能的好解释?任何人都可以解释缓和功能的概念,或指出它们的一个很好的解释,我感兴趣的概念不在框架的具体细节中?

缓和是严格用于位置还是一般的,可以应用于对象的任何属性?

6 个答案:

答案 0 :(得分:100)

缓动函数通常是一个函数,它描述给定完整性百分比的属性值。不同的框架使用略有不同的变体,但是一旦你理解了这个概念就很容易掌握,但最好看几个例子。

首先让我们看一下我们所有宽松功能都将遵守的界面。

我们的宽松函数将有几个参数:

  • percentComplete:(0.01.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,这是我们指定的startend值之间实际距离的四分之一。

如果我们要绘制这个函数的图形,它将看起来像这样:

Quad-Ease-In

现在让我们看一下基本的缓解:

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

这基本上与#34;相反"缓慢加速曲线。它快速开始,然后减速到其结束值:

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

此功能将开始缓慢并缓慢结束,在中间达到最大速度。

你可以使用一堆缓动/插值:线性,四次,立方,夸脱,Quint,正弦。还有一些特殊的缓和功能,如Bounce和elastic,它们都有自己的功能。

例如,弹性容易:

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

也许其他人可以解释插值背后的实际数学部分,因为说实话,我不是数学专家。但这是宽松功能本身的基本原则。

启动补间/动画时,动画引擎会记住所需的开始值和结束值。然后每次更新时,其数字都会显示已经过了多长时间。它使用值调用提供的缓动函数来计算属性应设置的值。只要所有缓动函数都实现相同的签名,就可以轻松地将它们换出,并且核心动画引擎不必知道差异。 (这使得关注点分离得很好。)

您会注意到我已明确避免谈论xy职位,因为宽松政策并未与职位具体相关SE 。缓动函数仅定义起始值和结束值之间的过渡。这些可以是x坐标,或颜色,或对象的透明度。

事实上,理论上,您可以应用不同的缓动函数来插入不同的属性。希望这有助于阐明基本理念。

这里有一个真正的cool example(使用略微不同的签名,但原则相同),以了解宽松与位置的关系。


修改

这是一个小jsFiddle我在一起演示了javascript中的一些基本用法。请注意,top属性是使用bounce进行补间的,而left属性是使用四元组补间的。使用滑块模拟渲染循环。

由于easing对象中的所有函数都具有相同的签名,因此您可以互相交换它们中的任何一个。现在大多数这些东西都是硬编码的(比如开始和结束值,使用的补间函数和动画的长度),但是在动画助手的真实示例中,你会希望通过在以下属性中:

  • 要更改的属性
  • 起始值(或左侧undefined然后使用其当前值)
  • 结束价值
  • 动画的长度
  • 您要使用的补间功能的引用。

动画引擎会在动画持续时间内跟踪这些设置,并且在每个更新周期中,它将使用补间参数来计算属性的新值。

答案 1 :(得分:11)

缓动函数是一种控制动画速度以产生所需效果(弹跳,放大和慢速等)的算法。

查看MSDN has to say about them了解更多细节。

答案 2 :(得分:2)

即使已经接受了答案,我也想回答这个旧问题。 32bitkid做出了必要的解释。我要添加的是基本的实际实现,因为我找不到一个(我还发布了一个question)。

例如,采用这种简单的线性动画。我怀疑它需要任何解释,因为代码是不言自明的。我们计算一个不随时间变化的恒定增量值,并且在每次迭代时,我们增加盒子的位置。我们直接修改位置变量,然后将其应用到框中。

JSFiddle

&#13;
&#13;
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
&#13;
body {
	background: gainsboro;
}
#box {
	width: 100px;
	height: 100px;
	background: white;
	box-shadow: 1px 1px 1px rgba(0,0,0,.2);
	position: absolute;
	left: 0;
}
&#13;
<div id="box"></div>
&#13;
&#13;
&#13;

现在,让我们添加缓和。我们通过使用linear(无缓和)开始简单。它会产生上面相同的动画,但方法不同。这一次,我们不会直接修改位置变量。我们要修改的是时间。

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

首先,让我们谈谈这些参数。

  • time:已用时间
  • begin:属性的初始值(宽度,左边距,边距,不透明度等)
  • change:排量,(结束值 - 起始值)
  • duration:动画的总时间

timeduration直接相关。如果您有2秒动画,则增加time并将其传递给缓动函数linear。该函数将返回一个位置,指示该框应该在给定时间处于该位置。

让我们说我在2秒钟内将一个盒子从0移动到100。如果我想获得盒子的位置,比如700毫秒,我可以通过以下方式调用linear函数:

linear(0.7, 0, 100, 2);

将返回35。动画开始后700毫秒,方框的位置将为35px。让我们看看这一点。

JSFiddle

&#13;
&#13;
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;
}
&#13;
body {
	background: gainsboro;
}
#box {
	width: 100px;
	height: 100px;
	background: white;
	box-shadow: 1px 1px 1px rgba(0,0,0,.2);
	position: absolute;
	left: 0;
}
&#13;
<div id="box"></div>
&#13;
&#13;
&#13;

此代码中需要注意的部分是:

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

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

在第一个动画中,我们直接修改了位置变量。我们需要一个恒定的位置增量值。我们计算的方式是posIncrement = distance / iterations。通过缓动,我们不再修改位置变量,而是修改时间变量。所以我们需要一个时间增量值。我们以与位置增量相同的方式计算它,只是这次我们将duration除以iterations。我们用时间增量增加时间并将时间传递给缓动函数,缓动函数返回框应占据的下一个位置。

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

以下是一些眼睛的图表。

Ease function graph

最后,一个easeInOutQuad示例。

JSFiddle

&#13;
&#13;
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;
  }
}
&#13;
body {
	background: gainsboro;
}
#box {
	width: 100px;
	height: 100px;
	background: white;
	box-shadow: 1px 1px 1px rgba(0,0,0,.2);
	position: absolute;
	left: 0;
}
&#13;
<div id="box"></div>
&#13;
&#13;
&#13;

答案 3 :(得分:0)

这是从一个州到另一个州的财产(大小,形状,位置)过渡。

以下是一些描述jquery ui提供的缓动函数的简洁小图。

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

答案 4 :(得分:0)

tl;dr 基本植入缓动功能,假设标准化的 0-1 范围有力量支持:

t = 归一化输入值,所以从 0 到 1。

s = 强度,其中 1 是线性的,它越高,缓动效果越强。

# ease-in
result = t**s 

# ease-out
s = int(s)*2 + 1
result = s*((t-1)**s + 1)

# ease-inOut
result = t**s /(t**s + (1-t)**s)

答案 5 :(得分:-2)

在现实生活中思考不像电脑一样工作。认为不要立即从开关切换到关闭再开启,就像你不能假装你的女朋友会立刻爱你一样。 因此,科学家和计算机人员(对你的女朋友一无所知)发明了缓和功能。这就像是不能立即应用或切换动画之类的东西。因此,如果你从左到右移动一个矩形,它就不像机器人一样移动:“开始,以恒定速度移动并立即停止”,但是“开始,不断提高速度,不断降低速度并最终停止”。 因此,放松就像让一些动画,功能,对象或东西在现实生活中表现得像。 每个缓和效果都定义了一种行为,这就是为什么我们有“弹性”,“弹跳”缓和效果等等。