tween.js user guide
tween.js用户指南
1.What is a tween? How do they work? Why do you want to use them?
一、什么是tween?它如何工作?为何你需要使用它?
tween允许你以缓和的方式改变一个对象属性的值。你只要告诉它要改变什么属性,停止改变时属性的终值该是什么,以及这一变化要经历多少时间,然后tweening的引擎就会从变化开始到变化结束关注该属性当前值。例如,假设你有一个有x和y坐标的位置对象:
var position = { x:100, y:0 }
如果你想把x值从100变到200,你只要:
// 首先为这一position对象创建一个tween
var tween =newTWEEN.Tween(position);
//
告诉tween我们想把x属性在1000毫秒内改变
tween.to({ x:200 }, 1000);
事实上这并不会做任何事情,这个tween虽然被创建了,但未被激活,你需要启动它:
tween.start();
最后,为了尽可能地让运动平缓,你应该在动画的同一个主循环内使用TWEEN.update。通常这看起来像:
animate();
functionanimate() {
requestAnimationFrame(animate);
// [...]
TWEEN.update();
// [...]
}
这会让引擎关注每一帧激活的position;在一秒后(也就是1000毫秒,tween变量建立时传入的参数),position.x会变成200。
如果你想看到position的数值变化的话,你可以使用onUpdate函数把x打印到控制台:
tween.onUpdate(function() {
console.log(this.x);
});
这个函数会在每一次tween更新时被调用;它发生多少次取决于许多因素——比如你的计算机的运行速度和工作状态等…
现在我们只是把属性值打印到控制台,但如果你把Tween用于其它场景,比如用来改变一个three.js对象的位置:
var tween =newTWEEN.Tween(cube.position)
.to({ x:100, y:100, z:100 }, 10000)
.start();
animate();
functionanimate() {
requestAnimationFrame(animate);
TWEEN.update();
threeRenderer.render(scene, camera);
}
这种情况下,因为three.js的渲染器会在渲染前读取对象的位置,因此你就没必要清楚的调用一个onUpdate函数啦!!
可能你已经在上面的代码里发现了不一样的内容:链式调用!!因为每个tween的方法返回了tween实例本身,因此你可以把下述代码:
var tween =newTWEEN.Tween(position);
tween.to({ x:200 }, 1000);
tween.start();
写成
var tween =newTWEEN.Tween(position)
.to({ x:200 }, 1000)
.start();
你会在提供的例子中看到许多链式调用tween方法的地方,因此有必要先去熟悉它。看看04-simplest这个例子吧!
2.Animating with
tween.js
二、使用tween.js来生成动画!!
tween.js是不会自动工作的,因此必须要调用update方法。推荐的作法是把它放进动画函数的主循环内,最好是使用requestAnimationFrame来获得最好的图形渲染效果。看起来像这样:
animate();
functionanimate() {
requestAnimationFrame(animate);
// [...]
TWEEN.update();
// [...]
}
如果update没有传入参数,它会使用当前时间来计算从上次运行到现在过了多久,也就是会立即调用。
而如果你给update传入了参数,例如:
TWEEN.update(100);
这意味着 "update with
time = 100 milliseconds"。你可以使用这个来确保你代码中所有基于时间的函数总是使用相同的时间值。比如你有一个player并且想同步地运行tween的话,你的animate代码可能会看起来像:
var currentTime =
player.currentTime;
TWEEN.update(currentTime);
可以查看github中的test.js来了解如何给TWEEN.update()传入不同的值来模仿经过的时间。
3.Controlling a
tween
三、控制一个tween的动画
strat and stop
我们已经知道Tween.start是启动一个tween,除此之外还有许多其他用来控制一个tween的方法。可能其中最重要的一个就是与start相对的方法:stop。如果想要取消一个tween,可以直接让一个tween调用stop方法:
tween.stop();
停止一个未被启动的、或是已经停止的tween是无效的,也不会抛出错误。
start方法也可以接收一个参数。如果传入了参数,那么tween不会启动,直到传入的时间才启动。否则,它就会尽可能快地启动(也就是第一次调用TWEEN.update的时候)
update
每一个tween实例也是有update方法的——而这实际上是通过TWEEN.update来调用的。一般不会直接使用这个方法,但如果你想做出疯狂的hack的话,这是很有用的。
chain
如果你把多个不同的tween排列起来的话(也就是一个tween结束之后另一个tween立即开始),事情将会变的很有趣。我们把这叫做chaning
tweens,而这是通过chain方法来串起来的。因此,如果想让tweenB接在tweenA之后开始的话,你可以:
tweenA.chain(tweenB);
或者,如果你想使用一个无限的chain,可以:
tweenA.chain(tweenB);
tweenB.chain(tweenA);
github中给出的00_Hello
world例子正是使用了无限的chain.
在另外一些情况下,你可能会想紧接着一个tween之后同时进行两个tween的动画:
tweenA.chain(tweenB,tweenC);
repeat
如果你想不停地使用一个tween的话,你可以让它chain它自己,但更好的方式是使用repeat方法。它接收一个参数,表示重复的次数:
tween.repeat(10); // repeats 10 times and stops
tween.repeat(Infinity); // repeats forever
yoyo
这个函数只会在使用repeat时有用。它会让tween的行为像个yoyo(悠悠球),也就是说,在下一次动画开始时,它的属性是慢慢从终值拉回到初始值的,而不是简单的从头开始tweens队列。
delay
更复杂的动画管理可能要在一个tween启动前延迟一定的时间。这样可以使用delay方法:
tween.delay(1000);
tween.start();
4.Controlling
all tweens
四、控制所有tween的动画
下列的方法是在TWEEN全局对象中的,而且你通常不会用到其中的大部分方法,除了update.
这些方法通常都该是内部的,但把它暴露出来是为了给你机会去尝试一些有趣的效果。
TWEEN.update(time)
前面已经说过的,这个方法用来启动所有tween的动画。如果未指定time,它将使用当前时间。
TWEEN.getAlland
TWEEN.removeAll
分别用来获得所有正在运行的tween的数组以及移除它们。
TWEEN.add(item) and TWEEN.remove(tween)
分别用来在当前活动的tween队列中增加一个tween或是移除指定的tween.
5.Changing the
easing function (AKA make it bouncy)
五、改变缓动方式
Tween.js会在起始于终止值间的插值表现为线性变化,也就是说变化量会与经过的时间成正比。这会使效果很容易预料,但也会过分无趣。不用担心!这一行为能被轻松的改变,只要你使用了easing方法,比如:
tween.easing(TWEEN.Easing.Quadratic.In);
它的效果是,tween的速度是慢慢增加的,而不是线性的,并且在图示上会表现为二次函数形式。
Available easing
functions: TWEEN.Easing可用的Easing函数
tween.js提供了几个缓动函数,它们按照效果被分为以下几组:Linear, Quadratic, Cubic,
Quartic, Quintic, Sinusoidal, Exponential, Circular, Elastic, Back 和 Bounce,同时它们有三种缓动类型:In,Out,InOut。
考虑到除非你非常熟悉这几个词的概念,不然你可能不太理解,github上又给出了一个Graphs的例子查看效果。它把所有的缓动曲线放在一个页面里,因此你能一眼就看出它们的区别来。
这些缓动函数的起源:these functions
are derived from the original set of equations that Robert Penner graciously
made available as free software a few years ago, but have been optimised to
play nicely with JavaScript.
使用自定义缓动函数
你不仅能使用现有的函数,也能自己写个你觉得更适用的,只要它符合一定的约定:
·它需要接受一个参数
o
<![endif]>k:表示缓动过程,或者说这个tween已经经历了多久。允许值为[0,1]。
· 它必须返回一个基于输入参数的值。
缓动函数会在tween每次update时调用。然后得到的结果会被用于初始值和它与终止值的差值(deltas),大概类似于下面的模拟代码:
easedElapsed
= easing(k);
for each property:
newPropertyValue =
initialPropertyValue + propertyDelta * easedElapsed;
deltas会在start()之后开始计算。
所以假设你想使用自定义的缓动函数来缓动属性值,并且是用Math.floor来输出结果,也就是只有整数部分才会被输出,这时就会表现有点些像台阶函数:
functiontenStepEasing(k)
{
returnMath.floor(k *10) /10;
}
然后你能在一个tween的easing方法中调用它,正如我们之前见过的:
tween.easing(tenStepEasing);
查看graphs for custom easing function例子
6.Callbacks
六、回调函数
tween另一个强大的特性是可以在每次tween的生命周期的某一时刻里使用自定义的回调函数。
比如,假定你想去给一个对象指定动画,但它的属性却不能直接读写,那么你就要使用一个setter了。你可以使用一个onUpdate回调函数来读取更新了的属性值并且手动调用setters:
var trickyObjTween =newTWEEN.Tween({
propertyA: trickyObj.getPropertyA(),
propertyB: trickyObj.getPropertyB()
})
.to({ propertyA:100, propertyB:200 })
.onUpdate(function() {
this.setA( this.propertyA );
this.setB( this.propertyB );
});
或者想像你要在tween开始时放个声音,这样你就能用一个onStart回调函数:
var tween =newTWEEN.Tween(obj)
.to({ x:100 })
.onStart(function() {
sound.play();
});
每个回调函数的作用域都是在这个被tweened的对象内——这个例子里,是obj
onStart
在tween开始之前,也就是在deltas计算之前。一个tween只会执行一次,也就是说即使被repeat()重复了也不会多次执行。
这一般是用来同步执行其他的事件,或者是触发一些你想要tween发生时要做的动作。
被tweened的对象是作为第一个参数,它也能通过this来获得引用。
onStop
当一个tween被stop()方法停止时执行的回调函数,而不是等它自己动画自然结束时,或者在任意一个chained了的tween被stopped时。
被tweened的对象是作为第一个参数,它也能通过this来获得引用。
onUpdate
tween每次更新时执行,在属性值被更新之后。
被tweened的对象能通过this来引用,而传入的第一个参数则是这个tween的进程,一个0~1的值。在将来版本可能会做出更改,因此你不能相信这一值。
onComplete
当一个tween正常结束时执行的回调函数。
被tweened的对象是作为第一个参数,它也能通过this来获得引用。
7.Advanced
tweening
七、进阶的缓间动画
使用当前属性值的相关值
当使用to方法时,你也能使用与当前值相关的值,Tween.js会读取当前的属性值然后根据相关值计算终值。但需要使用引号不然就会被改成绝对值了。
让我们看看如何使用:
//
This will make the `x` property be 100, always
var absoluteTween =newTWEEN.Tween(absoluteObj).to({ x:100 });
//
Suppose absoluteObj.x is 0 now
absoluteTween.start(); // Makes x go to 100
//
Suppose absoluteObj.x is -100 now
absoluteTween.start(); // Makes x go to 100
//
In contrast...
//
This will make the `x` property be 100 units more,
// relative to the actual value when it starts
var relativeTween =newTWEEN.Tween(relativeObj).to({ x:"+100"
});
//
Suppose relativeObj.x is 0 now
relativeTween.start(); // Makes x go to 0 +100 = 100
//
Suppose relativeObj.x is -100 now
relativeTween.start(); // Makes x go to -100 +100 = 0
看看github上这个例子
to的参数为一个数组时
除了把tween动画的目标属性设置为一个绝对或相对值,你也可以为tween动画设置一系列的目标值。要实现这一目的,你只要在to()函数中为属性指定一个值数组就可以了。例如:
var tween =newTWEEN.Tween(relativeObj).to({
x: [0, -100, 100] });
它会让x从初始值到0,-100和100.
插入值的计算方式是:
·首先tween的进程(tween
progess)像正常一样进行
·进程(从0到1)被用作插值函数的输入
·基于这一进程和数组中的值,来生成一个插值。
例如,当这一tween刚开始时(process为0),插值函数会返回数组中的第一个值。当tween进行到一半时,插值函数会返回一个接近数组中间的值的值,然后当tween结束时(process为0),插值函数会返回数组中最后的值。
看看github上的这个例子
8.Getting the
best performance
八、获得最佳表现
当使用Tween.js时,你可以使用一定的方式来提高你代码的性能(或者说当你在web中使用动画时,通常来说都是有效的)。
使用高性能的CSS
当你想给页面中的一个元素的位置做动画时,最简单的方案是对top和left属性做动画,就像这样:
var element =document.getElementById('myElement');
var tween =newTWEEN.Tween({
top:0, left:0 })
.to({ top:100, left:100 }, 1000)
.onUpdate(function() {
element.style.top=this.top+'px';
element.style.left=this.left+'px';
});
但这却是非常低效的!!!!因为更改这些属性会在每次tween更新时让浏览器重新计算布局,而是是很大的消费。相反,如果使用transform的话,这并不会让浏览器重新计算布局而且还允许硬件加速,像这样:
var element =document.getElementById('myElement');
var tween =newTWEEN.Tween({
top:0, left:0 })
.to({ top:100, left:100 }, 1000)
.onUpdate(function() {
element.style.transform
='translate('+this.left+'px, '+this.top+'px);';
});
但是!如果你的动画只是那么简单的话,那你还不如只用简单的CSS动画或者是transitions,那样子浏览器还能尽可能的做出优化。Tween.js最有用的地方是当你的动画涉及到复杂的管理,比如你要同步执行多个tween,或者是当一个tween结束后执行其他的tween,或者是循环执行一定次数等…
对GC机制友好些!!
如果你使用onUpdate回调,你要小心放进你要的内容。因为这个函数会每秒调用多次,所以如果你在每次tween更新时做出比较耗费资源的操作的话,你可能会阻塞主线程而导致jank,或者——如果你的操作涉及到内容分配,那么你会调用GC太多次,这也可能会导致jank。因此,一定不要做出这两类的操作。保证你的onUpdate回调函数是轻量级的,并确保你在开发时进行memory profiler。
9.Crazy tweening
九、更疯狂的tweening!!
这可能是你不怎么会用到的。
你可以在tween.js之外使用缓间方程,毕竟,它们只是函数。所以你可以用它们来计算缓和曲线之类的作为输入数据。比如在这个页面里,它们被用来生成视频数据。
文中所有的demo都是来自github中的examples的。
转载请注明出处:http://www.cnblogs.com/benymor/p/6373152.html
如有任何建议或疑问,欢迎留言讨论。