@react-three/drei
Version:
useful add-ons for react-three-fiber
90 lines (86 loc) • 3.09 kB
JavaScript
import _extends from '@babel/runtime/helpers/esm/extends';
import { useThree } from '@react-three/fiber';
import * as React from 'react';
import { PointerLockControls as PointerLockControls$1 } from 'three-stdlib';
const PointerLockControls = /* @__PURE__ */React.forwardRef(({
domElement,
selector,
onChange,
onLock,
onUnlock,
enabled = true,
makeDefault,
...props
}, ref) => {
const {
camera,
...rest
} = props;
const setEvents = useThree(state => state.setEvents);
const gl = useThree(state => state.gl);
const defaultCamera = useThree(state => state.camera);
const invalidate = useThree(state => state.invalidate);
const events = useThree(state => state.events);
const get = useThree(state => state.get);
const set = useThree(state => state.set);
const explCamera = camera || defaultCamera;
const explDomElement = domElement || events.connected || gl.domElement;
const controls = React.useMemo(() => new PointerLockControls$1(explCamera), [explCamera]);
React.useEffect(() => {
if (enabled) {
controls.connect(explDomElement);
// Force events to be centered while PLC is active
const oldComputeOffsets = get().events.compute;
setEvents({
compute(event, state) {
const offsetX = state.size.width / 2;
const offsetY = state.size.height / 2;
state.pointer.set(offsetX / state.size.width * 2 - 1, -(offsetY / state.size.height) * 2 + 1);
state.raycaster.setFromCamera(state.pointer, state.camera);
}
});
return () => {
controls.disconnect();
setEvents({
compute: oldComputeOffsets
});
};
}
}, [enabled, controls]);
React.useEffect(() => {
const callback = e => {
invalidate();
if (onChange) onChange(e);
};
controls.addEventListener('change', callback);
if (onLock) controls.addEventListener('lock', onLock);
if (onUnlock) controls.addEventListener('unlock', onUnlock);
// Enforce previous interaction
const handler = () => controls.lock();
const elements = selector ? Array.from(document.querySelectorAll(selector)) : [document];
elements.forEach(element => element && element.addEventListener('click', handler));
return () => {
controls.removeEventListener('change', callback);
if (onLock) controls.removeEventListener('lock', onLock);
if (onUnlock) controls.removeEventListener('unlock', onUnlock);
elements.forEach(element => element ? element.removeEventListener('click', handler) : undefined);
};
}, [onChange, onLock, onUnlock, selector, controls, invalidate]);
React.useEffect(() => {
if (makeDefault) {
const old = get().controls;
// @ts-ignore https://github.com/three-types/three-ts-types/pull/1398
set({
controls
});
return () => set({
controls: old
});
}
}, [makeDefault, controls]);
return /*#__PURE__*/React.createElement("primitive", _extends({
ref: ref,
object: controls
}, rest));
});
export { PointerLockControls };