jQuery 什么是缓动函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8316882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is an easing function?
提问by ams
What is meant by easing function in the context of animation. It seems that dojo, jquery, silverlight, flex and other UI systems have the notion of easing function. I could not locate a good explanation of easing functions? Can anyone explain the concept of easing functions, or point a good explanation of them, I am interested in the concept not in the specific details of a framework?
动画上下文中的缓动函数是什么意思。似乎dojo、jquery、silverlight、flex等UI系统都有缓动功能的概念。我找不到缓动函数的一个很好的解释?任何人都可以解释缓动函数的概念,或者对它们进行很好的解释,我对这个概念感兴趣而不是框架的具体细节?
Is easing strictly used for location or is it general and can be applied to any property of an object?
缓动是严格用于位置还是通用并且可以应用于对象的任何属性?
回答by J. Holmes
An easing function is usually a function that describes the value of a property given a percentage of completeness. Different frameworks use slightly different variations, but the concept is easy to grasp once you get the idea, but it's probably best to look a few examples.
缓动函数通常是描述给定完整性百分比的属性值的函数。不同的框架使用略有不同的变体,但是一旦你有了这个想法,这个概念就很容易掌握,但最好看几个例子。
First lets look at the interface that all our easing functions will abide by.
首先让我们看一下我们所有缓动函数都将遵循的接口。
Our easing functions will take several arguments:
我们的缓动函数将采用几个参数:
- percentComplete: (
0.0
to1.0
). - elaspedTime: The number of milliseconds the animation has been running
- startValue: the value to start at (or the value when the percent complete is 0%)
- endValue: the value to end at (or the value when the percent complete is 100%)
- totalDuration: The total desired length of the animation in milliseconds
- 百分比完成:(
0.0
到1.0
)。 - elaspedTime:动画已经运行的毫秒数
- startValue:开始的值(或完成百分比为 0% 时的值)
- endValue:结束的值(或完成百分比为 100% 时的值)
- totalDuration:动画所需的总长度(以毫秒为单位)
And will return a number which represents the value the property should be set to.
并将返回一个数字,该数字表示该属性应设置为的值。
Note: this is the same signature that jQuery uses for its easing functions, which I'll be borrowing for examples.
注意:这与 jQuery 用于其缓动函数的签名相同,我将借用它作为示例。
The easiest to understand is a linear ease:
最容易理解的是线性缓动:
var linear = function(percent,elapsed,start,end,total) {
return start+(end-start)*percent;
}
And now to put this to use:
现在要使用它:
Lets say we had an animation that was going to go for 1000 milliseconds and was supposed to start at 0 and end at 50. Passing those values into our easing function should tell us what the actual value should be:
假设我们有一个动画将持续 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
This is a pretty straight forward (no pun intended) tween. It is a simple linear interpolation. If you were to graph value vs time, it would be a straight line:
这是一个非常直接的(没有双关语意)补间。这是一个简单的线性插值。如果您要绘制价值与时间的关系图,它将是一条直线:
Lets take a look at a bit more complicated easing function, a quadratic ease in:
让我们来看看更复杂的缓动函数,二次缓动:
var easeInQuad = function (x, t, b, c, d) {
return c*(t/=d)*t + b;
}
And lets look at the same results, using the same inputs as before:
让我们看看相同的结果,使用与之前相同的输入:
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
Notice the values are very different than our linear ease. It starts out very slow, then accelerates to its ending point. At 50% completion of the animation it has only made it to a value of 12.5, which is one quarter of the actual distance between the start
and end
values we have specified.
请注意,这些值与我们的线性缓动非常不同。它开始非常缓慢,然后加速到终点。在动画完成 50% 时,它的值仅达到 12.5,这是我们指定的start
和end
值之间实际距离的四分之一。
If we were to graph this function it would look something like this:
如果我们要绘制这个函数,它看起来像这样:
Now lets take a look at a basic ease-out:
现在让我们看一下基本的缓出:
var easeOutQuad = function (x, t, b, c, d) {
return -c *(t/=d)*(t-2) + b;
};
This essentially does the "opposite" acceleration curve of an ease in. It starts out fast and then decelerates to its ending value:
这实质上是执行缓入的“相反”加速曲线。它开始快速,然后减速到其结束值:
And then there are functions that ease both in and 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;
};
This function will start out slow and end slow, reaching its maximum velocity in the middle.
此功能将开始缓慢结束,在中间达到其最大速度。
There are a bunch of easing/interpolations that you can use: Linear, Quadradic, Cubic, Quart, Quint, Sine. And there are specialty easing functions like Bounce and elastic, which have their own.
您可以使用许多缓动/插值:线性、二次、三次、四分、五分、正弦。还有一些特殊的缓动功能,比如 Bounce 和 elastic,它们都有自己的功能。
For example, an elastic ease in:
例如,弹性缓和:
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;
},
Perhaps somebody else can explain the actual math part behind the interpolation, because honestly I'm not a math wiz. But that's the basic principle of the easing functions themselves.
也许其他人可以解释插值背后的实际数学部分,因为老实说我不是数学奇才。但这是缓动函数本身的基本原则。
When you start a tween/animation, the animation engine remembers the start and end values you want. Then each time it updates, its figures out of how much time has passed. It call the supplied easing function with the values to figure out the value the property should be set to. As long as all of the easing functions implement the same signature, they can be swapped out with ease, and the core animation engine doesn't have to know difference. (Which makes for an excellent separation of concerns).
当您开始补间/动画时,动画引擎会记住您想要的开始和结束值。然后每次更新时,它都会计算出已经过去了多少时间。它使用值调用提供的缓动函数来确定属性应该设置的值。只要所有缓动函数都实现相同的签名,它们就可以轻松换出,核心动画引擎不必知道区别。(这可以很好地分离关注点)。
You'll notice that I've avoided talking about x
and y
positions explicitly, because easing doesn't have anything specifically to do with position per se. An easing function just defines a transition between a start and end values. Those could be x
coordinates, or a color, or the transparency of an object.
您会注意到,我已经避免明确谈论x
和y
定位,因为缓动本身与定位没有任何特别关系。缓动函数仅定义开始值和结束值之间的转换。这些可以是x
坐标、颜色或对象的透明度。
And in fact, in theory, you could apply different easing function to interpolate for different properties. Hopefully this helps shed some light on the basic idea.
事实上,理论上,您可以应用不同的缓动函数来对不同的属性进行插值。希望这有助于阐明基本思想。
And here is a really cool example(that uses a slightly different signature, but is the same principle) to play with to get the idea of how easing relates to position.
这是一个非常酷的示例(使用稍微不同的签名,但原理相同)来了解缓动与位置的关系。
Edit
编辑
Here is a little jsFiddleI threw together to demonstrate some of the basic usages in javascript. Notice that the top
property is tweened using bounce, and the left
property is tweened using a quad. Use the slider to simulate the render loop.
这是我拼凑的一个小jsFiddle来演示 javascript 中的一些基本用法。请注意,top
属性是使用反弹补间的,而left
属性是使用四边形补间的。使用滑块模拟渲染循环。
Since all the functions in the easing
object have the same signature, you can swap any of them out for each other. Right now most of these things are all hard-coded (things like start and end values, the tween functions that are used and the length of the animation), but in a real-world example of a animation helper, you would want to pass in the following properties:
由于easing
对象中的所有函数都具有相同的签名,因此您可以将它们中的任何一个相互交换。现在大多数这些东西都是硬编码的(比如开始和结束值,使用的补间函数和动画的长度),但是在动画助手的真实示例中,您可能希望通过在以下属性中:
- The property to be changed
- The start value (or if left
undefined
then use its current value) - The end value
- The length the animation should be
- The reference to the tweening function you want to use.
- 要更改的属性
- 起始值(或者如果留下
undefined
则使用其当前值) - 最终价值
- 动画的长度应该是
- 对您要使用的补间函数的引用。
The animation engine would keep track of these settings for the duration of the animation and during every update cycle, it would use the tweening argument to calculate the properties new value.
动画引擎会在动画持续时间内跟踪这些设置,并且在每个更新周期内,它会使用补间参数来计算属性的新值。
回答by Justin Niessner
An easing function is an algorithm that controls the speed of an animation to give a desired effect (bouncing, zoom in and slow, etc.).
缓动函数是一种算法,它控制动画的速度以提供所需的效果(弹跳、放大和慢速等)。
Check out what MSDN has to say about themfor a little more detail.
查看MSDN 对它们的评价,了解更多细节。
回答by akinuri
I'd like to post my answer to this old question even though it has an accepted answer. 32bitkidhas made the necessary explanation. What I'll add is the basic practical implementation, because I couldn't find one (which I also posted a questionabout it).
我想发布我对这个老问题的回答,即使它有一个公认的答案。32bitkid已经做出了必要的解释。我要添加的是基本的实际实现,因为我找不到(我也发布了一个关于它的问题)。
Take this simple linear animation, for example. I doubt it requires any explanations since the code is self-explanatory. We calculate a constant increment value which doesn't change over time and at each iteration, we increase the position of the box. We're modifying the position variable directly and then applying it on the box.
以这个简单的线性动画为例。我怀疑它需要任何解释,因为代码是不言自明的。我们计算一个不随时间变化的恒定增量值,并且在每次迭代中,我们增加框的位置。我们直接修改位置变量,然后将其应用到框上。
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>
Now, let's add easing. We start simple by using linear
(no-easing). It'll result the same animation above, but the approach is different. This time, we won't be modifying the position variable directly. What we'll be modifying is time.
现在,让我们添加缓动。我们从使用linear
(no-easing) 开始。它会产生与上面相同的动画,但方法不同。这一次,我们不会直接修改位置变量。我们要修改的是时间。
function linear(time, begin, change, duration) {
return change * (time / duration) + start;
}
First, let's talk about the parameters.
首先,让我们谈谈参数。
time
: the elapsed timebegin
: initial value of a property (width, left, margin, opacity, etc.)change
: displacement, (end value - start value)duration
: total time the animation will take
time
: 经过的时间begin
:属性的初始值(宽度、左、边距、不透明度等)change
:位移,(结束值 - 开始值)duration
: 动画所需的总时间
time
and duration
are directly related. If you have a 2 second animation, you increase time
and pass it to the easing function linear
. The function will return a position which indicates that the box should be at that position at the given time.
time
并且duration
有直接关系。如果你有一个 2 秒的动画,你增加time
并将它传递给 easing 函数linear
。该函数将返回一个位置,该位置指示框在给定时间应位于该位置。
Let's say I'm moving a box from 0 to 100 in 2 seconds. If I want to get the position of the box, say at the 700 millisecond, I'd call the linear
function in the following way:
假设我在 2 秒内将一个盒子从 0 移动到 100。如果我想获得盒子的位置,比如在 700 毫秒,我会linear
用以下方式调用该函数:
linear(0.7, 0, 100, 2);
which would return 35
. 700 milliseconds after the animation starts, box's position will be at 35px. Let's see this in action.
这将返回35
。动画开始后 700 毫秒,框的位置将在 35px。让我们看看它的实际效果。
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>
The parth that needs attention in this code is:
这段代码中需要注意的部分是:
var timeIncrement = duration / iterations;
var time = 0;
function move() {
time += timeIncrement;
position = linear(time, startPosition, distance, duration);
// ...
In the first animation, we directly modified the position variable. We needed a constant position increment value. The way we calculated that is posIncrement = distance / iterations
. With easing, we no longer modify the position variable, but the time variable. So we need a time increment value. We calculate it the same way we did position increment, only this time we divide duration
by iterations
. We increase the time with time increment and pass the time to easing function, and easing function returns us the next position the box should occupy.
在第一个动画中,我们直接修改了位置变量。我们需要一个恒定的位置增量值。我们计算的方式是posIncrement = distance / iterations
。通过缓动,我们不再修改位置变量,而是修改时间变量。所以我们需要一个时间增量值。我们计算的话,我们确实位置增量,只是这次我们把同样的方式duration
通过iterations
。我们随着时间的增加增加时间并将时间传递给缓动函数,缓动函数返回给我们框应该占据的下一个位置。
total distance / iterations (frames) = position change per frame
total duration / iterations (frames) = time change per frame
Here are some graph for the eye.
这是眼睛的一些图表。
And lastly, an easeInOutQuad example.
最后,一个easeInOutQuad 示例。
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>
回答by Chris Lacasse
It is a property (size, shape, location) transition from one state to another.
它是从一种状态到另一种状态的属性(大小、形状、位置)转换。
Here are some neat little graphs describing the easing functions offered by jquery ui.
这里有一些简洁的小图,描述了 jquery ui 提供的缓动功能。