Skip to content

Commit 30bb7a7

Browse files
xnimorzVlad Shilov
authored andcommitted
support multitouch
1 parent 8c736ee commit 30bb7a7

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

src/components/common/Interactive.tsx

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,25 @@ export interface Interaction {
1010
// Check if an event was triggered by touch
1111
const isTouch = (event: MouseEvent | TouchEvent): event is TouchEvent => "touches" in event;
1212

13+
const getPoint = (touches: TouchList, touchId: null | number): Touch => {
14+
for (let i = 0; i < touches.length; i++) {
15+
if (touches[i].identifier === touchId) {
16+
return touches[i];
17+
}
18+
}
19+
return touches[0];
20+
};
21+
1322
// Returns a relative position of the pointer inside the node's bounding box
14-
const getRelativePosition = (node: HTMLDivElement, event: MouseEvent | TouchEvent): Interaction => {
23+
const getRelativePosition = (
24+
node: HTMLDivElement,
25+
event: MouseEvent | TouchEvent,
26+
touchId: null | number
27+
): Interaction => {
1528
const rect = node.getBoundingClientRect();
1629

1730
// Get user's pointer position from `touches` array if it's a `TouchEvent`
18-
const pointer = isTouch(event) ? event.touches[0] : (event as MouseEvent);
31+
const pointer = isTouch(event) ? getPoint(event.touches, touchId) : (event as MouseEvent);
1932

2033
return {
2134
left: clamp((pointer.pageX - (rect.left + window.pageXOffset)) / rect.width),
@@ -46,6 +59,7 @@ const InteractiveBase = ({ onMove, onKey, ...rest }: Props) => {
4659
const container = useRef<HTMLDivElement>(null);
4760
const onMoveCallback = useEventCallback<Interaction>(onMove);
4861
const onKeyCallback = useEventCallback<Interaction>(onKey);
62+
const touchId = useRef<null | number>(null);
4963
const hasTouch = useRef(false);
5064

5165
const [handleMoveStart, handleKeyDown, toggleDocumentEvents] = useMemo(() => {
@@ -57,12 +71,15 @@ const InteractiveBase = ({ onMove, onKey, ...rest }: Props) => {
5771
preventDefaultMove(nativeEvent);
5872

5973
if (isInvalid(nativeEvent, hasTouch.current) || !el) return;
60-
hasTouch.current = isTouch(nativeEvent);
74+
if (isTouch(nativeEvent)) {
75+
hasTouch.current = true;
76+
touchId.current = nativeEvent.changedTouches[0].identifier;
77+
}
6178

6279
// The node/ref must actually exist when user start an interaction.
6380
// We won't suppress the ESLint warning though, as it should probably be something to be aware of.
6481
el.focus();
65-
onMoveCallback(getRelativePosition(el, nativeEvent));
82+
onMoveCallback(getRelativePosition(el, nativeEvent, touchId.current));
6683
toggleDocumentEvents(true);
6784
};
6885

@@ -78,7 +95,7 @@ const InteractiveBase = ({ onMove, onKey, ...rest }: Props) => {
7895
const isDown = isTouch(event) ? event.touches.length > 0 : event.buttons > 0;
7996

8097
if (isDown && container.current) {
81-
onMoveCallback(getRelativePosition(container.current, event));
98+
onMoveCallback(getRelativePosition(container.current, event, touchId.current));
8299
} else {
83100
toggleDocumentEvents(false);
84101
}

tests/components.test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ it("Doesn't call `onChange` when user changes a hue of a grayscale color", () =>
9292
const hue = container.querySelector(".react-colorful__hue .react-colorful__interactive");
9393

9494
fireEvent.touchStart(hue, {
95+
changedTouches: [{ pageX: 0, pageY: 0 }],
9596
touches: [{ pageX: 0, pageY: 0 }],
9697
});
9798
fireEvent.touchMove(hue, { touches: [{ pageX: 100, pageY: 0 }] });
@@ -119,6 +120,7 @@ it("Triggers `onChange` after a touch interaction", async () => {
119120
const hue = result.container.querySelector(".react-colorful__hue .react-colorful__interactive");
120121

121122
fireEvent.touchStart(hue, {
123+
changedTouches: [{ pageX: 0, pageY: 0 }],
122124
touches: [{ pageX: 0, pageY: 0, bubbles: true }],
123125
});
124126
fireEvent.touchMove(hue, { touches: [{ pageX: 55, pageY: 0, bubbles: true }] });
@@ -166,6 +168,7 @@ it("Doesn't react on mouse events after a touch interaction", () => {
166168
const hue = result.container.querySelector(".react-colorful__hue .react-colorful__interactive");
167169

168170
fireEvent.touchStart(hue, {
171+
changedTouches: [{ pageX: 0, pageY: 0 }],
169172
touches: [{ pageX: 0, pageY: 0, bubbles: true }],
170173
}); // 1
171174
fireEvent.touchMove(hue, { touches: [{ pageX: 55, pageY: 0, bubbles: true }] }); // 2

0 commit comments

Comments
 (0)