Allow player to play a from-to range (#1007)

* Allow player to play a from-to range

And optionally trigger a callback or loop

* Update packages/rrweb-player/src/Controller.svelte
This commit is contained in:
Justin Halsall
2026-04-01 12:00:00 +08:00
committed by GitHub
parent d97315d382
commit fe2b228c36
2 changed files with 54 additions and 0 deletions

View File

@@ -39,6 +39,13 @@
let step: HTMLElement; let step: HTMLElement;
let finished: boolean; let finished: boolean;
let pauseAt: number | false = false;
let onPauseHook: () => unknown | undefined = undefined;
let loop: {
start: number;
end: number;
} | null = null;
let meta: playerMetaData; let meta: playerMetaData;
$: meta = replayer.getMetaData(); $: meta = replayer.getMetaData();
let percentage: string; let percentage: string;
@@ -94,6 +101,18 @@
function update() { function update() {
currentTime = replayer.getCurrentTime(); currentTime = replayer.getCurrentTime();
if (pauseAt && currentTime >= pauseAt) {
if (loop) {
playRange(loop.start, loop.end, true, undefined);
} else {
replayer.pause();
if (onPauseHook) {
onPauseHook();
onPauseHook = null;
}
}
}
if (currentTime < meta.totalTime) { if (currentTime < meta.totalTime) {
timer = requestAnimationFrame(update); timer = requestAnimationFrame(update);
} }
@@ -139,10 +158,12 @@
return; return;
} }
replayer.pause(); replayer.pause();
pauseAt = false;
}; };
export const goto = (timeOffset: number, play?: boolean) => { export const goto = (timeOffset: number, play?: boolean) => {
currentTime = timeOffset; currentTime = timeOffset;
pauseAt = false;
const resumePlaying = const resumePlaying =
typeof play === 'boolean' ? play : playerState === 'playing'; typeof play === 'boolean' ? play : playerState === 'playing';
if (resumePlaying) { if (resumePlaying) {
@@ -152,6 +173,27 @@
} }
}; };
export const playRange = (
timeOffset: number,
endTimeOffset: number,
startLooping: boolean = false,
afterHook: undefined | (() => void) = undefined,
) => {
if (startLooping) {
loop = {
start: timeOffset,
end: endTimeOffset,
};
} else {
loop = null;
}
currentTime = timeOffset;
pauseAt = endTimeOffset;
onPauseHook = afterHook;
replayer.play(timeOffset);
};
const handleProgressClick = (event: MouseEvent) => { const handleProgressClick = (event: MouseEvent) => {
if (speedState === 'skipping') { if (speedState === 'skipping') {
return; return;
@@ -218,6 +260,10 @@
); );
replayer.on('finish', () => { replayer.on('finish', () => {
finished = true; finished = true;
if (onPauseHook) {
onPauseHook();
onPauseHook = null;
}
}); });
if (autoPlay) { if (autoPlay) {

View File

@@ -114,6 +114,14 @@
export const goto = (timeOffset: number, play?: boolean) => { export const goto = (timeOffset: number, play?: boolean) => {
controller.goto(timeOffset, play); controller.goto(timeOffset, play);
}; };
export const playRange = (
timeOffset: number,
endTimeOffset: number,
startLooping: boolean = false,
afterHook: undefined | (() => void) = undefined,
) => {
controller.playRange(timeOffset, endTimeOffset, startLooping, afterHook);
};
onMount(() => { onMount(() => {
// runtime type check // runtime type check