@realsee/vreo 0.1.6 → 0.2.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +103 -16
  2. package/docs/assets/custom.css +4 -4
  3. package/docs/assets/search.js +1 -1
  4. package/docs/classes/Player.Controller.html +54 -0
  5. package/docs/classes/Player.Player-1.html +11 -11
  6. package/docs/classes/Player.VideoAgentMesh.html +142 -0
  7. package/docs/classes/Player.VideoAgentScene.html +1 -0
  8. package/docs/enums/Player.InfoPanelStyleEnum.html +1 -0
  9. package/docs/enums/Player.InfoPanelTypeEnum.html +1 -1
  10. package/docs/enums/Player.PanoEffectEnum.html +2 -2
  11. package/docs/enums/Player.PanoTagEnum.html +1 -1
  12. package/docs/enums/Player.VreoKeyframeEnum.html +14 -12
  13. package/docs/enums/fivePlugins.CameraMovementEffect.html +1 -1
  14. package/docs/enums/fivePlugins.Rotation.html +1 -1
  15. package/docs/index.html +52 -19
  16. package/docs/interfaces/Player.CustomVreoKeyframeProps.html +1 -0
  17. package/docs/interfaces/Player.PlayerConfigs.html +4 -2
  18. package/docs/interfaces/Player.Vertex.html +1 -1
  19. package/docs/interfaces/Player.VideoAgentMeshOptions.html +1 -0
  20. package/docs/interfaces/Player.VreoKeyframe.html +1 -1
  21. package/docs/interfaces/Player.VreoUnit.html +1 -1
  22. package/docs/interfaces/Player.VreoVideo.html +1 -1
  23. package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +1 -1
  24. package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +3 -3
  25. package/docs/interfaces/fivePlugins.CameraMovementPluginParameterType.html +1 -1
  26. package/docs/interfaces/fivePlugins.ModelTVVideoPluginData.html +1 -1
  27. package/docs/interfaces/fivePlugins.ModelTVVideoPluginExportType.html +1 -1
  28. package/docs/interfaces/fivePlugins.ModelTVVideoPluginParameterType.html +1 -1
  29. package/docs/interfaces/react.VreoActionCallbacks.html +15 -7
  30. package/docs/interfaces/react.VreoProviderProps.html +1 -0
  31. package/docs/modules/Player.html +17 -15
  32. package/docs/modules/custom.html +3 -0
  33. package/docs/modules/fivePlugins.html +2 -2
  34. package/docs/modules/react.html +1 -1
  35. package/docs/modules.html +1 -1
  36. package/lib/PlayController/createHTMLAudioElement.d.ts +1 -0
  37. package/lib/PlayController/createHTMLAudioElement.js +47 -0
  38. package/lib/PlayController/index.d.ts +38 -0
  39. package/lib/PlayController/index.js +300 -0
  40. package/lib/Player/App.js +8 -3
  41. package/lib/Player/Controller.d.ts +2 -0
  42. package/lib/Player/Controller.js +14 -0
  43. package/lib/Player/custom/SpatialScenePanel/index.d.ts +22 -0
  44. package/lib/Player/custom/SpatialScenePanel/index.js +279 -0
  45. package/lib/Player/index.d.ts +1 -1
  46. package/lib/Player/index.js +98 -11
  47. package/lib/Player/modules/Drawer/index.js +1 -1
  48. package/lib/Player/modules/PopUp/index.d.ts +2 -0
  49. package/lib/Player/modules/PopUp/index.js +43 -0
  50. package/lib/Player/modules/VideoAgent/VideoAgentMesh.d.ts +1 -0
  51. package/lib/Player/modules/VideoAgent/VideoAgentMesh.js +6 -2
  52. package/lib/Player/modules/VideoAgent/VideoAgentScene.d.ts +4 -1
  53. package/lib/Player/modules/VideoAgent/VideoAgentScene.js +21 -6
  54. package/lib/Player/modules/VideoAgent/index.d.ts +2 -0
  55. package/lib/Player/modules/VideoAgent/index.js +1 -1
  56. package/lib/Player/modules/keyframes/BgMusic/index.d.ts +2 -0
  57. package/lib/Player/modules/keyframes/BgMusic/index.js +76 -0
  58. package/lib/Player/modules/keyframes/CameraMovement/index.js +41 -5
  59. package/lib/Player/modules/keyframes/InfoPanel/index.js +105 -23
  60. package/lib/Player/modules/keyframes/ModelVideo/index.js +47 -10
  61. package/lib/Player/modules/keyframes/PanoTextLabel/index.js +4 -12
  62. package/lib/Player/modules/keyframes/Prompter/index.js +4 -18
  63. package/lib/Player/modules/keyframes/UpdateVRPanorama/index.js +71 -12
  64. package/lib/Player/typings.d.ts +19 -1
  65. package/lib/fivePlugins/CameraMovementPlugin/index.js +104 -90
  66. package/lib/fivePlugins/CameraMovementPlugin/typings.d.ts +1 -0
  67. package/lib/react/index.d.ts +10 -2
  68. package/lib/react/index.js +1 -1
  69. package/lib/shared-utils/createTransMatrix.d.ts +1 -0
  70. package/lib/shared-utils/createTransMatrix.js +43 -0
  71. package/lib/typings/VreoUnit.d.ts +47 -7
  72. package/lib/typings/VreoUnit.js +15 -6
  73. package/package.json +6 -6
  74. package/resources/PlayController/createHTMLAudioElement.ts +53 -0
  75. package/resources/PlayController/index.ts +167 -0
  76. package/resources/Player/App.tsx +6 -1
  77. package/resources/Player/Controller.ts +12 -0
  78. package/resources/Player/custom/SpatialScenePanel/index.tsx +264 -0
  79. package/resources/Player/index.tsx +56 -2
  80. package/resources/Player/modules/Drawer/index.tsx +1 -1
  81. package/resources/Player/modules/PopUp/index.tsx +26 -0
  82. package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +5 -4
  83. package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +11 -2
  84. package/resources/Player/modules/VideoAgent/index.tsx +3 -2
  85. package/resources/Player/modules/keyframes/BgMusic/index.tsx +66 -0
  86. package/resources/Player/modules/keyframes/CameraMovement/index.tsx +7 -3
  87. package/resources/Player/modules/keyframes/InfoPanel/index.tsx +109 -11
  88. package/resources/Player/modules/keyframes/ModelVideo/index.tsx +38 -5
  89. package/resources/Player/modules/keyframes/PanoTextLabel/index.tsx +2 -2
  90. package/resources/Player/modules/keyframes/Prompter/index.tsx +5 -15
  91. package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +75 -12
  92. package/resources/Player/typings.ts +21 -1
  93. package/resources/fivePlugins/CameraMovementPlugin/index.ts +59 -48
  94. package/resources/fivePlugins/CameraMovementPlugin/typings.ts +2 -1
  95. package/resources/react/index.tsx +12 -3
  96. package/resources/shared-utils/createTransMatrix.ts +12 -0
  97. package/resources/typings/VreoUnit.ts +56 -7
  98. package/stylesheets/custom/SpatialScenePanel.css +309 -0
  99. package/stylesheets/default.css +127 -9
@@ -0,0 +1,167 @@
1
+ import { Subscribe } from '@realsee/five'
2
+ import { requestAnimationFrameInterval } from '../shared-utils/animationFrame'
3
+ import { VreoKeyframe, VreoKeyframeEvent, VreoUnit } from '../typings/VreoUnit'
4
+ import { createHTMLAudioElement } from './createHTMLAudioElement'
5
+
6
+ export interface PlayControllerConfig {
7
+ audio?: HTMLAudioElement
8
+ }
9
+
10
+ const closures: Record<string, any> = {}
11
+
12
+ export class PlayController extends Subscribe<VreoKeyframeEvent> {
13
+
14
+ vreoUnit?: VreoUnit
15
+
16
+ config: PlayControllerConfig = {}
17
+ stopInterval: () => void
18
+
19
+ get paused() {
20
+ return this.audioInstance.paused
21
+ }
22
+
23
+ get audioInstance() {
24
+ return this.config.audio!
25
+ }
26
+
27
+ get currentTime() {
28
+ return this.audioInstance.currentTime * 1000
29
+ }
30
+
31
+ get currentKeyframes() {
32
+ if (!this.vreoUnit) return []
33
+ const keyframes = this.vreoUnit.keyframes
34
+ // 没有被解析过且开始时间低于当前时间戳 100ms
35
+ return keyframes.filter((keyframe: VreoKeyframe) => {
36
+ if (keyframe.parsed) return false
37
+ const dur = this.currentTime - keyframe.start
38
+ return dur <= 100 && dur >= 0
39
+ })
40
+ }
41
+
42
+ /**
43
+ * 音频时长 不一定能获取得到,建议以 VreoUnit 配置的时长为准。
44
+ */
45
+ get duration() {
46
+ return this.audioInstance.duration * 1000
47
+ }
48
+
49
+ constructor(config: PlayControllerConfig = {}) {
50
+ super()
51
+
52
+ if (!config.audio) {
53
+ config.audio = createHTMLAudioElement()
54
+ }
55
+
56
+ this.config = Object.assign(this.config, config)
57
+
58
+ closures.onPlaying = () => this.emit('playing')
59
+ closures.onPaused = () => this.emit('paused')
60
+ closures.onEnded = () => this.emit('paused', true)
61
+
62
+ this.audioInstance.addEventListener('play', closures.onPlaying)
63
+ this.audioInstance.addEventListener('pause', closures.onPaused)
64
+ this.audioInstance.addEventListener('ended', closures.onEnded)
65
+
66
+ this.stopInterval = requestAnimationFrameInterval(() => {
67
+ if (this.audioInstance.paused) {
68
+ return
69
+ }
70
+
71
+ if (!this.vreoUnit) {
72
+ return
73
+ }
74
+
75
+ const keyframes = this.vreoUnit.keyframes
76
+ const currentTime = this.currentTime
77
+ // 没有被解析过且开始时间低于当前时间戳 100ms
78
+ const currentKeyframes = keyframes.filter((keyframe: VreoKeyframe) => {
79
+ if (keyframe.parsed) return false
80
+
81
+ const dur = currentTime - keyframe.start
82
+ return dur <= 60 && dur >= 0
83
+ })
84
+
85
+ currentKeyframes.forEach((keyframe) => {
86
+ if (keyframe.parsed) return
87
+ keyframe.parsed = true
88
+ this.emit(keyframe.type, keyframe)
89
+ })
90
+ })
91
+
92
+ }
93
+
94
+
95
+
96
+ /**
97
+ * 载入数据
98
+ */
99
+ async load(vreoUnit: VreoUnit): Promise<boolean> {
100
+ this.vreoUnit = vreoUnit
101
+
102
+ await this.pause()
103
+ return await new Promise((resolve, reject) => {
104
+ if (vreoUnit.video.url === this.audioInstance.src) {
105
+ return resolve(true)
106
+ }
107
+
108
+ this.audioInstance.src = vreoUnit.video.url
109
+ const canplaythrough = () => {
110
+ resolve(true)
111
+ this.audioInstance.removeEventListener('canplaythrough', canplaythrough)
112
+ }
113
+ const error = (err: any) => {
114
+ reject(err)
115
+ this.audioInstance.removeEventListener('error', error)
116
+ }
117
+ this.audioInstance.addEventListener('canplaythrough', canplaythrough)
118
+ this.audioInstance.addEventListener('error', error)
119
+ })
120
+ }
121
+
122
+ /**
123
+ * 播放
124
+ */
125
+ async play() {
126
+ closures.playPromise = this.audioInstance.play()
127
+ }
128
+
129
+ /**
130
+ * 暂停
131
+ */
132
+ async pause() {
133
+ if (closures.playPromise) {
134
+ await closures.playPromise
135
+ }
136
+ this.audioInstance.pause()
137
+ }
138
+
139
+ /**
140
+ * 销毁资源
141
+ * @notice 一旦销毁,创建的实例将不可用:需重新创建实例。
142
+ *
143
+ * @deprecated **慎重执行**
144
+ */
145
+ dispose() {
146
+ // 清理事件监听
147
+ this.audioInstance.removeEventListener('play', closures.onPlaying)
148
+ this.audioInstance.removeEventListener('pasue', closures.onPaused)
149
+ this.audioInstance.removeEventListener('ended', closures.onEnded)
150
+ if (this.stopInterval) {
151
+ this.stopInterval()
152
+ }
153
+ }
154
+ }
155
+
156
+ console.log(`
157
+
158
+ ┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━
159
+ ┃┏━┓┃━━━━━━━━━┃┃━━━━━━━━━━━━━
160
+ ┃┗━┛┃┏━━┓┏━━┓━┃┃━┏━━┓┏━━┓┏━━┓
161
+ ┃┏┓┏┛┃┏┓┃┗━┓┃━┃┃━┃━━┫┃┏┓┃┃┏┓┃
162
+ ┃┃┃┗┓┃┃━┫┃┗┛┗┓┃┗┓┣━━┃┃┃━┫┃┃━┫
163
+ ┗┛┗━┛┗━━┛┗━━━┛┗━┛┗━━┛┗━━┛┗━━┛
164
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
165
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
166
+
167
+ `)
@@ -2,7 +2,7 @@ import * as React from 'react'
2
2
  import classNames from 'classnames'
3
3
  import { observer } from 'mobx-react'
4
4
  import { Controller } from './Controller'
5
- import { useController } from './hooks'
5
+ import { useController, useFiveInstance } from './hooks'
6
6
  import { CameraMovement } from './modules/keyframes/CameraMovement'
7
7
  import { InfoPanel } from './modules/keyframes/InfoPanel'
8
8
  import { ModelVideo } from './modules/keyframes/ModelVideo'
@@ -13,8 +13,10 @@ import { Prompter } from './modules/keyframes/Prompter'
13
13
  import { UpdateVRPanorama } from './modules/keyframes/UpdateVRPanorama'
14
14
  import { VideoEffect } from './modules/keyframes/VideoEffect'
15
15
  import { VideoAgent } from './modules/VideoAgent'
16
+ import { BgMusic } from './modules/keyframes/BgMusic'
16
17
 
17
18
  const AppView = observer(({ controller }: { controller: Controller }) => {
19
+
18
20
  return (
19
21
  <div
20
22
  className={classNames('vreo-panel', {
@@ -33,8 +35,10 @@ const AppView = observer(({ controller }: { controller: Controller }) => {
33
35
  controller.setPlaying(true)
34
36
  }
35
37
  }}
38
+ options={controller.configs?.videoAgentMeshOptions || {}}
36
39
  />
37
40
  <Prompter />
41
+ {controller.configs?.customPanelChildren}
38
42
  </div>
39
43
  </div>
40
44
  )
@@ -53,6 +57,7 @@ export function App() {
53
57
  <PanoTextLabel />
54
58
  <InfoPanel />
55
59
  <PanoEffect />
60
+ <BgMusic />
56
61
  </>
57
62
  <AppView controller={controller} />
58
63
  </>
@@ -24,6 +24,16 @@ export class Controller extends Subscribe<VreoKeyframeEvent> {
24
24
  return !this.videoAgentScene?.videoAgentMesh.videoUrl?.endsWith('.mp4')
25
25
  }
26
26
 
27
+ popUp: string | JSX.Element | null = null
28
+
29
+ openPopUp(popUp: string | JSX.Element | false) {
30
+ if (!popUp) {
31
+ this.popUp = null
32
+ return
33
+ }
34
+ this.popUp = popUp
35
+ }
36
+
27
37
  drawerConfig: {
28
38
  content: string | JSX.Element
29
39
  height?: number | string
@@ -57,6 +67,8 @@ export class Controller extends Subscribe<VreoKeyframeEvent> {
57
67
  setVisible: action,
58
68
  playing: observable,
59
69
  setPlaying: action,
70
+ popUp: observable.ref,
71
+ openPopUp: action,
60
72
  drawerConfig: observable.ref,
61
73
  openDrawer: action,
62
74
  })
@@ -0,0 +1,264 @@
1
+ import * as React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+ import { Five } from '@realsee/five'
4
+ import * as THREE from 'three'
5
+ import { Object3D, Raycaster, Vector3 } from 'three'
6
+ import { tweenProgress } from '@realsee/dnalogel/shared-utils/animationFrame/BetterTween'
7
+ import { CSS3DRenderPlugin, CSS3DRenderPluginExportType } from '@realsee/dnalogel/plugins/CSS3DRenderPlugin'
8
+
9
+ import { VreoKeyframe, VreoKeyframeEnum } from '../../../typings/VreoUnit'
10
+ import { CustomVreoKeyframeProps } from '../../typings'
11
+
12
+ // __debug__
13
+ // const mockData: SpatialScenePanelData = {
14
+ // customType: 'SpatialScenePanel',
15
+ // "stateList": [
16
+ // {
17
+ // "icon": "http://vrlab-public.ljcdn.com/release/seesay/tools/___fc42f951076607a22fd5c54f005ba553.png",
18
+ // "text": "窗帘关闭"
19
+ // },
20
+ // {
21
+ // "icon": "http://vrlab-public.ljcdn.com/release/seesay/tools/___b331e7ad732debc07250a169a3393b13.png",
22
+ // "text": "摄像头休眠"
23
+ // },
24
+ // {
25
+ // "icon": "http://vrlab-public.ljcdn.com/release/seesay/tools/___2e425a81ac0ad88232d50d4e52a9abfa.png",
26
+ // "text": "氛围音乐"
27
+ // },
28
+ // {
29
+ // "icon": "http://vrlab-public.ljcdn.com/release/seesay/tools/___bff48bb81cde37aa6a319d6f5d56e3a4.png",
30
+ // "text": "空调打开"
31
+ // }
32
+ // ],
33
+ // "temperature": "27",
34
+ // "title": "沉浸式回家"
35
+ // }
36
+ export interface SpatialScenePanelData {
37
+ customType: 'SpatialScenePanel'
38
+ title: string
39
+ temperature: string
40
+ stateList: {
41
+ text: string
42
+ icon: string
43
+ }[]
44
+ position?: { x: number; y: number; z: number }
45
+ quaternion?: [number, number, number, number]
46
+ }
47
+
48
+ interface SearchParams {
49
+ five: Five
50
+ // position: Vector3
51
+ // rotation?: Vector3
52
+ // quaternion: [number, number, number, number]
53
+ dom: HTMLDivElement
54
+ }
55
+
56
+ // const getSphere = (position: Vector3, color = 0xffff00) => {
57
+ // const geometry = new SphereGeometry(0.05, 32, 16)
58
+ // const material = new MeshBasicMaterial({ color })
59
+ // const sphere = new Mesh(geometry, material)
60
+ // sphere.position.copy(position)
61
+ // return sphere
62
+ // }
63
+
64
+ const searchV1 = ({ five, dom }: SearchParams) => {
65
+ const cameraDirection = new Vector3()
66
+ five.camera.getWorldDirection(cameraDirection)
67
+ const cameraPosition = five.camera.position
68
+ const [intersect] = five.model.intersectRaycaster(new Raycaster(cameraPosition, cameraDirection))
69
+ const point = five.project2d(intersect.point)
70
+
71
+ const widescreen = window.innerWidth > 560 ? true : false
72
+ // const width = dom!.clientWidth
73
+ const height = dom!.clientHeight
74
+ dom!.style.left = point!.x + 'px'
75
+ dom!.style.top = point!.y - height / 2 + 'px'
76
+ const rect = dom!.getBoundingClientRect()
77
+ const { left, top, bottom, right } = rect
78
+
79
+ const leftBottom = new Vector3(left, bottom)
80
+ const leftTop = new Vector3(left, top)
81
+ const rightTop = new Vector3(right, top)
82
+ const rightBottom = new Vector3(right, bottom)
83
+
84
+ const points = [leftBottom, rightBottom, rightTop, leftTop].map((point) => {
85
+ point.setX((point.x / window.innerWidth) * 2 - (widescreen ? 1.25: 1.75))
86
+ point.setY(-(point.y / window.innerHeight) * 2 + (widescreen ? 1.35: 1.125))
87
+ point.setZ(0.5)
88
+ return point.unproject(five.camera).addScaledVector(cameraDirection, 0.2)
89
+ })
90
+
91
+ // __debug__
92
+ // const colors = [0xdc143c, 0xffff00, 0x0000ff, 0x008000]
93
+ // points.forEach((p, index) => five.scene.add(getSphere(p, colors[index])))
94
+
95
+ // 判断是手机 150
96
+ const ratio = leftBottom.distanceTo(rightBottom) / (widescreen ? 150 : 120)
97
+ return { points, ratio }
98
+ }
99
+
100
+ /**
101
+ * 空间场景面板
102
+ * @returns
103
+ */
104
+ export function SpatialScenePanel(props: CustomVreoKeyframeProps) {
105
+ const timeoutRef = React.useRef<NodeJS.Timeout | null>(null)
106
+ const ref = React.useRef<HTMLDivElement>(null)
107
+ const panelRef = React.useRef<HTMLDivElement | null>(null)
108
+ const rendererRef = React.useRef<CSS3DRenderPluginExportType>(CSS3DRenderPlugin(props.five))
109
+
110
+ React.useEffect(() => {
111
+ if (!ref.current) {
112
+ return
113
+ }
114
+
115
+ const callback = (keyframe: VreoKeyframe) => {
116
+ if (keyframe.data.customType !== 'SpatialScenePanel') {
117
+ return
118
+ }
119
+
120
+ const data = keyframe.data as SpatialScenePanelData
121
+
122
+ // const data = mockData
123
+ const { points, ratio } = searchV1({
124
+ five: props.five,
125
+ dom: ref.current!,
126
+ })
127
+
128
+ const { container, dispose, css3DObject, render } =
129
+ rendererRef.current.create3DDomContainer(points, { ratio, autoRender: false }) || {}
130
+
131
+ Object.assign(window, { $css3DObject: css3DObject })
132
+ if (!container) return
133
+
134
+ ReactDOM.render(<Panel ref={(ref) => (panelRef.current = ref)} data={data} />, container)
135
+ const startRotateY = -(Math.PI * 2) / 9
136
+ let lastRotateY = 0
137
+
138
+ tweenProgress(1000)
139
+ .onUpdate(({ progress }) => {
140
+ const needRotateY = (Math.PI / 90) * 11 * progress
141
+ const rotateY = needRotateY - lastRotateY
142
+ css3DObject?.rotateY(rotateY)
143
+ // css3DObject?.rotateZ
144
+ lastRotateY = needRotateY
145
+ })
146
+ .onStart(() => {
147
+ css3DObject?.rotateY(startRotateY)
148
+ render!()
149
+ })
150
+ .onDispose(() => {
151
+ panelRef.current?.classList.add('show')
152
+ })
153
+ .play()
154
+
155
+ // Object.assign(window, { $dispose: () => {
156
+ // panelRef.current?.classList.add('hide')
157
+ // setTimeout(() => dispose?.(), 1500)
158
+ // } })
159
+
160
+ const { start, end } = keyframe
161
+
162
+ timeoutRef.current = setTimeout(() => {
163
+ panelRef.current?.classList.add('hide')
164
+ timeoutRef.current = setTimeout(() => {
165
+ dispose?.()
166
+ timeoutRef.current = null
167
+ }, 1500)
168
+ }, end - start)
169
+ }
170
+
171
+ Object.assign(window, { $callback: callback })
172
+
173
+ // setTimeout(() => {callback()}, 8000)
174
+ props.subscribe.on(VreoKeyframeEnum.Custom, callback)
175
+
176
+ return () => {
177
+ props.subscribe.off(VreoKeyframeEnum.Custom, callback)
178
+ if (timeoutRef.current) {
179
+ clearTimeout(timeoutRef.current)
180
+ }
181
+ }
182
+ }, [])
183
+
184
+ return <div className="vreo-SpatialScenePanel" ref={ref}></div>
185
+ }
186
+
187
+ /** 背景动画:控制延迟 */
188
+ function SpatialScenePanelBg() {
189
+ const ref = React.useRef<HTMLDivElement>(null)
190
+ const timeoutRef = React.useRef<NodeJS.Timeout | null>(null)
191
+ React.useEffect(() => {
192
+ if (!ref.current) return
193
+
194
+ const listener = () => {
195
+ ref.current?.setAttribute('class', 'SpatialScenePanel-bg')
196
+
197
+ timeoutRef.current = setTimeout(() => {
198
+ ref.current?.setAttribute('class', 'SpatialScenePanel-bg SpatialScenePanel-bg--animation')
199
+ timeoutRef.current = null
200
+ }, 3000)
201
+ }
202
+
203
+ ref.current.addEventListener('animationend', listener)
204
+
205
+ return () => {
206
+ if (ref.current) ref.current.removeEventListener('animationend', listener)
207
+ if (timeoutRef.current) clearTimeout(timeoutRef.current)
208
+ }
209
+ }, [])
210
+ return <div ref={ref} className="SpatialScenePanel-bg SpatialScenePanel-bg--animation"></div>
211
+ }
212
+
213
+ const Panel = React.forwardRef(
214
+ (props: { data: SpatialScenePanelData }, myRef: React.LegacyRef<HTMLDivElement> | undefined) => (
215
+ <div className="SpatialScenePanel" ref={myRef}>
216
+ <div className="SpatialScenePanel-show-area">
217
+ <SpatialScenePanelBg />
218
+ <div className="SpatialScenePanel-header">
219
+ <div className="SpatialScenePanel-title">{props.data?.title}</div>
220
+ <div className="SpatialScenePanel-temperature">{props.data?.temperature}℃</div>
221
+ </div>
222
+ <div className="SpatialScenePanel-body">
223
+ {props.data?.stateList?.map((state, index) => (
224
+ <div key={`scene-${state.text}`} className={`SpatialScenePanel-item index_${index}`}>
225
+ <img className="SpatialScenePanel-icon" src={state.icon}></img>
226
+ <div className="SpatialScenePanel-text">{state.text}</div>
227
+ <div className="SpatialScenePanel-dot"></div>
228
+ </div>
229
+ ))}
230
+ </div>
231
+ </div>
232
+
233
+ <div className="SpatialScenePanel-disappear-area"></div>
234
+ </div>
235
+ )
236
+ )
237
+
238
+
239
+ // export function SpatialScenePanel() {
240
+ // // const data = mockData
241
+
242
+ // return (
243
+ // <div className="SpatialScenePanel" >
244
+ // <div className="SpatialScenePanel-show-area">
245
+ // <SpatialScenePanelBg />
246
+ // <div className="SpatialScenePanel-header">
247
+ // <div className="SpatialScenePanel-title">{data?.title}</div>
248
+ // <div className="SpatialScenePanel-temperature">{data?.temperature}℃</div>
249
+ // </div>
250
+ // <div className="SpatialScenePanel-body">
251
+ // {data?.stateList?.map((state, index) => (
252
+ // <div key={`scene-${state.text}`} className={`SpatialScenePanel-item index_${index}`}>
253
+ // <img className="SpatialScenePanel-icon" src={state.icon}></img>
254
+ // <div className="SpatialScenePanel-text">{state.text}</div>
255
+ // <div className="SpatialScenePanel-dot"></div>
256
+ // </div>
257
+ // ))}
258
+ // </div>
259
+ // </div>
260
+
261
+ // <div className="SpatialScenePanel-disappear-area"></div>
262
+ // </div>
263
+ // )
264
+ // }
@@ -4,10 +4,11 @@ import { Five, Subscribe } from '@realsee/five'
4
4
 
5
5
  import { App } from './App'
6
6
  import { Controller, ControllerContext } from './Controller'
7
- import { VreoKeyframeEvent, VreoKeyframeConfigMap, VreoUnit } from '../typings/VreoUnit'
7
+ import { CameraMovementData, VreoKeyframeEnum, VreoKeyframeEvent, VreoUnit } from '../typings/VreoUnit'
8
8
  import { reaction } from 'mobx'
9
9
  import { Drawer } from './modules/Drawer'
10
10
  import { PlayerConfigs } from './typings'
11
+ import { PopUp } from './modules/PopUp'
11
12
 
12
13
  export class Player extends Subscribe<VreoKeyframeEvent> {
13
14
  $five: Five
@@ -42,6 +43,19 @@ export class Player extends Subscribe<VreoKeyframeEvent> {
42
43
  <ControllerContext.Provider value={this.controller}>
43
44
  <App></App>
44
45
  <Drawer />
46
+ <PopUp />
47
+ {this.configs.customKeyframes &&
48
+ this.configs.customKeyframes.map((CustomCmpt, key) => (
49
+ <CustomCmpt
50
+ key={key}
51
+ subscribe={{
52
+ on: (name, callback) => this.on(name, callback),
53
+ once: (name, callback) => this.once(name, callback),
54
+ off: (name, callback) => this.off(name, callback),
55
+ }}
56
+ five={five}
57
+ />
58
+ ))}
45
59
  </ControllerContext.Provider>,
46
60
  configs.containter
47
61
  )
@@ -55,9 +69,13 @@ export class Player extends Subscribe<VreoKeyframeEvent> {
55
69
  )
56
70
  }
57
71
 
58
- async load(vreoUnit: VreoUnit, currentTime = 0) {
72
+ async load(vreoUnit: VreoUnit, currentTime = 0, preload = false, force = false) {
73
+ if (force) {
74
+ vreoUnit = JSON.parse(JSON.stringify(vreoUnit))
75
+ }
59
76
  if (!this.controller.visible) {
60
77
  this.controller.setVisible(true)
78
+ // 延迟 500ms 规避跟 DOM 动画冲突
61
79
  await new Promise((resolve) => {
62
80
  setTimeout(() => resolve(true), 500)
63
81
  })
@@ -71,6 +89,42 @@ export class Player extends Subscribe<VreoKeyframeEvent> {
71
89
  this.controller.vreoUnit = vreoUnit
72
90
  this.controller.videoInstance?.pause()
73
91
 
92
+ // 预载逻辑
93
+ // 是否降低图片分辨率
94
+ if (this.$five.imageOptions.size && this.configs.imageOptions?.size && this.$five.imageOptions.size > this.configs.imageOptions.size) {
95
+ this.$five.imageOptions.size = this.configs.imageOptions.size
96
+ }
97
+
98
+ // 预载数据中的点位
99
+ if (preload || (preload === undefined && this.configs.autoPreload)) {
100
+ const panoIndexMap = vreoUnit.keyframes.filter((vreoKeyframe) => {
101
+ if (vreoKeyframe.type !== VreoKeyframeEnum.CameraMovement) {
102
+ return false
103
+ }
104
+
105
+ const data = vreoKeyframe.data as CameraMovementData
106
+ if (data.panoIndex === undefined) {
107
+ return false
108
+ }
109
+ return true
110
+ }).reduce((accu: Record<number, boolean>, curr) => {
111
+ const panoIndex = curr.data.panoIndex as number
112
+ if (!accu[panoIndex]) {
113
+ accu[panoIndex] = true
114
+ }
115
+ return accu
116
+ }, {})
117
+
118
+ const panoIndexs = Object.keys(panoIndexMap)
119
+ for (let i = 0; i < panoIndexs.length; i++) {
120
+ await this.$five.preloadPano(Number(panoIndexs[i]))
121
+ }
122
+ }
123
+
124
+ // 新数据载入就绪
125
+ this.emit('loaded', vreoUnit)
126
+ this.controller.emit('loaded', vreoUnit)
127
+
74
128
  if (vreoUnit.video.url) {
75
129
  if (this.controller.videoAgentScene?.videoAgentMesh.videoInstance) {
76
130
  this.controller.videoAgentScene.videoAgentMesh.videoInstance.currentTime = currentTime / 1000
@@ -5,7 +5,7 @@ import { Controller } from '../../Controller'
5
5
  import { useController } from '../../hooks'
6
6
 
7
7
  const DrawerView = observer(({ controller }: { controller: Controller }) => {
8
- const maxHeight = '540px'
8
+ const maxHeight = '400px'
9
9
  const height = (() => {
10
10
  const height = controller.drawerConfig?.height
11
11
  if (!height) {
@@ -0,0 +1,26 @@
1
+ import * as React from 'react'
2
+ import classNames from 'classnames'
3
+ import { observer } from 'mobx-react'
4
+ import { Controller } from '../../Controller'
5
+ import { useController } from '../../hooks'
6
+
7
+ const PopUpView = observer(({ controller }: { controller: Controller }) => {
8
+
9
+ return (
10
+ <div
11
+ className={classNames('vreo-PopUp', {
12
+ 'vreo-PopUp-visible': controller.popUp,
13
+ })}
14
+ onClick={() => controller.openPopUp(false)}
15
+ >
16
+ <div className="vreo-PopUp-inner">
17
+ {controller.popUp || ''}
18
+ </div>
19
+ </div>
20
+ )
21
+ })
22
+
23
+ export function PopUp() {
24
+ const controller = useController()
25
+ return <PopUpView controller={controller} />
26
+ }
@@ -64,6 +64,7 @@ const cacheInstance: {
64
64
 
65
65
  export interface VideoAgentMeshOptions {
66
66
  videoInstance?: HTMLVideoElement
67
+ audioInstance?: HTMLAudioElement
67
68
  }
68
69
 
69
70
  /**
@@ -134,10 +135,9 @@ export class VideoAgentMesh extends THREE.Mesh {
134
135
  this.freeze = false
135
136
  this.paused = true
136
137
 
137
- {
138
+ if (!options.audioInstance) {
138
139
  if (cacheInstance.audioInstance) {
139
140
  this.audioInstance = cacheInstance.audioInstance
140
-
141
141
  } else {
142
142
  const audioInstance = document.createElement('audio')
143
143
  audioInstance.crossOrigin = ''
@@ -151,7 +151,8 @@ export class VideoAgentMesh extends THREE.Mesh {
151
151
  this.audioInstance = audioInstance
152
152
  cacheInstance.audioInstance = audioInstance
153
153
  }
154
-
154
+ } else {
155
+ this.audioInstance = options.audioInstance
155
156
  }
156
157
 
157
158
  makeObservable(this, { paused: observable })
@@ -196,7 +197,7 @@ export class VideoAgentMesh extends THREE.Mesh {
196
197
  }
197
198
 
198
199
  async play(videoUrl = '') {
199
- videoUrl = (videoUrl || '').replace(/https*:/, '')
200
+ videoUrl = videoUrl || ''
200
201
  if (!videoUrl) {
201
202
  if (this.videoUrl) await this.videoInstance.play()
202
203
  else console.warn('警告:视频资源未初始化。')