Skip to content

Commit

Permalink
fix: exaggerate pointer exit listener on mouseout to account for hita…
Browse files Browse the repository at this point in the history
…reas too close to the artboard border

[Bug reported](https://2dimensions.slack.com/archives/CLLCU09T6/p1699924347919509) where hitareas for a listener ~2px away from the Artboard border were not getting their `pointer exit` listener invoked. There seems to be a small rounding issue when taking into account the [2px hitRadius](https://github.com/rive-app/rive-cpp/blob/master/src/animation/state_machine_instance.cpp#L336) we use downstream that doesn't invoke the pointer exit accordingly.

Flutter web doesn't have this issue because it taps out early before doing this hitRadius detection by doing a check first on the shape's bounds (which [doesn't exist](https://github.com/rive-app/rive-cpp/blob/master/src/animation/state_machine_instance.cpp#L346) in C++).

Adding a large buffer to the coordinates when the user "mouseout"'s the canvas to ensure we report the user has effectively `pointer exit`'d. We can't just add/subtract 2 here because if for example, Rive is setup with `fit: cover`, it expands the rive graphic potentially past the canvas bounds. Open to other suggestions here

Diffs=
f0ca1b0ef fix: exaggerate pointer exit listener on mouseout to account for hitareas too close to the artboard border (#6319)

Co-authored-by: Zachary Plata <plata.zach@gmail.com>
  • Loading branch information
zplata and zplata committed Dec 8, 2023
1 parent 64c935e commit b831f39
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
53972cc17b532e83ffee7cae7d3420e95f822e8f
f0ca1b0ef3052ecb92f5bf6ca8411e85d4368e86
22 changes: 21 additions & 1 deletion js/src/utils/registerTouchInteractions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,30 @@ export const registerTouchInteractions = ({
forwardMatrix.delete();

switch (event.type) {
/**
* There's a 2px buffer for a hitRadius when translating the pointer coordinates
* down to the state machine. In cases where the hitbox is about that much away
* from the Artboard border, we don't have exact precision on determining pointer
* exit. We're therefore adding to the translated coordinates on mouseout of a canvas
* to ensure that we report the mouse has truly exited the hitarea.
* https://github.com/rive-app/rive-cpp/blob/master/src/animation/state_machine_instance.cpp#L336
*
* We add/subtract 10000 to account for when the graphic goes beyond the canvas bound
* due to for example, a fit: 'cover'. Not perfect, but helps reliably (for now) ensure
* we report going out of bounds when the mouse is out of the canvas
*/
case "mouseout":
for (const stateMachine of stateMachines) {
stateMachine.pointerMove(
transformedX < 0 ? transformedX - 10000 : transformedX + 10000,
transformedY < 0 ? transformedY - 10000 : transformedY + 10000
);
}
break;

// Pointer moving/hovering on the canvas
case "touchmove":
case "mouseover":
case "mouseout":
case "mousemove": {
for (const stateMachine of stateMachines) {
stateMachine.pointerMove(transformedX, transformedY);
Expand Down
13 changes: 13 additions & 0 deletions js/test/registerTouchInteractions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,16 @@ test("touchend event can invoke pointerUp", (): void => {
expect(mockStateMachines[0].pointerMove).not.toBeCalledWith();
expect(mockStateMachines[0].pointerUp).toBeCalledWith(100, 100);
});

test("mouseout event can invoke pointerMove with out of bounds coordinates", (): void => {
canvas.dispatchEvent(
new MouseEvent("mouseout", {
clientX: -1,
clientY: 1,
})
);

expect(mockStateMachines[0].pointerDown).not.toBeCalled();
expect(mockStateMachines[0].pointerMove).toBeCalledWith(-10001, 10001);
expect(mockStateMachines[0].pointerUp).not.toBeCalled();
});

0 comments on commit b831f39

Please sign in to comment.