X.d 笔记

小Web,大世界

0%

Tween.js 简单使用

Tween.js 是一个 过渡计算工具包 ,理论上来说只是一个工具包,可以用到各种需要有过渡效果的场景,实际上也是这样。 不个人目前最常用的就是与 threejs 结合使用。

一、引入工具包

npm install @tweenjs/tween.js

引入

var TWEEN = require('@tweenjs/tween.js');

个人习惯性的用 npm 安装引入 ,如果不习惯,下载源文件并通过 script 标签套进来也是一样的。

一般情况下,需要通过环境里面提供的辅助时间工具来实现。比如在网页上就是使用 window 下的 requestAnimationFrame 方法,低端浏览器只能使用 setInterval 方法来配合了。

二、简单使用

例如:把一个元素的 x 坐标在 1秒内由100 增加到 200, 通过以下代码可以实现:

// 1. 定义元素
var position = { x: 100, y: 0 };
// 2. new 一个 Tween对象,构造参数传入需要变化的元素
var tween = new TWEEN.Tween(position);
// 3. 设置目标
tween.to({ x: 200 }, 1000);
// 4. 启动,通常情况下,2,3,4步一般习惯性写在一起,定义命名也省了
//    例如 new TWEEN.Tween(position).to({ x: 200 }, 1000).start();
tween.start();
// 5. (可选:)如果在变化过程中想自定义事件,则可以通过 `onUpdate` 实现
tween.onUpdate(function(pos) {
    console.log(pos.x);
});
// 6. 设置 requestAnimationFrame,在方法里面调用全局的 `TWEEN.update()`
//    在这个方法里面也可以加入其它的代码:d3, threejs 里面经常会用到。
//	  比如THREEJS里面用到的变化,如 `renderer.render(scene, camera);` 等
function animate() {
    requestAnimationFrame(animate);
    TWEEN.update();
}
// 6. 启动全局的 animate
animate();

三、设置变化参数

上面代码中,参数主要是通过 new 操作to 方法 设置进入的。大部分时候可以满足需要,

to 方法设置元素过渡的时间和目标值即可。

连续型变化

一般情况下,设置起点和终点时两个数时,认为是连续型的,里面有无数的可能变化到的值(算上小数)。

连续型变化使用 easing 做为时间变化函数,默认使用的是 Liner 纯性过渡函数,easing过渡 的种类很多,每种还区分 IN, OUT, INOUT 算法。引用时 使用 TWEEN.Easing前缀,例如 :

tween.easing(TWEEN.Easing.Quadratic.Out)

目前内置的过渡函数下图:

tween-easing

离散型变化

** 离散型变化 ** :也就是非连续型的,比如变化过程只能是在 [1,2,3,4,5] 5个值中进行(跳跃,不会1 -> 1.5 -> 2这种 )变化,那么应该:

// to 方法中设置的 target 将对象的值以数组的形式传入:
var tween = new TWEEN.Tween(relativeObj).to({ x: [ 1, 2, 3, 4, 5]});
// 设置后会根据值的数量(5个值时) ,分别时间经过 0%, 25%, 50%, 75%, 100% 时返回。

数量过渡默认使用的是 TWEEN.Interpolation.Linear, 也可以使用 interpolation 方法做为时间变换的参数,除了 TWEEN.Interpolation.Linear 之外,还支持 TWEEN.Interpolation.Bezier, TWEEN.Interpolation.CatmullRom

自定义过渡函数

不管是连续型还是离散型,都是支持自定义函数的,如果对于 Tween 内置的不满意或不满足条件,可以自定义一个函数按自己的算法实现过渡,例如:

function stepEasing(k) {
    return Math.floor(k * 10) / 10;
}
tween.easing(stepEasing);

四、主动控制

Demo 里面,我们使用了 start() 方法启动了过渡,x 会从 start 开始从初始值,经过 to() 方法设置的时间后,再到 to() 方法设置的值。在变化的过程中,使用 update() 方法将事件发出。

start([time])stop()

开始,结束,start 方法还接受一个时间参数,如果传了的话,就直接从传入的时间开始

update([time])

更新,会触发更新事件,如果有监听,则可以执行监听相关代码。

更新方法接受一个时间参数,如果传了的话,就更新到指定的时间

chain(tweenObject,[tweenObject])

如果是多个 Tween 对像 如果 tweenA 需要等到 tweenB 结束后,才能 start, 那么可以使用 。

tweenA.chain(tweenB);
//另外,chain方法也可以接收多个参数,如果 A对象 需要等待多个对像时,依次传入
tweenA.chain(tweenB, tweenC, tweenD);

当然,你还可以利用这个特性,创建一个两个对像的无限循环

tweenA.chain(tweenB);
tweenB.chain(tweenA);

repeat(number)

循环的次数,默认是 1 所以不定义的话,只过渡一次就没了,可以使用上面刚说的无限循环的方法,便只是一个对象无限循环时,就使用 :

tween.repeat(Infinity); //无限循环

tween.repeat(5); //循环5次

delay(time)

delay 是指延时多久才开始。比如以下代码

tween.delay(1000);
tween.start();

虽然已经调用 start 了,但过渡动作要等 1秒 后才开始执行!

监听 onStart, onStop, onUpdate, onComplete

分别对应 生命周期里面的 start, stop, update, complete, 如果 设置了这些监听事件,那么执行到对应部分时,会进行调用。

每个方法都接收一个 类型为 function(object){} 回调函数做为参数,当事件触发时,会将监听对象的实体传入到回实体。

五、全局控制

全局控制函数

全局控制函数平时使用的并不是太多, 简单带过一下:

  1. TWEEN.update(time) :对所有 active 状态的 Tween 对象实行 update(time) 调用
  2. TWEEN.getAll() , TWEEN.removeAll() : 获取 删除所有的 Tween对象
  3. TWEEN.add(tween), TWEEN.remove(tween) : 自定义添加,删除 Tween对象 ,这个方法在 Tween对象 的生命周期里面自动调用的,不需要手动调用,提供 API 可能是让各位能发挥想象空间做点更炫酷的功能!

分组控制

对于复杂的动画来说,可能需要同时管理成百上千个 Tween对象TWEEN提供了分组控制的,以便于复杂的组合。

var groupA = new TWEEN.Group();
var groupB = new TWEEN.Group();

var tweenA = new TWEEN.Tween({ x: 1 }, groupA)
    .to({ x: 10 }, 100)
    .start();

var tweenB = new TWEEN.Tween({ x: 1 }, groupB)
    .to({ x: 10 }, 100)
    .start();

var tweenC = new TWEEN.Tween({ x: 1 })
    .to({ x: 10 }, 100)
    .start();

groupA.update(); // only updates tweenA
groupB.update(); // only updates tweenB
TWEEN.update(); // only updates tweenC

groupA.removeAll(); // only removes tweenA
groupB.removeAll(); // only removes tweenB
TWEEN.removeAll(); // only removes tweenC

六、小结

其实我是不太想用这个工具包的,但使用 threejs 要用的很多动画,官方没有提供动画工具,而不得已才使用。

个人更一喜欢 d3 的动画方式, 使用selector.transition() 来完成一个动画,与环境结合的更紧密,后续的各种动画都会以 selector 做为上下文在应用中,希望 threejs 早点出一个像 d3 一样的能包含上下文的动画 API :jack_o_lantern: