199 lines
5.7 KiB
JavaScript
Generated
199 lines
5.7 KiB
JavaScript
Generated
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
if (typeof __VRT_PLAYBACK_SPEED__ === 'undefined') {
|
|
window.__VRT_PLAYBACK_SPEED__ = 1;
|
|
}
|
|
const nativeRaf = window.requestAnimationFrame;
|
|
const nativeSetTimeout = window.setTimeout;
|
|
const nativeSetInterval = window.setInterval;
|
|
const FIXED_FRAME_TIME = 16;
|
|
const MAX_FRAME_TIME = 80;
|
|
const TIMELINE_START = 1566458693300;
|
|
|
|
window.__VRT_TIMELINE_PAUSED__ = true;
|
|
|
|
let realFrameStartTime = 0;
|
|
|
|
/** Control timeline loop */
|
|
let rafCbs = [];
|
|
let frameIdx = 0;
|
|
let timelineTime = 0;
|
|
|
|
function runFrame() {
|
|
realFrameStartTime = NativeDate.now();
|
|
frameIdx++;
|
|
timelineTime += FIXED_FRAME_TIME;
|
|
const currentRafCbs = rafCbs;
|
|
// Clear before calling the callbacks. raf may be registered in the callback
|
|
rafCbs = [];
|
|
currentRafCbs.forEach((cb) => {
|
|
try {
|
|
cb();
|
|
}
|
|
catch (e) {
|
|
// Catch error to avoid following tasks.
|
|
__VRT_LOG_ERRORS__(e.toString());
|
|
}
|
|
});
|
|
flushTimeoutHandlers();
|
|
flushIntervalHandlers();
|
|
}
|
|
function timelineLoop() {
|
|
if (!__VRT_TIMELINE_PAUSED__) {
|
|
runFrame();
|
|
}
|
|
nativeRaf(timelineLoop);
|
|
}
|
|
nativeRaf(timelineLoop);
|
|
|
|
window.requestAnimationFrame = function (cb) {
|
|
rafCbs.push(cb);
|
|
};
|
|
|
|
/** Mock setTimeout, setInterval */
|
|
let timeoutHandlers = [];
|
|
let intervalHandlers = [];
|
|
|
|
let timeoutId = 1;
|
|
let intervalId = 1;
|
|
|
|
window.setTimeout = function (cb, timeout) {
|
|
const elapsedFrame = Math.ceil(Math.max(timeout || 0, 1) / FIXED_FRAME_TIME);
|
|
timeoutHandlers.push({
|
|
callback: cb,
|
|
id: timeoutId,
|
|
frame: frameIdx + elapsedFrame
|
|
});
|
|
|
|
return timeoutId++;
|
|
}
|
|
|
|
window.clearTimeout = function (id) {
|
|
const idx = timeoutHandlers.findIndex(handler => {
|
|
return handler.id === id
|
|
});
|
|
if (idx >= 0) {
|
|
timeoutHandlers.splice(idx, 1);
|
|
}
|
|
}
|
|
|
|
function flushTimeoutHandlers() {
|
|
// Copy the array. In case setTimeout/clearTimeout is invoked in the callback.
|
|
const savedTimeoutHandlers = timeoutHandlers.slice();
|
|
for (let i = 0; i < savedTimeoutHandlers.length; i++) {
|
|
const handler = savedTimeoutHandlers[i];
|
|
if (handler.frame === frameIdx) {
|
|
// Need find index again. In case setTimeout/clearTimeout is invoked in the callback.
|
|
const idx = timeoutHandlers.indexOf(handler);
|
|
timeoutHandlers.splice(idx, 1);
|
|
try {
|
|
handler.callback();
|
|
}
|
|
catch (e) {
|
|
// Catch error to avoid following tasks.
|
|
__VRT_LOG_ERRORS__(e.toString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
window.setInterval = function (cb, interval) {
|
|
const intervalFrame = Math.ceil(Math.max(interval || 0, 1) / FIXED_FRAME_TIME);
|
|
intervalHandlers.push({
|
|
callback: cb,
|
|
id: intervalId,
|
|
intervalFrame,
|
|
frame: frameIdx + intervalFrame
|
|
});
|
|
|
|
return intervalId++;
|
|
}
|
|
|
|
window.clearInterval = function (id) {
|
|
const idx = intervalHandlers.findIndex(handler => {
|
|
return handler.id === id;
|
|
});
|
|
if (idx >= 0) {
|
|
intervalHandlers.splice(idx, 1);
|
|
}
|
|
}
|
|
|
|
function flushIntervalHandlers() {
|
|
// Copy the array. In case setInterval/clearInterval is invoked in the callback.
|
|
const savedIntervalHandlers = intervalHandlers.slice();
|
|
for (let i = 0; i < savedIntervalHandlers.length; i++) {
|
|
const handler = savedIntervalHandlers[i];
|
|
if (handler.frame === frameIdx) {
|
|
try {
|
|
handler.callback();
|
|
}
|
|
catch (e) {
|
|
// Catch error to avoid following tasks.
|
|
__VRT_LOG_ERRORS__(e.toString());
|
|
}
|
|
handler.frame += handler.intervalFrame;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Mock Date */
|
|
|
|
const NativeDate = window.Date;
|
|
|
|
const mockNow = function () {
|
|
// // Use same time in one frame.
|
|
// var realFrameTime = NativeDate.now();
|
|
// // Split frame. Add 8ms offset on the second half
|
|
// // Avoid infinite loop when some logic determine whether to break the loop based on the execution time.
|
|
// // For example https://github.com/apache/echarts/blob/737e23c0054e6b501ecc6f562920cffae953b5c6/src/core/echarts.ts#L537
|
|
// var frameDeltaTime = realFrameTime - realFrameStartTime;
|
|
var frameDeltaTime = 0;
|
|
// Use same time in one frame.
|
|
return TIMELINE_START + (timelineTime + frameDeltaTime) * window.__VRT_PLAYBACK_SPEED__;
|
|
};
|
|
function MockDate(...args) {
|
|
if (!args.length) {
|
|
return new NativeDate(mockNow());
|
|
}
|
|
else {
|
|
return new NativeDate(...args);
|
|
}
|
|
}
|
|
MockDate.prototype = Object.create(NativeDate.prototype);
|
|
Object.setPrototypeOf(MockDate, NativeDate);
|
|
MockDate.now = mockNow;
|
|
window.Date = MockDate;
|
|
|
|
// TODO Do we need to mock performance? Or leave some API that can keep real.
|
|
|
|
|
|
export function start() {
|
|
window.__VRT_TIMELINE_PAUSED__ = false;
|
|
}
|
|
|
|
export function pause() {
|
|
window.__VRT_TIMELINE_PAUSED__ = true;
|
|
}
|
|
|
|
export function resume() {
|
|
window.__VRT_TIMELINE_PAUSED__ = false;
|
|
}
|
|
|
|
export { nativeRaf, nativeSetInterval, nativeSetTimeout }; |