forked from pmndrs/drei
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOrbitControls.tsx
108 lines (95 loc) · 3.51 KB
/
OrbitControls.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { EventManager, ReactThreeFiber, useFrame, useThree } from '@react-three/fiber'
import * as React from 'react'
import type { Camera, Event } from 'three'
import { OrbitControls as OrbitControlsImpl } from 'three-stdlib'
import { ForwardRefComponent } from '../helpers/ts-utils'
export type OrbitControlsChangeEvent = Event & {
target: EventTarget & { object: Camera }
}
export type OrbitControlsProps = Omit<
ReactThreeFiber.Overwrite<
ReactThreeFiber.Object3DNode<OrbitControlsImpl, typeof OrbitControlsImpl>,
{
camera?: Camera
domElement?: HTMLElement
enableDamping?: boolean
makeDefault?: boolean
onChange?: (e?: OrbitControlsChangeEvent) => void
onEnd?: (e?: Event) => void
onStart?: (e?: Event) => void
regress?: boolean
target?: ReactThreeFiber.Vector3
keyEvents?: boolean | HTMLElement
}
>,
'ref'
>
export const OrbitControls: ForwardRefComponent<OrbitControlsProps, OrbitControlsImpl> =
/* @__PURE__ */ React.forwardRef<OrbitControlsImpl, OrbitControlsProps>(
(
{
makeDefault,
camera,
regress,
domElement,
enableDamping = true,
keyEvents = false,
onChange,
onStart,
onEnd,
...restProps
},
ref
) => {
const invalidate = useThree((state) => state.invalidate)
const defaultCamera = useThree((state) => state.camera)
const gl = useThree((state) => state.gl)
const events = useThree((state) => state.events) as EventManager<HTMLElement>
const setEvents = useThree((state) => state.setEvents)
const set = useThree((state) => state.set)
const get = useThree((state) => state.get)
const performance = useThree((state) => state.performance)
const explCamera = (camera || defaultCamera) as THREE.OrthographicCamera | THREE.PerspectiveCamera
const explDomElement = (domElement || events.connected || gl.domElement) as HTMLElement
const controls = React.useMemo(() => new OrbitControlsImpl(explCamera), [explCamera])
useFrame(() => {
if (controls.enabled) controls.update()
}, -1)
React.useEffect(() => {
if (keyEvents) {
controls.connect(keyEvents === true ? explDomElement : keyEvents)
}
controls.connect(explDomElement)
return () => void controls.dispose()
}, [keyEvents, explDomElement, regress, controls, invalidate])
React.useEffect(() => {
const callback = (e: OrbitControlsChangeEvent) => {
invalidate()
if (regress) performance.regress()
if (onChange) onChange(e)
}
const onStartCb = (e: Event) => {
if (onStart) onStart(e)
}
const onEndCb = (e: Event) => {
if (onEnd) onEnd(e)
}
controls.addEventListener('change', callback)
controls.addEventListener('start', onStartCb)
controls.addEventListener('end', onEndCb)
return () => {
controls.removeEventListener('start', onStartCb)
controls.removeEventListener('end', onEndCb)
controls.removeEventListener('change', callback)
}
}, [onChange, onStart, onEnd, controls, invalidate, setEvents])
React.useEffect(() => {
if (makeDefault) {
const old = get().controls
set({ controls })
return () => set({ controls: old })
}
}, [makeDefault, controls])
return <primitive ref={ref} object={controls} enableDamping={enableDamping} {...restProps} />
}
)