Skip to content

Commit

Permalink
resolve #4 removing later function from timer
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardwu1 committed Nov 15, 2018
1 parent 3a92a3c commit e598d3c
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 90 deletions.
65 changes: 34 additions & 31 deletions src/replay/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { rebuild, buildNodeWithSN } from 'rrweb-snapshot';
import * as mittProxy from 'mitt';
import { later, Timer } from './timer';
import Timer from './timer';
import {
EventType,
incrementalData,
Expand All @@ -14,6 +14,7 @@ import {
missingNodeMap,
addedNodeMutation,
missingNode,
actionWithDelay,
} from '../types';
import { mirror } from '../utils';
import './styles/style.css';
Expand All @@ -36,7 +37,6 @@ export class Replayer {
private iframe: HTMLIFrameElement;
private mouse: HTMLDivElement;

private timerIds: number[] = [];
private emitter: mitt.Emitter = mitt();

private baselineTime: number = 0;
Expand Down Expand Up @@ -66,7 +66,6 @@ export class Replayer {
Object.keys(config).forEach((key: keyof playerConfig) => {
this.config[key] = config[key]!;
});
this.timer.changeConfig(this.config);
}

public getMetaData(): playerMetaData {
Expand All @@ -88,25 +87,27 @@ export class Replayer {
*/
public play(timeOffset = 0) {
this.baselineTime = this.events[0].timestamp + timeOffset;
const actions = new Array<actionWithDelay>();
for (const event of this.events) {
const isSync = event.timestamp < this.baselineTime;
const castFn = this.getCastFn(event, isSync);
if (isSync) {
castFn();
} else {
const action = { doAction: castFn, delay: this.getDelay(event) };
this.timer.addAction(action);
actions.push({ doAction: castFn, delay: this.getDelay(event) });
}
}
this.timer.addActions(actions);
this.timer.start();
}

public pause() {
this.timer.stop();
this.timer.clear();
}

public resume(timeOffset = 0) {
this.timer.stop();
this.timer.clear();
const actions = new Array<actionWithDelay>();
for (const event of this.events) {
if (
event.timestamp < this.lastPlayedEvent.timestamp ||
Expand All @@ -116,11 +117,12 @@ export class Replayer {
}
const delayToBaseline = this.getDelay(event);
const castFn = this.getCastFn(event);
this.timer.addAction({
actions.push({
doAction: castFn,
delay: delayToBaseline - timeOffset,
});
}
this.timer.addActions(actions);
this.timer.start();
}

Expand All @@ -142,11 +144,6 @@ export class Replayer {
this.iframe.height = `${dimension.height}px`;
}

private later(cb: () => void, delayMs: number) {
const id = later(cb, delayMs, this.config);
this.timerIds.push(id);
}

// TODO: add speed to mouse move timestamp calculation
private getDelay(event: eventWithTime): number {
// Mouse move events was recorded in a throttle function,
Expand Down Expand Up @@ -305,26 +302,32 @@ export class Replayer {
// skip mouse move in sync mode
if (!isSync) {
d.positions.forEach(p => {
this.later(() => {
this.mouse.style.left = `${p.x}px`;
this.mouse.style.top = `${p.y}px`;
const target = mirror.getNode(p.id);
if (target) {
this.hoverElements((target as Node) as Element);
}
}, p.timeOffset);
const action = {
doAction: () => {
this.mouse.style.left = `${p.x}px`;
this.mouse.style.top = `${p.y}px`;
const target = mirror.getNode(p.id);
if (target) {
this.hoverElements((target as Node) as Element);
}
},
delay: p.timeOffset,
};
this.timer.addAction(action);
});
// d.positions.forEach(p => {
// const action = { doAction: () => {
// this.mouse.style.left = `${p.x}px`;
// this.mouse.style.top = `${p.y}px`;
// const target = mirror.getNode(p.id);
// if (target) {
// this.hoverElements((target as Node) as Element);
// }
// }, delay: p.timeOffset };

// this.timer.addAction(action);
// later(
// () => {
// this.mouse.style.left = `${p.x}px`;
// this.mouse.style.top = `${p.y}px`;
// const target = mirror.getNode(p.id);
// if (target) {
// this.hoverElements((target as Node) as Element);
// }
// },
// p.timeOffset,
// this.config,
// );
// });
}
break;
Expand Down
84 changes: 30 additions & 54 deletions src/replay/timer.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,34 @@
import { playerConfig, actionWithDelay, TimerStatus } from '../types';
export class Timer {
import { playerConfig, actionWithDelay } from '../types';

export default class Timer {
private actions: actionWithDelay[];
private config: playerConfig;
private status: TimerStatus;

constructor(config: playerConfig, actions: actionWithDelay[] = []) {
this.actions = actions;
this.config = config;
this.status = TimerStatus.Stopped;
}

public addActions(actions: actionWithDelay[]) {
if (this.status !== TimerStatus.Stopped) {
throw new Error('Actions can only be added when the timer is stopped');
}
this.actions.push(...actions);
}

/**
* Add an action after the timer starts.
* @param action
*/
public addAction(action: actionWithDelay) {
this.addActions([action]);
const index = this.findActionIndex(action);
this.actions.splice(index, 0, action);
}

public changeConfig(config: Partial<playerConfig>) {
Object.keys(config).forEach((key: keyof playerConfig) => {
this.config[key] = config[key]!;
});
/**
* 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);
let delayed = 0;
const start = performance.now();
const actions = this.actions;
const config = this.config;
const { actions, config } = this;
function check(time: number) {
if (actions.length === 0) {
this.stop();
Expand All @@ -54,45 +50,25 @@ export class Timer {
}
}
requestAnimationFrame(check);
this.status = TimerStatus.Started;
}

public stop() {
public clear() {
this.actions = [];
this.status = TimerStatus.Stopped;
}
}

const FRAME_MS = 16;
let _id = 1;
const timerMap: Map<number, boolean> = new Map();

export function later(
cb: () => void,
delayMs: number,
config: playerConfig,
): number {
const now = performance.now();
let lastStep = now;
const id = _id++;
timerMap.set(id, true);
function check(step: number) {
if (!timerMap.has(id)) {
return;
}
const stepDiff = step - lastStep;
lastStep = step;
delayMs -= config.speed * stepDiff;
if (delayMs < FRAME_MS) {
cb();
clear(id);
} else {
requestAnimationFrame(check);
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;
}
requestAnimationFrame(check);
return id;
}
export function clear(id: number) {
timerMap.delete(id);
}
5 changes: 0 additions & 5 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,3 @@ export type actionWithDelay = {
doAction: () => void;
delay: number;
};

export enum TimerStatus {
Started,
Stopped,
}

0 comments on commit e598d3c

Please sign in to comment.