88 lines
2.8 KiB
JavaScript
88 lines
2.8 KiB
JavaScript
import _extends from '@babel/runtime/helpers/esm/extends';
|
|
import * as React from 'react';
|
|
import { MathUtils } from 'three';
|
|
import { useThree } from '@react-three/fiber';
|
|
import { useSpring, a } from '@react-spring/three';
|
|
import { useGesture } from '@use-gesture/react';
|
|
|
|
function PresentationControls({
|
|
enabled = true,
|
|
snap,
|
|
global,
|
|
domElement,
|
|
cursor = true,
|
|
children,
|
|
speed = 1,
|
|
rotation = [0, 0, 0],
|
|
zoom = 1,
|
|
polar = [0, Math.PI / 2],
|
|
azimuth = [-Infinity, Infinity],
|
|
config = {
|
|
mass: 1,
|
|
tension: 170,
|
|
friction: 26
|
|
}
|
|
}) {
|
|
const events = useThree(state => state.events);
|
|
const gl = useThree(state => state.gl);
|
|
const explDomElement = domElement || events.connected || gl.domElement;
|
|
const {
|
|
size
|
|
} = useThree();
|
|
const rPolar = React.useMemo(() => [rotation[0] + polar[0], rotation[0] + polar[1]], [rotation[0], polar[0], polar[1]]);
|
|
const rAzimuth = React.useMemo(() => [rotation[1] + azimuth[0], rotation[1] + azimuth[1]], [rotation[1], azimuth[0], azimuth[1]]);
|
|
const rInitial = React.useMemo(() => [MathUtils.clamp(rotation[0], ...rPolar), MathUtils.clamp(rotation[1], ...rAzimuth), rotation[2]], [rotation[0], rotation[1], rotation[2], rPolar, rAzimuth]);
|
|
const [spring, api] = useSpring(() => ({
|
|
scale: 1,
|
|
rotation: rInitial,
|
|
config
|
|
}));
|
|
React.useEffect(() => void api.start({
|
|
scale: 1,
|
|
rotation: rInitial,
|
|
config
|
|
}), [rInitial]);
|
|
React.useEffect(() => {
|
|
if (global && cursor && enabled) {
|
|
explDomElement.style.cursor = 'grab';
|
|
gl.domElement.style.cursor = '';
|
|
return () => {
|
|
explDomElement.style.cursor = 'default';
|
|
gl.domElement.style.cursor = 'default';
|
|
};
|
|
}
|
|
}, [global, cursor, explDomElement, enabled]);
|
|
const bind = useGesture({
|
|
onHover: ({
|
|
last
|
|
}) => {
|
|
if (cursor && !global && enabled) explDomElement.style.cursor = last ? 'auto' : 'grab';
|
|
},
|
|
onDrag: ({
|
|
down,
|
|
delta: [x, y],
|
|
memo: [oldY, oldX] = spring.rotation.animation.to || rInitial
|
|
}) => {
|
|
if (!enabled) return [y, x];
|
|
if (cursor) explDomElement.style.cursor = down ? 'grabbing' : 'grab';
|
|
x = MathUtils.clamp(oldX + x / size.width * Math.PI * speed, ...rAzimuth);
|
|
y = MathUtils.clamp(oldY + y / size.height * Math.PI * speed, ...rPolar);
|
|
const sConfig = snap && !down && typeof snap !== 'boolean' ? snap : config;
|
|
api.start({
|
|
scale: down && y > rPolar[1] / 2 ? zoom : 1,
|
|
rotation: snap && !down ? rInitial : [y, x, 0],
|
|
config: n => n === 'scale' ? {
|
|
...sConfig,
|
|
friction: sConfig.friction * 3
|
|
} : sConfig
|
|
});
|
|
return [y, x];
|
|
}
|
|
}, {
|
|
target: global ? explDomElement : undefined
|
|
});
|
|
return /*#__PURE__*/React.createElement(a.group, _extends({}, bind == null ? void 0 : bind(), spring), children);
|
|
}
|
|
|
|
export { PresentationControls };
|