Skip to content

Commit

Permalink
Record pointerType on clicks - could be useful for displaying e.g. a …
Browse files Browse the repository at this point in the history
…circle rather than a point during replay

 - We have to switch to 'onpointerdown' & 'onpointerup' in order to actually capture `e.pointerType`
 - this replaces 4 event listeners (MouseDown/MouseUp/TouchStart/TouchEnd) with 2 pointer ones which should fire in all 4 scenarios. We still output the old types according to the MouseInteractions enum
 - there is no Pointer equivalent of Click, so we leave that is, but use the last Pointer event to attach a pointerType to (only) the click event, where it is most useful
 - we can fallback to the old method for any browsers not supporting `window.PointerEvent`, in which case \`pointerType\` will be absent from all events
  • Loading branch information
eoghanmurray committed Mar 30, 2023
1 parent 1b2855b commit 351c555
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 7 deletions.
49 changes: 44 additions & 5 deletions packages/rrweb/src/record/observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
getWindowHeight,
getWindowWidth,
isBlocked,
isTouchEvent,
legacy_isTouchEvent,
patch,
StyleSheetMirror,
} from '../utils';
Expand Down Expand Up @@ -170,7 +170,8 @@ function initMoveObserver({
throttle<MouseEvent | TouchEvent | DragEvent>(
callbackWrapper((evt) => {
const target = getEventTarget(evt);
const { clientX, clientY } = isTouchEvent(evt)
// 'legacy' here as we could switch to https://developer.mozilla.org/en-US/docs/Web/API/Element/pointermove_event
const { clientX, clientY } = legacy_isTouchEvent(evt)
? evt.changedTouches[0]
: evt;
if (!timeBaseline) {
Expand Down Expand Up @@ -228,13 +229,38 @@ function initMouseInteractionObserver({
: sampling.mouseInteraction;

const handlers: listenerHandler[] = [];
let currentPointerType = null;
const getHandler = (eventKey: keyof typeof MouseInteractions) => {
return (event: MouseEvent | TouchEvent) => {
return (event: MouseEvent | TouchEvent | PointerEvent) => {
const target = getEventTarget(event) as Node;
if (isBlocked(target, blockClass, blockSelector, true)) {
return;
}
const e = isTouchEvent(event) ? event.changedTouches[0] : event;
let pointerType = null;
let e = event;
if ('pointerType' in e) {
pointerType = (e as PointerEvent).pointerType; // touch / pen / mouse
if (pointerType === 'touch') {
if (MouseInteractions[eventKey] === MouseInteractions.MouseDown) {
// we are actually listening on 'pointerdown'
eventKey = 'TouchStart';
} else if (MouseInteractions[eventKey] === MouseInteractions.MouseUp) {
// we are actually listening on 'pointerup'
eventKey = 'TouchEnd';
}
} else if (pointerType == 'pen') {
// TODO: these will get incorrectly emitted as MouseDown/MouseUp
}
} else if (legacy_isTouchEvent(event)) {
e = event.changedTouches[0];
pointerType = 'touch';
}
if (pointerType) {
currentPointerType = pointerType;
} else if (MouseInteractions[eventKey] === MouseInteractions.Click) {
pointerType = currentPointerType;
currentPointerType = null; // cleanup as we've used it
}
if (!e) {
return;
}
Expand All @@ -245,6 +271,7 @@ function initMouseInteractionObserver({
id,
x: clientX,
y: clientY,
...pointerType && { pointerType }
});
};
};
Expand All @@ -256,8 +283,20 @@ function initMouseInteractionObserver({
disableMap[key] !== false,
)
.forEach((eventKey: keyof typeof MouseInteractions) => {
const eventName = eventKey.toLowerCase();
let eventName = eventKey.toLowerCase();
const handler = getHandler(eventKey);
if (window.PointerEvent) {
switch(MouseInteractions[eventKey]) {
case MouseInteractions.MouseDown:
case MouseInteractions.MouseUp:
eventName = eventName.replace('mouse', 'pointer');
break;
case MouseInteractions.TouchStart:
case MouseInteractions.TouchEnd:
// these are handled by pointerdown/pointerup
return;
}
}
handlers.push(on(eventName, handler, doc));
});
return callbackWrapper(() => {
Expand Down
4 changes: 2 additions & 2 deletions packages/rrweb/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ export function isAncestorRemoved(target: Node, mirror: Mirror): boolean {
return isAncestorRemoved(target.parentNode, mirror);
}

export function isTouchEvent(
event: MouseEvent | TouchEvent,
export function legacy_isTouchEvent(
event: MouseEvent | TouchEvent | PointerEvent,
): event is TouchEvent {
return Boolean((event as TouchEvent).changedTouches);
}
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ type mouseInteractionParam = {
id: number;
x: number;
y: number;
pointerType?: string;
};

export type mouseInteractionCallBack = (d: mouseInteractionParam) => void;
Expand Down

0 comments on commit 351c555

Please sign in to comment.