import moment from 'moment'; /** * 帧动画控制工具 * */ 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.isStop = true; // 是否开启动态绘制速度 this.dynamicSpeed = false; // 每个任务耗时(秒) this.taskPeriod = 4; // 数据最新时间 this.lastestTime; } FrameAnimation.prototype = { start: function () { // 不存在动画任务时重新开始,否则继续 if (this.intervalFlag == undefined) { this._doTask(); } this.isPause = false; this.isStop = false; this.isRunning = true; }, /** * 动态动画速度 * 当页面失去焦点时,循环任务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; this.isRunning = false; }, stop: function () { if (this.isStop) return; 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.isStop = true; this.lastestTime = undefined; this.speed = 1; }, 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]; // 动态调整速度 if (typeof t.data.times === 'object') { this.dynamicAdjustment(t.data.times[t.data.times.length - 1]); } var index = 0; this.intervalFlag = setInterval(() => { if (this.isPause) { return; } // 绘制3D图形时,最少需要2个点才可绘制图形 // 因此此处索引只到倒数第二个点就结束 if (index >= t.count - 1) { this._endTask(this.intervalFlag); return; } t.task(t.data, index, t.count); index += this.speed; }, this.timeout); } }, _endTask: function (intervalFlag) { clearInterval(intervalFlag); this.animationTask.splice(0, 1); if (this.animationTask.length > 0) { this._doTask(); } else { this.stop(); } } }; export { FrameAnimation };