mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
100.38k stars 35.2k forks source link

OrbitControls doesn't detect pointerup when off the DOM element #24566

Open MixMasterMitch opened 1 year ago

MixMasterMitch commented 1 year ago

Describe the bug The OrbitControls continue to manipulate the camera if a click+drag is released outside of the OrbitControls' DOM element.

To Reproduce Steps to reproduce the behavior:

  1. Go to any three.js scene using OrbitControls, such as https://threejs.org/examples/#webgl_animation_keyframes
  2. Click and drag starting in the scene and release the click with the cursor out of the scene.
  3. Return the cursor to the scene without clicking and observe that the camera is still being controlled by the cursor movements.

Expected behavior I would expect the camera to no longer be rotated by the cursor after releasing the click.

Platform:

MixMasterMitch commented 1 year ago

I have hacked around this with code like this:

window.addEventListener('pointerup', (event) => {
    const clone = new event.constructor(event.type, { pointerId: event.pointerId, bubbles: false });
    document.getElementsByTagName('canvas')[0].dispatchEvent(clone); 
})
Mugen87 commented 1 year ago

Strange, I can't reproduce this with Chrome on macOS. Is there something else I have to look for?

VanderSP commented 1 year ago

and if instead you listen to window you listen to document?

arodic commented 1 year ago

Strange, I can't reproduce this with Chrome on macOS. Is there something else I have to look for?

I was able to reproduce on Chrome/MacOS with middle mouse button (dolly).

Mugen87 commented 1 year ago

I can reproduce with the middle mouse button, too. It would be interesting to know why left/right and middle mouse button behave differently.

It seems a simple fix is adding this to OrbitControls:

scope.domElement.addEventListener( 'pointerleave', onPointerUp );

@MixMasterMitch Can you please check if this would work for you?

Tinoooo commented 1 year ago

Faking a mouse event in the canvas turned out to be a workaround for me.

document.addEventListener('pointerleave', () => {
  canvas.dispatchEvent(new MouseEvent('pointerup'))
})
snosenzo commented 1 year ago

I'm seeing this behavior with Chrome on MacOS: Left-click drags to and releasing outside window fire a pointerup normally. However when releasing a right click drag outside of the page, no pointerup is being fired. Then subsequent left click drag and release outside of the canvas no longer fire pointerup. Also pointermove events outside of the canvas are no longer firing for either type of click.

This is not the behavior in Safari or Firefox however, so it might be just a Chrome bug

wnr commented 4 months ago

I too can reproduce it with Chrome on MacOS.