/** * 帧动画控制工具 * */ 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() } }, }