Record pointerType on clicks - could be useful for displaying e.g. a 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
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
|||||||
getWindowHeight,
|
getWindowHeight,
|
||||||
getWindowWidth,
|
getWindowWidth,
|
||||||
isBlocked,
|
isBlocked,
|
||||||
isTouchEvent,
|
legacy_isTouchEvent,
|
||||||
patch,
|
patch,
|
||||||
StyleSheetMirror,
|
StyleSheetMirror,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
@@ -170,7 +170,8 @@ function initMoveObserver({
|
|||||||
throttle<MouseEvent | TouchEvent | DragEvent>(
|
throttle<MouseEvent | TouchEvent | DragEvent>(
|
||||||
callbackWrapper((evt) => {
|
callbackWrapper((evt) => {
|
||||||
const target = getEventTarget(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.changedTouches[0]
|
||||||
: evt;
|
: evt;
|
||||||
if (!timeBaseline) {
|
if (!timeBaseline) {
|
||||||
@@ -228,13 +229,38 @@ function initMouseInteractionObserver({
|
|||||||
: sampling.mouseInteraction;
|
: sampling.mouseInteraction;
|
||||||
|
|
||||||
const handlers: listenerHandler[] = [];
|
const handlers: listenerHandler[] = [];
|
||||||
|
let currentPointerType = null;
|
||||||
const getHandler = (eventKey: keyof typeof MouseInteractions) => {
|
const getHandler = (eventKey: keyof typeof MouseInteractions) => {
|
||||||
return (event: MouseEvent | TouchEvent) => {
|
return (event: MouseEvent | TouchEvent | PointerEvent) => {
|
||||||
const target = getEventTarget(event) as Node;
|
const target = getEventTarget(event) as Node;
|
||||||
if (isBlocked(target, blockClass, blockSelector, true)) {
|
if (isBlocked(target, blockClass, blockSelector, true)) {
|
||||||
return;
|
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) {
|
if (!e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -245,6 +271,7 @@ function initMouseInteractionObserver({
|
|||||||
id,
|
id,
|
||||||
x: clientX,
|
x: clientX,
|
||||||
y: clientY,
|
y: clientY,
|
||||||
|
...pointerType && { pointerType }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -256,8 +283,20 @@ function initMouseInteractionObserver({
|
|||||||
disableMap[key] !== false,
|
disableMap[key] !== false,
|
||||||
)
|
)
|
||||||
.forEach((eventKey: keyof typeof MouseInteractions) => {
|
.forEach((eventKey: keyof typeof MouseInteractions) => {
|
||||||
const eventName = eventKey.toLowerCase();
|
let eventName = eventKey.toLowerCase();
|
||||||
const handler = getHandler(eventKey);
|
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));
|
handlers.push(on(eventName, handler, doc));
|
||||||
});
|
});
|
||||||
return callbackWrapper(() => {
|
return callbackWrapper(() => {
|
||||||
|
|||||||
@@ -277,8 +277,8 @@ export function isAncestorRemoved(target: Node, mirror: Mirror): boolean {
|
|||||||
return isAncestorRemoved(target.parentNode, mirror);
|
return isAncestorRemoved(target.parentNode, mirror);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isTouchEvent(
|
export function legacy_isTouchEvent(
|
||||||
event: MouseEvent | TouchEvent,
|
event: MouseEvent | TouchEvent | PointerEvent,
|
||||||
): event is TouchEvent {
|
): event is TouchEvent {
|
||||||
return Boolean((event as TouchEvent).changedTouches);
|
return Boolean((event as TouchEvent).changedTouches);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,6 +404,7 @@ type mouseInteractionParam = {
|
|||||||
id: number;
|
id: number;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
pointerType?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type mouseInteractionCallBack = (d: mouseInteractionParam) => void;
|
export type mouseInteractionCallBack = (d: mouseInteractionParam) => void;
|
||||||
|
|||||||
Reference in New Issue
Block a user