2021SC@SDUSC
AnimationProcess.js
上一次我们AnimationProcess.js文件的内容讲了个开篇,接下来继续其余内容
AnimationProcess中动画功能的主要元素上一篇内已经讲过了,接下来的部分主要是动画过程的一些操作定义。
when(time, config) {
let flattenMap = new Map();
dataUtil.flattenObj(config, flattenMap);
flattenMap.forEach((value, key, map) => {
let track = this._trackCacheMap.get(key);
if (!track) {
track = new Track({
element: this.element,
path: key,
delay: this._delay,
});
if (time !== 0) {
let temp = dataUtil.getAttrByPath(this.element, key);
if (temp == null || temp == undefined) {
temp = 0;
}
track.addKeyFrame({
time: 0,
value: dataUtil.clone(temp),
});
}
this._trackCacheMap.set(key, track);
}
track.addKeyFrame({
time: time,
value: dataUtil.clone(value),
});
});
return this;
}
首先是对关键帧的操作。
关键帧是指在动画和电影制作中绘制所有平滑变换中所必须定义的起点和终点,又称作画格、关键影格,因其时间点符合影片画格的原则。
关键格的序列定义了观众将会看到哪些动作,虽然在影片、视讯或动画上的关键格位置限定了动作的时机掌握。由于每秒仅有二到三格的关键格并不能产生运动错觉,其余需要补满的画格就称作“中间格”(inbetweens)。
首先是为每一种需要进行动画的属性创建一条轨道,轨道的起点和终点就是关键帧,同时定义关键帧的存活时间(单位是毫秒m)以及关键帧的属性值(key-value 表示),这里Quark Renderer 能支持动画的属性有 position、shape、style。
然后是后半部分,这里主要的功能是,先进行判断,time为0的时候是否有帧,如果有,将其定为关键帧,如果参数中没有提供第 0 帧,自动补第 0 帧,以元素上当前的属性值为关键帧的值。
start(loop = false, easing = '', forceAnimate = false) {
this._running = true;
this._paused = false;
this.trigger('start');
return this;
}
这里是动画的开始代码,当running的布尔值为true而paused为false时,动画触发器获得信息为开始,动画开始播放。
if (!this._trackCacheMap.size) {
this.trigger('done');
return this;
}
this._trackCacheMap.forEach((track, key, map) => {
track && track.start(loop, easing, forceAnimate);
});
这里的功能是判断动画是否进行循环播放和是否强制开启动画,这些都被整合到了动画的开始动作里。其中easing部分调用了缓动引擎,这个后面面再说。
nextFrame(time, delta) {
this._running = true;
this._paused = false;
let deferredEvents = [];
let deferredTracks = [];
let percent = '';
let isFinished = true;
this._trackCacheMap.forEach((track, key, map) => {
let result = track.nextFrame(time, delta);
if (dataUtil.isString(result)) {
deferredEvents.push(result);
deferredTracks.push(track);
} else if (dataUtil.isNumeric(result)) {
percent = result;
}
isFinished = isFinished && track.isFinished;
if (dataUtil.isNumeric(percent)) {
this.trigger('during', this.element, track._path, track._currentValue, percent);
}
});
let len = deferredEvents.length;
for (let i = 0; i < len; i++) {
deferredTracks[i].fire(deferredEvents[i]);
}
if (isFinished) {
this.trigger('done');
}
}
这一整段代码都是负责动画的播放,首先第一部分trackCacheMap的相关属性来确定当前帧并对当前帧是否是结束关键帧进行判断,如果不是就会进入下一帧,后面的两部分则是用于通过当前帧获取时间轴上的当前时间,然后利用时间的偏移量获得下一帧的时间,再精确的利用时间检索下一帧并播放出来。
stop(forwardToLast) {
this._running = false;
this._paused = false;
this._trackCacheMap.forEach((track, key, map) => {
track.stop(this.element, 1);
});
this._trackCacheMap = new Map();
this.trigger('stop');
return this;
}
这里是停止的代码,当上一部分判断获得的帧是结束关键帧或者手动停止的时候就会启动这一部分,这时,不管是播放的running还是暂停paused都是false,动画在创建的轨道上停止。其中,如果有特殊要求,动画会在停止后自动跳到最后一帧。
pause() {
this._running = false;
this._paused = true;
this._trackCacheMap.forEach((track, key, map) => {
track.pause();
});
this.trigger('pause');
return this;
}
resume() {
this._running = true;
this._paused = false;
this._trackCacheMap.forEach((track, key, map) => {
track.resume();
});
this.trigger('resume');
return this;
}
这两个就是动画的暂停和恢复,与启动和停止大同小异,没什么好说的。
为了方便链式调用
during(callback) {
this.on('during', callback);
return this;
}
done(callback) {
this.on('done', callback);
return this;
}
获取每一帧的回调函数并为动画添加一个结束的回调。
delay(time) {
this._delay = time;
return this;
}
最后,为动画设置延迟播放的开始时间。
这就是AnimationProcess.js文件的主要内容了。