association.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import { sdk } from './sdk'
  2. import { models, isEdit, sysBus, getModelShowVariable, ModelType, backupModels } from '@/store'
  3. import { toRaw, watchEffect, ref, watch, createApp } from 'vue'
  4. import { viewModeStack, custom, getResource, showRightCtrlPanoStack } from '@/env'
  5. import {
  6. diffArrayChange,
  7. shallowWatchArray,
  8. arrayChildEffectScope,
  9. togetherCallback,
  10. showLoad,
  11. hideLoad
  12. } from '@/utils'
  13. import SDKApp from './index.vue'
  14. import Components from 'bill/index'
  15. import { Model } from '@/store'
  16. import type { SDK, SceneModel, SceneGuidePath, ModelAttrRange } from '.'
  17. export const modelRange: ModelAttrRange = {
  18. opacityRange: { min: 0, max: 100, step: 0.1 },
  19. bottomRange: { min: -30, max: 70, step: 0.1 },
  20. scaleRange: { min: 0, max: 200, step: 0.1 }
  21. }
  22. const sceneModelMap = new WeakMap<Model, SceneModel>()
  23. export const getSceneModel = (model: Model | null) => model && sceneModelMap.get(toRaw(model))
  24. const associationModels = (sdk: SDK) => {
  25. const getModels = () => models.value
  26. shallowWatchArray(getModels, (models, oldModels) => {
  27. const { added, deleted } = diffArrayChange(models, oldModels)
  28. for (const item of added) {
  29. if (getSceneModel(item)) {
  30. continue;
  31. }
  32. const itemRaw = toRaw(item)
  33. console.log('加载模型', {
  34. ...itemRaw,
  35. ...modelRange,
  36. url: getResource(item.url)
  37. })
  38. const sceneModel = sdk.addModel({
  39. ...itemRaw,
  40. ...modelRange,
  41. // type: ModelType.SWMX,
  42. url: getResource(item.url)
  43. })
  44. sceneModelMap.set(itemRaw, sceneModel)
  45. sceneModel.bus.on('transformChanged', transform => {
  46. Object.assign(item, transform)
  47. })
  48. sceneModel.bus.on('changeSelect', select => {
  49. if (custom.currentModel === item && !select) {
  50. custom.currentModel = null
  51. } else if (custom.currentModel !== item && select) {
  52. custom.currentModel = item
  53. }
  54. })
  55. showLoad()
  56. sceneModel.bus.on('loadDone', () => {
  57. item.loaded = true
  58. backupModels()
  59. hideLoad()
  60. })
  61. sceneModel.bus.on('loadError', () => {
  62. item.error = true
  63. item.show = false
  64. custom.showModelsMap.delete(item)
  65. hideLoad()
  66. })
  67. sceneModel.bus.on('loadProgress', progress => item.progress = progress)
  68. }
  69. for (const item of deleted) {
  70. getSceneModel(item)?.destroy()
  71. }
  72. })
  73. arrayChildEffectScope(getModels, item => {
  74. const stopLoadedWatch = watch(
  75. () => item.loaded,
  76. (loaded) => {
  77. if (loaded) {
  78. const modelShow = getModelShowVariable(item)
  79. watchEffect(() => {
  80. getSceneModel(item)?.changeBottom(item.bottom)
  81. })
  82. watchEffect(() => getSceneModel(item)?.changeOpacity(item.opacity))
  83. watchEffect(() => getSceneModel(item)?.changeScale(item.scale))
  84. watchEffect(() => {
  85. console.error(getSceneModel(item), 'changeshow', modelShow.value)
  86. getSceneModel(item)?.changeShow(modelShow.value)
  87. })
  88. stopLoadedWatch()
  89. }
  90. }
  91. )
  92. })
  93. }
  94. const fullView = async (fn: () => void) => {
  95. const pop = togetherCallback([
  96. viewModeStack.push(ref('full')),
  97. showRightCtrlPanoStack.push(ref(false))
  98. ])
  99. await document.documentElement.requestFullscreen()
  100. const driving = () => document.fullscreenElement || fn()
  101. document.addEventListener('fullscreenchange', driving)
  102. document.addEventListener('fullscreenerror', fn)
  103. return () => {
  104. pop()
  105. document.fullscreenElement && document.exitFullscreen()
  106. document.removeEventListener('fullscreenchange', driving)
  107. document.removeEventListener('fullscreenerror', fn)
  108. }
  109. }
  110. export const isScenePlayIng = ref(false)
  111. export const playSceneGuide = async (paths: SceneGuidePath[], changeIndexCallback?: (index: number) => void) => {
  112. if (isScenePlayIng.value) {
  113. throw new Error('导览正在播放')
  114. }
  115. isScenePlayIng.value = true
  116. const sceneGuide = sdk.enterSceneGuide(paths)
  117. changeIndexCallback && sceneGuide.bus.on('changePoint', changeIndexCallback)
  118. const quitHandler = () => (isScenePlayIng.value = false)
  119. const clearHandler = isEdit.value ? null : await fullView(quitHandler)
  120. if (!clearHandler) {
  121. sysBus.on('leave', quitHandler, { last: true })
  122. sysBus.on('save', quitHandler, { last: true })
  123. }
  124. sceneGuide.play()
  125. const reces = [
  126. new Promise(resolve => sceneGuide.bus.on('playComplete', resolve)),
  127. new Promise<void>(resolve => {
  128. const stop = watch(isScenePlayIng, () => {
  129. if (!isScenePlayIng.value) {
  130. resolve()
  131. sceneGuide.pause()
  132. stop()
  133. }
  134. })
  135. }),
  136. ]
  137. await Promise.race(reces)
  138. isScenePlayIng.value = false
  139. if (clearHandler) {
  140. clearHandler()
  141. } else {
  142. sysBus.off('leave', quitHandler)
  143. sysBus.off('save', quitHandler)
  144. }
  145. sceneGuide.clear()
  146. sceneGuide.bus.off('changePoint')
  147. }
  148. export const pauseSceneGuide = () => isScenePlayIng.value = false
  149. export const setupAssociation = (mountEl: HTMLDivElement) => {
  150. associationModels(sdk)
  151. const sdkApp = createApp(SDKApp)
  152. sdkApp.mount(mountEl)
  153. sdkApp.use(Components)
  154. }