impl dynamic config and pause. Bump 0.3.0
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rrweb",
|
"name": "rrweb",
|
||||||
"version": "0.2.0",
|
"version": "0.3.0",
|
||||||
"description": "record and replay the web",
|
"description": "record and replay the web",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { rebuild, serializeNodeWithId } from 'rrweb-snapshot';
|
import { rebuild, serializeNodeWithId } from 'rrweb-snapshot';
|
||||||
import later from './timer';
|
import { later, clear } from './timer';
|
||||||
import {
|
import {
|
||||||
EventType,
|
EventType,
|
||||||
incrementalData,
|
incrementalData,
|
||||||
@@ -7,18 +7,35 @@ import {
|
|||||||
fullSnapshotEvent,
|
fullSnapshotEvent,
|
||||||
eventWithTime,
|
eventWithTime,
|
||||||
MouseInteractions,
|
MouseInteractions,
|
||||||
|
playerConfig,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { mirror, getIdNodeMap } from '../utils';
|
import { mirror, getIdNodeMap } from '../utils';
|
||||||
|
|
||||||
|
const defaultConfig: playerConfig = {
|
||||||
|
speed: 1,
|
||||||
|
};
|
||||||
|
|
||||||
export class Replayer {
|
export class Replayer {
|
||||||
private events: eventWithTime[] = [];
|
private events: eventWithTime[] = [];
|
||||||
|
private config: playerConfig;
|
||||||
|
|
||||||
private wrapper: HTMLDivElement;
|
private wrapper: HTMLDivElement;
|
||||||
private iframe: HTMLIFrameElement;
|
private iframe: HTMLIFrameElement;
|
||||||
private mouse: HTMLDivElement;
|
private mouse: HTMLDivElement;
|
||||||
private startTime: number = 0;
|
private startTime: number = 0;
|
||||||
|
|
||||||
constructor(events: eventWithTime[]) {
|
private timerIds: number[] = [];
|
||||||
|
|
||||||
|
constructor(events: eventWithTime[], config: playerConfig = defaultConfig) {
|
||||||
this.events = events;
|
this.events = events;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setConfig(config: Partial<playerConfig>) {
|
||||||
|
this.config = {
|
||||||
|
...this.config,
|
||||||
|
...config,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public play() {
|
public play() {
|
||||||
@@ -33,12 +50,13 @@ export class Replayer {
|
|||||||
this.iframe.height = `${event.data.height}px`;
|
this.iframe.height = `${event.data.height}px`;
|
||||||
break;
|
break;
|
||||||
case EventType.FullSnapshot:
|
case EventType.FullSnapshot:
|
||||||
later(() => {
|
this.later(() => {
|
||||||
this.rebuildFullSnapshot(event);
|
this.rebuildFullSnapshot(event);
|
||||||
|
this.iframe.contentWindow!.scrollTo(event.data.initialOffset);
|
||||||
}, this.getDelay(event));
|
}, this.getDelay(event));
|
||||||
break;
|
break;
|
||||||
case EventType.IncrementalSnapshot:
|
case EventType.IncrementalSnapshot:
|
||||||
later(() => {
|
this.later(() => {
|
||||||
this.applyIncremental(event.data);
|
this.applyIncremental(event.data);
|
||||||
}, this.getDelay(event));
|
}, this.getDelay(event));
|
||||||
break;
|
break;
|
||||||
@@ -47,6 +65,10 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public pause() {
|
||||||
|
this.timerIds.forEach(clear);
|
||||||
|
}
|
||||||
|
|
||||||
private setupDom() {
|
private setupDom() {
|
||||||
this.wrapper = document.createElement('div');
|
this.wrapper = document.createElement('div');
|
||||||
this.wrapper.classList.add('replayer-wrapper');
|
this.wrapper.classList.add('replayer-wrapper');
|
||||||
@@ -60,6 +82,11 @@ export class Replayer {
|
|||||||
this.wrapper.appendChild(this.iframe);
|
this.wrapper.appendChild(this.iframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private later(cb: () => void, delayMs: number) {
|
||||||
|
const id = later(cb, delayMs, this.config.speed);
|
||||||
|
this.timerIds.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
private getDelay(event: eventWithTime): number {
|
private getDelay(event: eventWithTime): number {
|
||||||
// Mouse move events was recorded in a throttle function,
|
// Mouse move events was recorded in a throttle function,
|
||||||
// so we need to find the real timestamp by traverse the time offsets.
|
// so we need to find the real timestamp by traverse the time offsets.
|
||||||
@@ -152,7 +179,7 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
case IncrementalSource.MouseMove:
|
case IncrementalSource.MouseMove:
|
||||||
d.positions.forEach(p => {
|
d.positions.forEach(p => {
|
||||||
later(() => {
|
this.later(() => {
|
||||||
this.mouse.style.left = `${p.x}px`;
|
this.mouse.style.left = `${p.x}px`;
|
||||||
this.mouse.style.top = `${p.y}px`;
|
this.mouse.style.top = `${p.y}px`;
|
||||||
}, p.timeOffset);
|
}, p.timeOffset);
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
const FRAME_MS = 16;
|
const FRAME_MS = 16;
|
||||||
|
const timerMap: Map<number, boolean> = new Map();
|
||||||
|
|
||||||
function later(cb: () => void, delayMs: number, speed = 1) {
|
export function later(cb: () => void, delayMs: number, speed = 1): number {
|
||||||
const now = performance.now();
|
const now = performance.now();
|
||||||
|
const id = timerMap.size + 1;
|
||||||
|
timerMap.set(id, true);
|
||||||
|
|
||||||
function check(step: number) {
|
function check(step: number) {
|
||||||
|
if (!timerMap.has(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (step - now > delayMs / speed - FRAME_MS) {
|
if (step - now > delayMs / speed - FRAME_MS) {
|
||||||
cb();
|
cb();
|
||||||
|
clear(id);
|
||||||
} else {
|
} else {
|
||||||
requestAnimationFrame(check);
|
requestAnimationFrame(check);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requestAnimationFrame(check);
|
requestAnimationFrame(check);
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default later;
|
export function clear(id: number) {
|
||||||
|
timerMap.delete(id);
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user