123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- <script lang="ts" setup>
- import { useLoop, useTresContext } from '@tresjs/core'
- import { useEventListener } from '@vueuse/core'
- import { MOUSE, TOUCH } from 'three'
- import { OrbitControls } from 'three-stdlib'
- import { onUnmounted, shallowRef, toRefs, watch } from 'vue'
- import type { TresVector3 } from '@tresjs/core'
- import type { Camera } from 'three'
- export interface OrbitControlsProps {
- /**
- * Whether to make this the default controls.
- *
- * @default false
- * @type {boolean}
- * @memberof OrbitControlsProps
- */
- makeDefault?: boolean
- /**
- * The camera to control.
- *
- * @type {Camera}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.camera
- */
- camera?: Camera
- /**
- * The dom element to listen to.
- *
- * @type {HTMLElement}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.domElement
- */
- domElement?: HTMLElement
- /**
- * The target to orbit around.
- *
- * @type {TresVector3}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.target
- */
- target?: TresVector3
- /**
- * Whether to enable damping (inertia)
- *
- * @default false
- * @type {boolean}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableDamping
- */
- enableDamping?: boolean
- /**
- * The damping inertia used if `.enableDamping` is set to true
- *
- * @default 0.05
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.dampingFactor
- */
- dampingFactor?: number
- /**
- * Set to true to automatically rotate around the target.
- *
- * @default false
- * @type {boolean}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.autoRotate
- */
- autoRotate?: boolean
- /**
- * How fast to rotate around the target if `.autoRotate` is true.
- *
- * @default 2
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.autoRotateSpeed
- */
- autoRotateSpeed?: number
- /**
- * Whether to enable panning.
- *
- * @default true
- * @type {boolean}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enablePan
- */
- enablePan?: boolean
- /**
- * How fast to pan the camera when the keyboard is used. Default is 7.0 pixels per keypress.
- *
- * @default 7.0
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.keyPanSpeed
- */
- keyPanSpeed?: number
- /**
- * This object contains references to the keycodes for controlling camera panning.
- * Default is the 4 arrow keys.
- *
- * @default `{ LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' }`
- * @type Record<string, string>
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.keys
- */
- keys?: Record<string, string>
- /**
- * How far you can orbit horizontally, upper limit.
- * If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ],
- * with ( max - min < 2 PI ). Default is Infinity.
- *
- * @default Infinity
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxAzimuthAngle
- */
- maxAzimuthAngle?: number
- /**
- * How far you can orbit horizontally, lower limit.
- * If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ],
- * with ( max - min < 2 PI ).
- * Default is - Infinity.
- *
- * @default -Infinity
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minAzimuthAngle
- */
- minAzimuthAngle?: number
- /**
- * How far you can orbit vertically, upper limit.
- * Range is 0 to Math.PI radians, and default is Math.PI.
- *
- * @default Math.PI
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxPolarAngle
- */
- maxPolarAngle?: number
- /**
- * How far you can orbit vertically, lower limit.
- * Range is 0 to Math.PI radians, and default is 0.
- *
- * @default 0
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minPolarAngle
- */
- minPolarAngle?: number
- /**
- * The minimum distance of the camera to the target.
- * Default is 0.
- *
- * @default 0
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minDistance
- */
- minDistance?: number
- /**
- * The maximum distance of the camera to the target.
- * Default is Infinity.
- *
- * @default Infinity
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxDistance
- */
- maxDistance?: number
- /**
- * The minimum field of view angle, in radians.
- * Default is 0.
- *
- * @default 0
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.minZoom
- */
- minZoom?: number
- /**
- * The maximum field of view angle, in radians.
- * ( OrthographicCamera only ).
- * Default is Infinity.
- *
- * @default Infinity
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/index.html?q=orbi#examples/en/controls/OrbitControls.maxZoom
- */
- maxZoom?: number
- touches?: {
- ONE?: number | undefined
- TWO?: number | undefined
- }
- /**
- * Whether to enable zooming.
- *
- * @default true
- * @type {boolean}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableZoom
- */
- enableZoom?: boolean
- /**
- * How fast to zoom in and out. Default is 1.
- *
- * @default 1
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.zoomSpeed
- */
- zoomSpeed?: number
- /**
- * Whether to enable rotating.
- *
- * @default true
- * @type {boolean}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.enableRotate
- */
- enableRotate?: boolean
- /**
- * How fast to rotate around the target. Default is 1.
- *
- * @default 1
- * @type {number}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.rotateSpeed
- */
- rotateSpeed?: number
- /**
- * This object contains references to the mouse actions used by the controls.
- * LEFT: Rotate around the target
- * MIDDLE: Zoom the camera
- * RIGHT: Pan the camera
- *
- * @default { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }
- * @type {{ LEFT?: number, MIDDLE?: number, RIGHT?: number }}
- * @memberof OrbitControlsProps
- * @see https://threejs.org/docs/#examples/en/controls/OrbitControls.mouseButtons
- */
- mouseButtons?: {
- LEFT?: number
- MIDDLE?: number
- RIGHT?: number
- }
- }
- const props = withDefaults(defineProps<OrbitControlsProps>(), {
- makeDefault: false,
- autoRotate: false,
- autoRotateSpeed: 2,
- enableDamping: true,
- dampingFactor: 0.05,
- enablePan: true,
- keyPanSpeed: 7,
- maxAzimuthAngle: Number.POSITIVE_INFINITY,
- minAzimuthAngle: Number.NEGATIVE_INFINITY,
- maxPolarAngle: Math.PI,
- minPolarAngle: 0,
- minDistance: 0,
- maxDistance: Number.POSITIVE_INFINITY,
- minZoom: 0,
- maxZoom: Number.POSITIVE_INFINITY,
- enableZoom: true,
- zoomSpeed: 1,
- enableRotate: true,
- touches: () => ({ ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN }),
- rotateSpeed: 1,
- target: () => [0, 0, 0],
- mouseButtons: () => ({ LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }),
- })
- const emit = defineEmits(['change', 'start', 'end'])
- const {
- makeDefault,
- autoRotate,
- autoRotateSpeed,
- enableDamping,
- dampingFactor,
- enablePan,
- keyPanSpeed,
- maxAzimuthAngle,
- minAzimuthAngle,
- maxPolarAngle,
- minPolarAngle,
- minDistance,
- maxDistance,
- minZoom,
- maxZoom,
- enableZoom,
- zoomSpeed,
- enableRotate,
- touches,
- rotateSpeed,
- target,
- mouseButtons,
- } = toRefs(props)
- const { camera: activeCamera, renderer, extend, controls, invalidate } = useTresContext()
- const controlsRef = shallowRef<OrbitControls | null>(null)
- extend({ OrbitControls })
- watch(controlsRef, (value) => {
- addEventListeners()
- if (value && makeDefault.value) {
- controls.value = value
- }
- else {
- controls.value = null
- }
- })
- function addEventListeners() {
- useEventListener(controlsRef.value as any, 'change', () => {
- emit('change', controlsRef.value)
- invalidate()
- })
- useEventListener(controlsRef.value as any, 'start', () => emit('start', controlsRef.value))
- useEventListener(controlsRef.value as any, 'end', () => emit('end', controlsRef.value))
- }
- const { onBeforeRender } = useLoop()
- onBeforeRender(({ invalidate }) => {
- if (controlsRef.value && (enableDamping.value || autoRotate.value)) {
- controlsRef.value.update()
- if (autoRotate.value) {
- invalidate()
- }
- }
- })
- onUnmounted(() => {
- if (controlsRef.value) {
- controlsRef.value.dispose()
- }
- })
- defineExpose({ instance: controlsRef })
- </script>
- <template>
- <TresOrbitControls
- v-if="(camera || activeCamera) && (domElement || renderer)"
- ref="controlsRef"
- :target="target"
- :auto-rotate="autoRotate"
- :auto-rotate-speed="autoRotateSpeed"
- :enable-damping="enableDamping"
- :damping-factor="dampingFactor"
- :enable-pan="enablePan"
- :key-pan-speed="keyPanSpeed"
- :keys="keys"
- :max-azimuth-angle="maxAzimuthAngle"
- :min-azimuth-angle="minAzimuthAngle"
- :max-polar-angle="maxPolarAngle"
- :min-polar-angle="minPolarAngle"
- :min-distance="minDistance"
- :max-distance="maxDistance"
- :min-zoom="minZoom"
- :max-zoom="maxZoom"
- :touches="touches"
- :enable-zoom="enableZoom"
- :zoom-speed="zoomSpeed"
- :enable-rotate="enableRotate"
- :rotate-speed="rotateSpeed"
- :mouse-buttons="mouseButtons"
- :args="[camera || activeCamera, domElement || renderer.domElement]"
- />
- </template>
|