/**
|
* 帧动画控制工具
|
*
|
*/
|
function FrameAnimation() {
|
// 动画帧数
|
this.fps = 12
|
// 帧间隔(ms)
|
this.timeout = 1000 / this.fps
|
this.speed = 1
|
this.animationTask = []
|
// 单次插入最多任务数
|
this.maxTasks = 10
|
this.onNextTask
|
|
this.isPause = false
|
this.isRunning = false
|
// 是否开启动态绘制速度
|
this.dynamicSpeed = false
|
// 每个任务耗时(秒)
|
this.taskPeriod = 4
|
// 数据最新时间
|
this.lastestTime
|
}
|
|
FrameAnimation.prototype = {
|
start: function() {
|
if (this.intervalFlag != undefined) {
|
this.isPause = false
|
} else {
|
this.isRunning = true
|
this._doTask()
|
}
|
},
|
/**
|
* 动态动画速度
|
* 当页面失去焦点时,循环任务js会暂停,此时后续的轨迹动画就会被延后;
|
* 同时,由于浏览器性能问题,当运行时间逐渐变长时,轨迹动画与实际时间的差值也会逐渐拉大;
|
* 因此需要动态调整动画运行倍速,与实际时间保持相近
|
*/
|
dynamicAdjustment: function (time) {
|
if (this.dynamicSpeed && this.lastestTime) {
|
// 以两个坐标点(一次task)为最小单位,根据当前绘制数据时间和最新数据时间的差值,调整绘制速度
|
var t1 = moment(time)
|
var t2 = moment(this.lastestTime)
|
var sec = Math.abs(t1.diff(t2, 'seconds'))// 获取时间差
|
|
// 当时间差超过单任务耗时时,需要适当加快动画速度
|
if (sec > this.taskPeriod) {
|
this.speed = Math.round(sec / this.taskPeriod)
|
if (this.speed > 16) {
|
// this.speed = 16
|
}
|
} else {
|
this.speed = 1
|
}
|
}
|
},
|
changeSpeed: function(speed) {
|
if (typeof speed === 'number') {
|
this.speed = speed
|
}
|
},
|
pause: function() {
|
this.isPause = true
|
},
|
stop: function() {
|
if (this.intervalFlag != undefined) {
|
clearInterval(this.intervalFlag)
|
this.intervalFlag = undefined
|
this.animationTask = []
|
}
|
|
// 当前任务列表结束后,首先判断是否有下一段任务
|
if (this.onNextTask) {
|
this.onNextTask()
|
return
|
}
|
|
if (typeof this.onStopCallback === 'function') {
|
this.onStopCallback()
|
}
|
|
this.isRunning = false
|
this.isPause = false
|
this.lastestTime = undefined
|
},
|
setOnStopCallback: function(callback) {
|
this.onStopCallback = callback
|
},
|
addTask: function(count, data, callback) {
|
var task = {
|
data: data,
|
count: count,
|
task: callback
|
}
|
this.animationTask.push(task)
|
// console.log('FrameAnimation: addTask ' + count);
|
},
|
// 任务采取分段执行方式,即当当前任务列表执行完成后,继续开始处理下一段任务
|
addOnNextTasks: function (callback) {
|
this.onNextTask = callback
|
},
|
runStatus: function(){
|
return this.isRunning
|
},
|
_doTask: function() {
|
if (this.animationTask.length > 0) {
|
var t = this.animationTask[0]
|
|
// 动态调整速度
|
this.dynamicAdjustment(t.data.times[t.data.times.length - 1])
|
|
var index = 0
|
this.intervalFlag = setInterval(() => {
|
if (this.isPause) {
|
return
|
}
|
if (index >= t.count) {
|
this._endTask(this.intervalFlag)
|
return
|
}
|
t.task(t.data, index, t.count)
|
|
index += this.speed
|
// console.log("_doTask:" + index);
|
}, this.timeout);
|
}
|
},
|
_endTask: function(intervalFlag) {
|
clearInterval(intervalFlag)
|
this.animationTask.splice(0, 1)
|
if (this.animationTask.length > 0) {
|
this._doTask()
|
} else {
|
this.stop()
|
}
|
},
|
}
|