Files
rrweb/src/replay/timer.ts
Lucky Feng f0f32a097a fix: sometimes currentTime is smaller than the totalTime when player is finished (#445)
plus: fix the problem that sometimes return value of getCurrentTime() is negative
2020-12-18 15:32:11 +08:00

116 lines
2.9 KiB
TypeScript

import {
actionWithDelay,
eventWithTime,
EventType,
IncrementalSource,
} from '../types';
export class Timer {
public timeOffset: number = 0;
public speed: number;
private actions: actionWithDelay[];
private raf: number | null = null;
private liveMode: boolean;
constructor(actions: actionWithDelay[] = [], speed: number) {
this.actions = actions;
this.speed = speed;
}
/**
* Add an action after the timer starts.
* @param action
*/
public addAction(action: actionWithDelay) {
const index = this.findActionIndex(action);
this.actions.splice(index, 0, action);
}
/**
* Add all actions before the timer starts
* @param actions
*/
public addActions(actions: actionWithDelay[]) {
this.actions.push(...actions);
}
public start() {
this.actions.sort((a1, a2) => a1.delay - a2.delay);
this.timeOffset = 0;
let lastTimestamp = performance.now();
const { actions } = this;
const self = this;
function check() {
const time = performance.now();
self.timeOffset += (time - lastTimestamp) * self.speed;
lastTimestamp = time;
while (actions.length) {
const action = actions[0];
if (self.timeOffset >= action.delay) {
actions.shift();
action.doAction();
} else {
break;
}
}
if (actions.length > 0 || self.liveMode) {
self.raf = requestAnimationFrame(check);
}
}
this.raf = requestAnimationFrame(check);
}
public clear() {
if (this.raf) {
cancelAnimationFrame(this.raf);
this.raf = null;
}
this.actions.length = 0;
}
public setSpeed(speed: number) {
this.speed = speed;
}
public toggleLiveMode(mode: boolean) {
this.liveMode = mode;
}
public isActive() {
return this.raf !== null;
}
private findActionIndex(action: actionWithDelay): number {
let start = 0;
let end = this.actions.length - 1;
while (start <= end) {
let mid = Math.floor((start + end) / 2);
if (this.actions[mid].delay < action.delay) {
start = mid + 1;
} else if (this.actions[mid].delay > action.delay) {
end = mid - 1;
} else {
return mid;
}
}
return start;
}
}
// TODO: add speed to mouse move timestamp calculation
export function addDelay(event: eventWithTime, baselineTime: number): number {
// Mouse move events was recorded in a throttle function,
// so we need to find the real timestamp by traverse the time offsets.
if (
event.type === EventType.IncrementalSnapshot &&
event.data.source === IncrementalSource.MouseMove
) {
const firstOffset = event.data.positions[0].timeOffset;
// timeOffset is a negative offset to event.timestamp
const firstTimestamp = event.timestamp + firstOffset;
event.delay = firstTimestamp - baselineTime;
return firstTimestamp - baselineTime;
}
event.delay = event.timestamp - baselineTime;
return event.delay;
}