add scroll and viewport resize observers
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { snapshot } from 'rrweb-snapshot';
|
import { snapshot } from 'rrweb-snapshot';
|
||||||
import initObservers from './observer';
|
import initObservers from './observer';
|
||||||
import { mirror } from '../utils';
|
import { mirror, on } from '../utils';
|
||||||
import {
|
import {
|
||||||
EventType,
|
EventType,
|
||||||
event,
|
event,
|
||||||
@@ -9,14 +9,6 @@ import {
|
|||||||
IncrementalSource,
|
IncrementalSource,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
function on(
|
|
||||||
type: string,
|
|
||||||
fn: EventListenerOrEventListenerObject,
|
|
||||||
target = document,
|
|
||||||
) {
|
|
||||||
target.addEventListener(type, fn, { capture: true, passive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
function wrapEvent(e: event): eventWithTime {
|
function wrapEvent(e: event): eventWithTime {
|
||||||
return {
|
return {
|
||||||
...e,
|
...e,
|
||||||
@@ -80,6 +72,26 @@ function record(options: recordOptions) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
scrollCb: p =>
|
||||||
|
emit(
|
||||||
|
wrapEvent({
|
||||||
|
type: EventType.IncrementalSnapshot,
|
||||||
|
data: {
|
||||||
|
source: IncrementalSource.Scroll,
|
||||||
|
...p,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
viewportResizeCb: d =>
|
||||||
|
emit(
|
||||||
|
wrapEvent({
|
||||||
|
type: EventType.IncrementalSnapshot,
|
||||||
|
data: {
|
||||||
|
source: IncrementalSource.ViewportResize,
|
||||||
|
...d,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { INode } from 'rrweb-snapshot';
|
import { INode } from 'rrweb-snapshot';
|
||||||
import { mirror, throttle } from '../utils';
|
import { mirror, throttle, on } from '../utils';
|
||||||
import {
|
import {
|
||||||
mutationCallBack,
|
mutationCallBack,
|
||||||
textMutation,
|
textMutation,
|
||||||
@@ -9,9 +9,11 @@ import {
|
|||||||
observerParam,
|
observerParam,
|
||||||
mousemoveCallBack,
|
mousemoveCallBack,
|
||||||
mousePosition,
|
mousePosition,
|
||||||
handlerMap,
|
|
||||||
mouseInteractionCallBack,
|
mouseInteractionCallBack,
|
||||||
MouseInteractions,
|
MouseInteractions,
|
||||||
|
listenerHandler,
|
||||||
|
scrollCallback,
|
||||||
|
viewportResizeCallback,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
function initMutationObserver(cb: mutationCallBack): MutationObserver {
|
function initMutationObserver(cb: mutationCallBack): MutationObserver {
|
||||||
@@ -68,6 +70,7 @@ function initMutationObserver(cb: mutationCallBack): MutationObserver {
|
|||||||
id: mirror.getId(n as INode),
|
id: mirror.getId(n as INode),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// TODO: init new nodes to be INode
|
||||||
addedNodes.forEach(n => {
|
addedNodes.forEach(n => {
|
||||||
adds.push({
|
adds.push({
|
||||||
parentId: id,
|
parentId: id,
|
||||||
@@ -104,7 +107,7 @@ function initMutationObserver(cb: mutationCallBack): MutationObserver {
|
|||||||
return observer;
|
return observer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function initMousemoveObserver(cb: mousemoveCallBack): () => void {
|
function initMousemoveObserver(cb: mousemoveCallBack): listenerHandler {
|
||||||
let positions: mousePosition[] = [];
|
let positions: mousePosition[] = [];
|
||||||
let timeBaseline: number | null;
|
let timeBaseline: number | null;
|
||||||
const wrappedCb = throttle(() => {
|
const wrappedCb = throttle(() => {
|
||||||
@@ -136,16 +139,13 @@ function initMousemoveObserver(cb: mousemoveCallBack): () => void {
|
|||||||
trailing: false,
|
trailing: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
document.addEventListener('mousemove', updatePosition);
|
return on('mousemove', updatePosition);
|
||||||
return () => {
|
|
||||||
document.removeEventListener('mousemove', updatePosition);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initMouseInteractionObserver(
|
function initMouseInteractionObserver(
|
||||||
cb: mouseInteractionCallBack,
|
cb: mouseInteractionCallBack,
|
||||||
): () => void {
|
): listenerHandler {
|
||||||
const handlers: handlerMap = {};
|
const handlers: listenerHandler[] = [];
|
||||||
const getHandler = (eventKey: keyof typeof MouseInteractions) => {
|
const getHandler = (eventKey: keyof typeof MouseInteractions) => {
|
||||||
return (event: MouseEvent) => {
|
return (event: MouseEvent) => {
|
||||||
const id = mirror.getId(event.target as INode);
|
const id = mirror.getId(event.target as INode);
|
||||||
@@ -163,25 +163,69 @@ function initMouseInteractionObserver(
|
|||||||
.forEach((eventKey: keyof typeof MouseInteractions) => {
|
.forEach((eventKey: keyof typeof MouseInteractions) => {
|
||||||
const eventName = eventKey.toLowerCase();
|
const eventName = eventKey.toLowerCase();
|
||||||
const handler = getHandler(eventKey);
|
const handler = getHandler(eventKey);
|
||||||
handlers[eventName] = handler;
|
handlers.push(on(eventName, handler));
|
||||||
document.addEventListener(eventName, handler);
|
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
Object.keys(handlers).forEach(eventName => {
|
handlers.forEach(h => h());
|
||||||
document.removeEventListener(eventName, handlers[eventName]);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initScrollObserver(cb: scrollCallback): listenerHandler {
|
||||||
|
const updatePosition = throttle<UIEvent>(evt => {
|
||||||
|
if (!evt.target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const id = mirror.getId(evt.target as INode);
|
||||||
|
if (evt.target === document) {
|
||||||
|
cb({
|
||||||
|
id,
|
||||||
|
x: document.documentElement.scrollTop,
|
||||||
|
y: document.documentElement.scrollLeft,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cb({
|
||||||
|
id,
|
||||||
|
x: (evt.target as HTMLElement).scrollTop,
|
||||||
|
y: (evt.target as HTMLElement).scrollLeft,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
return on('scroll', updatePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initViewportResizeObserver(
|
||||||
|
cb: viewportResizeCallback,
|
||||||
|
): listenerHandler {
|
||||||
|
const updateDimension = throttle(() => {
|
||||||
|
const height =
|
||||||
|
window.innerHeight ||
|
||||||
|
(document.documentElement && document.documentElement.clientHeight) ||
|
||||||
|
(document.body && document.body.clientHeight);
|
||||||
|
const width =
|
||||||
|
window.innerWidth ||
|
||||||
|
(document.documentElement && document.documentElement.clientWidth) ||
|
||||||
|
(document.body && document.body.clientWidth);
|
||||||
|
cb({
|
||||||
|
width: Number(width),
|
||||||
|
height: Number(height),
|
||||||
|
});
|
||||||
|
}, 200);
|
||||||
|
return on('resize', updateDimension, window);
|
||||||
|
}
|
||||||
|
|
||||||
export default function initObservers(o: observerParam) {
|
export default function initObservers(o: observerParam) {
|
||||||
const mutationObserver = initMutationObserver(o.mutationCb);
|
const mutationObserver = initMutationObserver(o.mutationCb);
|
||||||
const mousemoveHandler = initMousemoveObserver(o.mousemoveCb);
|
const mousemoveHandler = initMousemoveObserver(o.mousemoveCb);
|
||||||
const mouseInteractionHandler = initMouseInteractionObserver(
|
const mouseInteractionHandler = initMouseInteractionObserver(
|
||||||
o.mouseInteractionCb,
|
o.mouseInteractionCb,
|
||||||
);
|
);
|
||||||
|
const scrollHandler = initScrollObserver(o.scrollCb);
|
||||||
|
const viewportResizeHandler = initViewportResizeObserver(o.viewportResizeCb);
|
||||||
return {
|
return {
|
||||||
mutationObserver,
|
mutationObserver,
|
||||||
mousemoveHandler,
|
mousemoveHandler,
|
||||||
mouseInteractionHandler,
|
mouseInteractionHandler,
|
||||||
|
scrollHandler,
|
||||||
|
viewportResizeHandler,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/types.ts
37
src/types.ts
@@ -35,6 +35,8 @@ export enum IncrementalSource {
|
|||||||
Mutation,
|
Mutation,
|
||||||
MouseMove,
|
MouseMove,
|
||||||
MouseInteraction,
|
MouseInteraction,
|
||||||
|
Scroll,
|
||||||
|
ViewportResize,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type mutationData = {
|
export type mutationData = {
|
||||||
@@ -50,10 +52,20 @@ export type mouseInteractionData = {
|
|||||||
source: IncrementalSource.MouseInteraction;
|
source: IncrementalSource.MouseInteraction;
|
||||||
} & mouseInteractionParam;
|
} & mouseInteractionParam;
|
||||||
|
|
||||||
|
export type scrollData = {
|
||||||
|
source: IncrementalSource.Scroll;
|
||||||
|
} & scrollPosition;
|
||||||
|
|
||||||
|
export type viewportResizeData = {
|
||||||
|
source: IncrementalSource.ViewportResize;
|
||||||
|
} & viewportResizeDimention;
|
||||||
|
|
||||||
export type incrementalData =
|
export type incrementalData =
|
||||||
| mutationData
|
| mutationData
|
||||||
| mousemoveData
|
| mousemoveData
|
||||||
| mouseInteractionData;
|
| mouseInteractionData
|
||||||
|
| scrollData
|
||||||
|
| viewportResizeData;
|
||||||
|
|
||||||
export type event =
|
export type event =
|
||||||
| domContentLoadedEvent
|
| domContentLoadedEvent
|
||||||
@@ -73,6 +85,8 @@ export type observerParam = {
|
|||||||
mutationCb: mutationCallBack;
|
mutationCb: mutationCallBack;
|
||||||
mousemoveCb: mousemoveCallBack;
|
mousemoveCb: mousemoveCallBack;
|
||||||
mouseInteractionCb: mouseInteractionCallBack;
|
mouseInteractionCb: mouseInteractionCallBack;
|
||||||
|
scrollCb: scrollCallback;
|
||||||
|
viewportResizeCb: viewportResizeCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type textMutation = {
|
export type textMutation = {
|
||||||
@@ -116,10 +130,6 @@ export type mousePosition = {
|
|||||||
timeOffset: number;
|
timeOffset: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type handlerMap = {
|
|
||||||
[key: string]: EventListener;
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum MouseInteractions {
|
export enum MouseInteractions {
|
||||||
MouseUp,
|
MouseUp,
|
||||||
MouseDown,
|
MouseDown,
|
||||||
@@ -142,6 +152,21 @@ type mouseInteractionParam = {
|
|||||||
|
|
||||||
export type mouseInteractionCallBack = (d: mouseInteractionParam) => void;
|
export type mouseInteractionCallBack = (d: mouseInteractionParam) => void;
|
||||||
|
|
||||||
|
export type scrollPosition = {
|
||||||
|
id: number;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type scrollCallback = (p: scrollPosition) => void;
|
||||||
|
|
||||||
|
export type viewportResizeDimention = {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type viewportResizeCallback = (d: viewportResizeDimention) => void;
|
||||||
|
|
||||||
export type Mirror = {
|
export type Mirror = {
|
||||||
map: idNodeMap;
|
map: idNodeMap;
|
||||||
getId: (n: INode) => number;
|
getId: (n: INode) => number;
|
||||||
@@ -152,3 +177,5 @@ export type throttleOptions = {
|
|||||||
leading?: boolean;
|
leading?: boolean;
|
||||||
trailing?: boolean;
|
trailing?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type listenerHandler = () => void;
|
||||||
|
|||||||
11
src/utils.ts
11
src/utils.ts
@@ -1,4 +1,13 @@
|
|||||||
import { Mirror, throttleOptions } from './types';
|
import { Mirror, throttleOptions, listenerHandler } from './types';
|
||||||
|
|
||||||
|
export function on(
|
||||||
|
type: string,
|
||||||
|
fn: EventListenerOrEventListenerObject,
|
||||||
|
target: Document | Window = document,
|
||||||
|
): listenerHandler {
|
||||||
|
target.addEventListener(type, fn, { capture: true, passive: true });
|
||||||
|
return () => target.removeEventListener(type, fn);
|
||||||
|
}
|
||||||
|
|
||||||
export const mirror: Mirror = {
|
export const mirror: Mirror = {
|
||||||
map: {},
|
map: {},
|
||||||
|
|||||||
Reference in New Issue
Block a user