File size: 3,027 Bytes
b7ed1ef | 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 109 110 | import { ref, watch } from 'vue'
import { CameraWidget } from '../CameraWidget'
import type { CameraState } from '../types'
export function useCameraWidget(
initialState: Partial<CameraState> = {},
onExternalStateChange?: (state: CameraState) => void
) {
const azimuth = ref(initialState.azimuth ?? 0)
const elevation = ref(initialState.elevation ?? 0)
const distance = ref(initialState.distance ?? 5)
const imageUrl = ref<string | null>(null)
const prompt = ref('<sks> front view eye-level shot medium shot')
let widget: CameraWidget | null = null
let updatingFromWidget = false
let updatingFromExternal = false
function notifyParent() {
onExternalStateChange?.({
azimuth: azimuth.value,
elevation: elevation.value,
distance: distance.value,
imageUrl: imageUrl.value
})
}
function initScene(container: HTMLElement) {
widget = new CameraWidget({
container,
initialState: {
azimuth: azimuth.value,
elevation: elevation.value,
distance: distance.value
},
onStateChange: (state: CameraState) => {
updatingFromWidget = true
azimuth.value = state.azimuth
elevation.value = state.elevation
distance.value = state.distance
prompt.value = widget!.generatePrompt()
updatingFromWidget = false
notifyParent()
}
})
prompt.value = widget.generatePrompt()
}
watch([azimuth, elevation, distance], () => {
if (!updatingFromWidget && !updatingFromExternal && widget) {
widget.setState({
azimuth: azimuth.value,
elevation: elevation.value,
distance: distance.value
})
prompt.value = widget.generatePrompt()
notifyParent()
}
}, { flush: 'sync' })
function setState(state: Partial<CameraState>) {
updatingFromExternal = true
if (state.azimuth !== undefined) azimuth.value = state.azimuth
if (state.elevation !== undefined) elevation.value = state.elevation
if (state.distance !== undefined) distance.value = state.distance
widget?.setState(state)
if (widget) prompt.value = widget.generatePrompt()
updatingFromExternal = false
}
function updateImage(url: string | null) {
imageUrl.value = url
widget?.updateImage(url)
}
function setCameraView(enabled: boolean) {
widget?.setCameraView(enabled)
}
function reset() {
updatingFromExternal = true
azimuth.value = 0
elevation.value = 0
distance.value = 5
updatingFromExternal = false
widget?.setState({ azimuth: 0, elevation: 0, distance: 5 })
if (widget) prompt.value = widget.generatePrompt()
notifyParent()
}
function cleanup() {
widget?.dispose()
widget = null
}
return {
azimuth,
elevation,
distance,
imageUrl,
prompt,
initScene,
setState,
updateImage,
setCameraView,
reset,
cleanup
}
}
|