Skip to content

Commit

Permalink
Merge pull request #717 from microsoft/mn/fixPointer
Browse files Browse the repository at this point in the history
Add primary flag for touch events to handle multi-touch scenarios
  • Loading branch information
ender336 authored Dec 6, 2024
2 parents 6e64027 + c1e6932 commit 5cac37e
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 5 deletions.
8 changes: 7 additions & 1 deletion packages/clarity-js/src/interaction/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ export default async function (type: Event, ts: number = null): Promise<void> {
tokens.push(pTarget.id);
tokens.push(entry.data.x);
tokens.push(entry.data.y);
if (entry.data.id !== undefined) { tokens.push(entry.data.id); }
if (entry.data.id !== undefined) {
tokens.push(entry.data.id);

if (entry.data.isPrimary !== undefined) {
tokens.push(entry.data.isPrimary.toString());
}
}
queue(tokens);
baseline.track(entry.event, entry.data.x, entry.data.y);
}
Expand Down
23 changes: 19 additions & 4 deletions packages/clarity-js/src/interaction/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import encode from "./encode";

export let state: PointerState[] = [];
let timeout: number = null;
let activeTouchPointId = 0;
const activeTouchPointIds = new Set<number>();

export function start(): void {
reset();
Expand Down Expand Up @@ -58,13 +60,26 @@ function touch(event: Event, root: Node, evt: TouchEvent): void {
x = x && frame ? x + Math.round(frame.offsetLeft) : x;
y = y && frame ? y + Math.round(frame.offsetTop) : y;

// identifier is 0-based, unique for each touch point and resets when all fingers are lifted
// that is not a part of the spec, but it is how it is implemented in browsers
// tested in Chromium-based browsers as well as Firefox
// We cannot rely on identifier to determine primary touch as its value doesn't always start with 0.
// Safari/Webkit uses the address of the UITouch object as the identifier value for each touch point.
const id = "identifier" in entry ? entry["identifier"] : undefined;

switch(event) {
case Event.TouchStart:
if (activeTouchPointIds.size === 0) {
activeTouchPointId = id;
}
activeTouchPointIds.add(id);
break;
case Event.TouchEnd:
case Event.TouchCancel:
activeTouchPointIds.delete(id);
break;
}
const isPrimary = activeTouchPointId === id;

// Check for null values before processing this event
if (x !== null && y !== null) { handler({ time: t, event, data: { target: target(evt), x, y, id } }); }
if (x !== null && y !== null) { handler({ time: t, event, data: { target: target(evt), x, y, id, isPrimary } }); }
}
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/clarity-js/types/interaction.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export interface PointerData {
x: number;
y: number;
id?: number;
isPrimary?: boolean;
}

export interface ClickData {
Expand Down

0 comments on commit 5cac37e

Please sign in to comment.