@realsee/vreo 0.2.0-alpha.9 → 1.0.0-alpha.2

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 (156) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +16 -5
  3. package/docs/assets/highlight.css +1 -1
  4. package/docs/assets/main.js +2 -2
  5. package/docs/assets/search.js +1 -1
  6. package/docs/assets/style.css +28 -2
  7. package/docs/classes/Player.AudioLike.html +52 -0
  8. package/docs/classes/Player.Controller.html +13 -13
  9. package/docs/classes/Player.Player-1.html +11 -11
  10. package/docs/classes/Player.VideoAgentMesh.html +53 -53
  11. package/docs/classes/Player.VideoAgentScene.html +1 -1
  12. package/docs/demo/assets/AppReact.d0ee843a.js +1 -0
  13. package/docs/demo/assets/default.63925584.js +3984 -0
  14. package/docs/demo/assets/default.f3f3ca8c.css +1 -0
  15. package/docs/demo/assets/dynamic.76506c2c.js +1 -0
  16. package/docs/demo/assets/examples.3d8323db.js +25 -0
  17. package/docs/demo/assets/examples.dac4a6fe.css +1 -0
  18. package/docs/demo/assets/index.7e31122c.js +1 -0
  19. package/docs/demo/assets/index.9331038f.css +1 -0
  20. package/docs/demo/assets/main.79b11b9d.js +1 -0
  21. package/docs/demo/assets/react.2ee8565f.css +1 -0
  22. package/docs/demo/assets/react.c1c07c14.js +25 -0
  23. package/docs/demo/assets/znRoyv06SZQeqA7m.0057e8ae.js +1 -0
  24. package/docs/demo/examples.html +17 -0
  25. package/docs/demo/index-react-dynamic.html +20 -0
  26. package/docs/demo/index-react.html +20 -0
  27. package/docs/demo/index.html +19 -0
  28. package/docs/enums/Player.InfoPanelStyleEnum.html +1 -1
  29. package/docs/enums/Player.InfoPanelTypeEnum.html +2 -2
  30. package/docs/enums/Player.PanoEffectEnum.html +2 -2
  31. package/docs/enums/Player.PanoTagEnum.html +2 -2
  32. package/docs/enums/Player.PanoTagStyleEnum.html +7 -0
  33. package/docs/enums/Player.VreoKeyframeEnum.html +12 -12
  34. package/docs/enums/fivePlugins.CameraMovementEffect.html +1 -1
  35. package/docs/enums/fivePlugins.Rotation.html +1 -1
  36. package/docs/index.html +13 -6
  37. package/docs/interfaces/Player.CustomVreoKeyframeProps.html +1 -1
  38. package/docs/interfaces/Player.PlayerConfigs.html +4 -3
  39. package/docs/interfaces/Player.Vertex.html +2 -2
  40. package/docs/interfaces/Player.VideoAgentMeshOptions.html +8 -1
  41. package/docs/interfaces/Player.VreoKeyframe.html +2 -2
  42. package/docs/interfaces/Player.VreoUnit.html +2 -2
  43. package/docs/interfaces/Player.VreoVideo.html +2 -2
  44. package/docs/interfaces/fivePlugins.CSS3DRenderPluginExportType.html +4 -0
  45. package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +1 -1
  46. package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +2 -2
  47. package/docs/interfaces/fivePlugins.CameraMovementPluginParameterType.html +1 -1
  48. package/docs/interfaces/fivePlugins.ModelTVVideoPluginData.html +1 -1
  49. package/docs/interfaces/fivePlugins.ModelTVVideoPluginExportType.html +1 -1
  50. package/docs/interfaces/fivePlugins.ModelTVVideoPluginParameterType.html +1 -1
  51. package/docs/interfaces/fivePlugins.Vector3Position.html +3 -0
  52. package/docs/interfaces/react.VreoActionCallbacks.html +15 -7
  53. package/docs/interfaces/react.VreoProviderProps.html +1 -1
  54. package/docs/modules/Player.html +21 -15
  55. package/docs/modules/custom.html +1 -1
  56. package/docs/modules/fivePlugins.html +5 -2
  57. package/docs/modules/react.html +1 -1
  58. package/docs/modules.html +1 -1
  59. package/lib/PlayController/index.js +4 -5
  60. package/lib/Player/App.js +9 -7
  61. package/lib/Player/Controller.d.ts +29 -8
  62. package/lib/Player/Controller.js +193 -27
  63. package/lib/Player/custom/SpatialScenePanel/index.js +5 -4
  64. package/lib/Player/hooks.js +2 -2
  65. package/lib/Player/index.d.ts +5 -3
  66. package/lib/Player/index.js +97 -53
  67. package/lib/Player/modules/Drawer/index.js +1 -1
  68. package/lib/Player/modules/PopUp/index.js +1 -1
  69. package/lib/Player/modules/ResizeObserver/index.d.ts +2 -0
  70. package/lib/Player/modules/ResizeObserver/index.js +37 -0
  71. package/lib/Player/modules/VideoAgent/VideoAgentMesh.d.ts +16 -2
  72. package/lib/Player/modules/VideoAgent/VideoAgentMesh.js +132 -59
  73. package/lib/Player/modules/VideoAgent/VideoAgentScene.d.ts +3 -6
  74. package/lib/Player/modules/VideoAgent/VideoAgentScene.js +31 -36
  75. package/lib/Player/modules/VideoAgent/index.js +53 -12
  76. package/lib/Player/modules/Wave/index.d.ts +5 -0
  77. package/lib/Player/modules/Wave/index.js +51 -0
  78. package/lib/Player/modules/keyframes/BgMusic/index.js +1 -1
  79. package/lib/Player/modules/keyframes/CameraMovement/index.js +1 -1
  80. package/lib/Player/modules/keyframes/InfoPanel/index.js +22 -10
  81. package/lib/Player/modules/keyframes/ModelVideo/index.js +46 -9
  82. package/lib/Player/modules/keyframes/PanoEffect/index.js +1 -1
  83. package/lib/Player/modules/keyframes/PanoEffect/lineAnime.js +1 -1
  84. package/lib/Player/modules/keyframes/PanoTag/index.d.ts +1 -2
  85. package/lib/Player/modules/keyframes/PanoTag/index.js +79 -119
  86. package/lib/Player/modules/keyframes/PanoTextLabel/index.d.ts +3 -0
  87. package/lib/Player/modules/keyframes/PanoTextLabel/index.js +96 -44
  88. package/lib/Player/modules/keyframes/Prompter/index.js +10 -23
  89. package/lib/Player/modules/keyframes/UpdateVRPanorama/index.js +10 -6
  90. package/lib/Player/modules/keyframes/VideoEffect/index.js +1 -1
  91. package/lib/Player/typings.d.ts +12 -1
  92. package/lib/fivePlugins/CSS3DRenderPlugin/centerPoint.d.ts +2 -0
  93. package/lib/fivePlugins/CSS3DRenderPlugin/centerPoint.js +12 -0
  94. package/lib/fivePlugins/CSS3DRenderPlugin/createResizeObserver.d.ts +7 -0
  95. package/lib/fivePlugins/CSS3DRenderPlugin/createResizeObserver.js +32 -0
  96. package/lib/fivePlugins/CSS3DRenderPlugin/evenNumber.d.ts +3 -0
  97. package/lib/fivePlugins/CSS3DRenderPlugin/evenNumber.js +11 -0
  98. package/lib/fivePlugins/CSS3DRenderPlugin/index.d.ts +56 -0
  99. package/lib/fivePlugins/CSS3DRenderPlugin/index.js +275 -0
  100. package/lib/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.d.ts +7 -0
  101. package/lib/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.js +18 -0
  102. package/lib/fivePlugins/CameraMovementPlugin/index.js +13 -12
  103. package/lib/fivePlugins/ModelTVVideoPlugin/index.js +1 -1
  104. package/lib/react/index.d.ts +8 -4
  105. package/lib/react/index.js +3 -3
  106. package/lib/shared-utils/AduioLike.d.ts +37 -0
  107. package/lib/shared-utils/AduioLike.js +166 -0
  108. package/lib/shared-utils/addResizeListener.d.ts +4 -0
  109. package/lib/shared-utils/addResizeListener.js +51 -0
  110. package/lib/shared-utils/animationFrame/BetterTween.js +7 -3
  111. package/lib/shared-utils/animationFrame/tween.js +1 -1
  112. package/lib/shared-utils/createTransMatrix.d.ts +1 -0
  113. package/lib/shared-utils/createTransMatrix.js +43 -0
  114. package/lib/shared-utils/getFileExpandedName.d.ts +1 -0
  115. package/lib/shared-utils/getFileExpandedName.js +13 -0
  116. package/lib/shared-utils/getMediaInfo.d.ts +9 -0
  117. package/lib/shared-utils/getMediaInfo.js +75 -0
  118. package/lib/shared-utils/setElementDataset.d.ts +1 -0
  119. package/lib/shared-utils/setElementDataset.js +24 -0
  120. package/lib/typings/VreoUnit.d.ts +37 -2
  121. package/lib/typings/VreoUnit.js +13 -1
  122. package/package.json +10 -10
  123. package/resources/PlayController/index.ts +0 -13
  124. package/resources/Player/App.tsx +5 -4
  125. package/resources/Player/Controller.ts +277 -146
  126. package/resources/Player/custom/SpatialScenePanel/index.tsx +5 -5
  127. package/resources/Player/hooks.ts +3 -5
  128. package/resources/Player/index.tsx +189 -141
  129. package/resources/Player/modules/ResizeObserver/index.tsx +23 -0
  130. package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +87 -31
  131. package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +27 -24
  132. package/resources/Player/modules/VideoAgent/index.tsx +28 -12
  133. package/resources/Player/modules/Wave/index.tsx +18 -0
  134. package/resources/Player/modules/keyframes/InfoPanel/index.tsx +26 -11
  135. package/resources/Player/modules/keyframes/ModelVideo/index.tsx +36 -3
  136. package/resources/Player/modules/keyframes/PanoTag/index.tsx +53 -97
  137. package/resources/Player/modules/keyframes/PanoTextLabel/index.tsx +86 -34
  138. package/resources/Player/modules/keyframes/Prompter/index.tsx +6 -16
  139. package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +6 -2
  140. package/resources/Player/typings.ts +15 -1
  141. package/resources/fivePlugins/CSS3DRenderPlugin/centerPoint.ts +5 -0
  142. package/resources/fivePlugins/CSS3DRenderPlugin/createResizeObserver.ts +17 -0
  143. package/resources/fivePlugins/CSS3DRenderPlugin/evenNumber.ts +4 -0
  144. package/resources/fivePlugins/CSS3DRenderPlugin/index.ts +254 -0
  145. package/resources/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.ts +5 -0
  146. package/resources/fivePlugins/CameraMovementPlugin/index.ts +19 -12
  147. package/resources/react/index.tsx +7 -3
  148. package/resources/shared-utils/AduioLike.ts +109 -0
  149. package/resources/shared-utils/addResizeListener.ts +46 -0
  150. package/resources/shared-utils/createTransMatrix.ts +12 -0
  151. package/resources/shared-utils/getFileExpandedName.ts +6 -0
  152. package/resources/shared-utils/getMediaInfo.ts +52 -0
  153. package/resources/shared-utils/setElementDataset.ts +18 -0
  154. package/resources/typings/VreoUnit.ts +41 -3
  155. package/stylesheets/custom/SpatialScenePanel.css +2 -1
  156. package/stylesheets/default.css +348 -84
@@ -1,4 +1,3 @@
1
- import * as React from 'react'
2
1
  import * as ReactDOM from 'react-dom'
3
2
  import { Five, Subscribe } from '@realsee/five'
4
3
 
@@ -7,160 +6,209 @@ import { Controller, ControllerContext } from './Controller'
7
6
  import { CameraMovementData, VreoKeyframeEnum, VreoKeyframeEvent, VreoUnit } from '../typings/VreoUnit'
8
7
  import { reaction } from 'mobx'
9
8
  import { Drawer } from './modules/Drawer'
10
- import { PlayerConfigs } from './typings'
9
+ import { Appearance, PlayerConfigs, WaveAppearance } from './typings'
11
10
  import { PopUp } from './modules/PopUp'
12
11
 
13
12
  export class Player extends Subscribe<VreoKeyframeEvent> {
14
- $five: Five
15
- private controller: Controller
16
- configs: Readonly<PlayerConfigs>
17
-
18
- constructor(five: Five, configs: Partial<PlayerConfigs> = {}) {
19
- super()
20
- this.controller = new Controller()
21
- this.$five = this.controller.$five = five
22
-
23
- if (!configs.containter) {
24
- const containter = document.querySelector('#vreo-app') || document.createElement('div')
25
- ReactDOM.unmountComponentAtNode(containter)
26
- containter.setAttribute('id', 'vreo-app')
27
- configs.containter = containter
28
- document.body.append(containter)
29
- }
13
+ $five: Five
14
+ private controller: Controller
15
+ configs: Readonly<PlayerConfigs>
30
16
 
31
- this.configs = Object.freeze(
32
- Object.assign(
33
- {
34
- keyframeMap: {},
35
- },
36
- configs
37
- )
38
- )
39
-
40
- this.controller.configs = this.configs
41
-
42
- ReactDOM.render(
43
- <ControllerContext.Provider value={this.controller}>
44
- <App></App>
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
- ))}
59
- </ControllerContext.Provider>,
60
- configs.containter
61
- )
62
-
63
- // 监听播放情况:抛出触发时机
64
- reaction(
65
- () => this.controller.playing,
66
- (playing) => {
67
- this.emit(playing ? 'playing' : 'paused')
68
- }
69
- )
70
- }
71
-
72
- async load(vreoUnit: VreoUnit, currentTime = 0, preload = false) {
73
- if (!this.controller.visible) {
74
- this.controller.setVisible(true)
75
- // 延迟 500ms 规避跟 DOM 动画冲突
76
- await new Promise((resolve) => {
77
- setTimeout(() => resolve(true), 500)
78
- })
79
- }
17
+ constructor(five: Five, configs: Partial<PlayerConfigs> = {}) {
18
+ super()
19
+ this.$five = five
80
20
 
81
- if (this.controller.stopInterval) {
82
- this.controller.stopInterval()
83
- this.controller.stopInterval = undefined
84
- }
85
21
 
86
- this.controller.vreoUnit = vreoUnit
87
- this.controller.videoInstance?.pause()
22
+ if (!configs.container) {
23
+ configs.container = configs.containter
24
+ }
25
+ if (!configs.container) {
26
+ const container = document.getElementById('vreo-app') || document.createElement('div')
27
+ ReactDOM.unmountComponentAtNode(container)
28
+ container.setAttribute('id', 'vreo-app')
29
+ configs.container = container
30
+ const fiveCanvasDomParent = five.getElement()?.parentNode
31
+ if (fiveCanvasDomParent) {
32
+ fiveCanvasDomParent.append(container)
33
+ } else {
34
+ document.body.append(container)
35
+ }
36
+ }
88
37
 
89
- // 预载逻辑
90
- // 是否降低图片分辨率
91
- if (this.$five.imageOptions.size && this.configs.imageOptions?.size && this.$five.imageOptions.size > this.configs.imageOptions.size) {
92
- this.$five.imageOptions.size = this.configs.imageOptions.size
38
+ if (!configs.container.classList.contains('vreo-app')) configs.container.classList.add('vreo-app')
39
+
40
+ this.configs = Object.freeze( Object.assign({ keyframeMap: {} }, configs) )
41
+
42
+ this.controller = new Controller({five, container:configs.container, configs: this.configs})
43
+
44
+
45
+ ReactDOM.render(
46
+ <ControllerContext.Provider value={this.controller}>
47
+ <App />
48
+ <Drawer />
49
+ <PopUp />
50
+ {this.configs.customKeyframes &&
51
+ this.configs.customKeyframes.map((CustomCmpt, key) => (
52
+ <CustomCmpt
53
+ key={key}
54
+ subscribe={{
55
+ on: (name, callback) => this.on(name, callback),
56
+ once: (name, callback) => this.once(name, callback),
57
+ off: (name, callback) => this.off(name, callback),
58
+ }}
59
+ five={five}
60
+ />
61
+ ))}
62
+ </ControllerContext.Provider>,
63
+ configs.container
64
+ )
65
+
66
+ // 监听播放情况:抛出触发时机
67
+ reaction(
68
+ () => this.controller.ended,
69
+ (ended) => {
70
+ if (ended) {
71
+ this.emit('paused', true)
72
+ }
73
+ }
74
+ )
75
+
76
+ reaction(
77
+ () => this.controller.playing,
78
+ (playing) => {
79
+ if (!this.controller.ended) {
80
+ this.emit(playing ? 'playing' : 'paused')
81
+ }
82
+ }
83
+ )
93
84
  }
94
-
95
- // 预载数据中的点位
96
- if (preload || (preload === undefined && this.configs.autoPreload)) {
97
- const panoIndexMap = vreoUnit.keyframes.filter((vreoKeyframe) => {
98
- if (vreoKeyframe.type !== VreoKeyframeEnum.CameraMovement) {
99
- return false
85
+
86
+ async load(vreoUnit: VreoUnit, currentTime = 0, preload = false, force = false) {
87
+ this.controller.setLoading(true)
88
+ if (force) {
89
+ vreoUnit = JSON.parse(JSON.stringify(vreoUnit))
90
+ }
91
+ if (!this.controller.visible) {
92
+ this.controller.setVisible(true)
93
+ // 延迟 500ms 规避跟 DOM 动画冲突
94
+ await new Promise((resolve) => {
95
+ setTimeout(() => resolve(true), 500)
96
+ })
100
97
  }
101
-
102
- const data = vreoKeyframe.data as CameraMovementData
103
- if (data.panoIndex === undefined) {
104
- return false
98
+
99
+ if (this.controller.stopInterval) {
100
+ this.controller.stopInterval()
101
+ this.controller.stopInterval = undefined
102
+ }
103
+
104
+ this.controller.vreoUnit = vreoUnit
105
+ this.controller.mediaInstance?.pause()
106
+
107
+ // 预载逻辑
108
+ // 是否降低图片分辨率
109
+ if (
110
+ this.$five.imageOptions.size &&
111
+ this.configs.imageOptions?.size &&
112
+ this.$five.imageOptions.size > this.configs.imageOptions.size
113
+ ) {
114
+ this.$five.imageOptions.size = this.configs.imageOptions.size
105
115
  }
116
+
117
+ // 预载数据中的点位
118
+ if (preload || (preload === undefined && this.configs.autoPreload)) {
119
+ const panoIndexMap = vreoUnit.keyframes
120
+ .filter((vreoKeyframe) => {
121
+ if (vreoKeyframe.type !== VreoKeyframeEnum.CameraMovement) {
122
+ return false
123
+ }
124
+
125
+ const data = vreoKeyframe.data as CameraMovementData
126
+ if (data.panoIndex === undefined) {
127
+ return false
128
+ }
129
+ return true
130
+ })
131
+ .reduce((accu: Record<number, boolean>, curr) => {
132
+ const panoIndex = curr.data.panoIndex as number
133
+ if (!accu[panoIndex]) {
134
+ accu[panoIndex] = true
135
+ }
136
+ return accu
137
+ }, {})
138
+
139
+ const panoIndexes = Object.keys(panoIndexMap)
140
+ for (let i = 0; i < panoIndexes.length; i++) {
141
+ await this.$five.preloadPano(Number(panoIndexes[i]))
142
+ }
143
+ }
144
+
145
+ // 新数据载入就绪
146
+ this.emit('loaded', vreoUnit)
147
+ this.controller.emit('loaded', vreoUnit)
148
+
149
+ if (this.controller.videoAgentScene?.videoAgentMesh.mediaInstance) {
150
+ this.controller.videoAgentScene.videoAgentMesh.mediaInstance.currentTime = currentTime / 1000
151
+ }
152
+
153
+ this.controller.setAvatar(vreoUnit.video.avatar)
154
+
155
+ await this.controller.videoAgentScene?.videoAgentMesh.play(
156
+ vreoUnit.video.url,
157
+ currentTime / 1000,
158
+ vreoUnit.video.duration
159
+ )
160
+
161
+ this.controller.setEnded(false)
162
+ this.play()
163
+
164
+ this.controller.run((type, keyframe) => this.emit(type, keyframe))
165
+ this.controller.setLoading(false)
106
166
  return true
107
- }).reduce((accu: Record<number, boolean>, curr) => {
108
- const panoIndex = curr.data.panoIndex as number
109
- if (!accu[panoIndex]) {
110
- accu[panoIndex] = true
167
+ }
168
+
169
+ get paused() {
170
+ return !this.controller.playing
171
+ }
172
+
173
+ play(currentTime?: number) {
174
+ if (this.controller.playing) return true
175
+ if (currentTime && this.controller.mediaInstance) {
176
+ this.controller.mediaInstance.currentTime = currentTime / 1000
111
177
  }
112
- return accu
113
- }, {})
114
-
115
- const panoIndexs = Object.keys(panoIndexMap)
116
- for (let i = 0; i < panoIndexs.length; i++) {
117
- await this.$five.preloadPano(Number(panoIndexs[i]))
118
- }
178
+ Object.assign(window, { $vreoController: this.controller })
179
+
180
+ this.controller.setPlaying(true)
181
+ return true
119
182
  }
120
-
121
- // 新数据载入就绪
122
- this.emit('loaded', vreoUnit)
123
- if (vreoUnit.video.url) {
124
- if (this.controller.videoAgentScene?.videoAgentMesh.videoInstance) {
125
- this.controller.videoAgentScene.videoAgentMesh.videoInstance.currentTime = currentTime / 1000
126
- }
127
- await this.controller.videoAgentScene?.videoAgentMesh.play(vreoUnit.video.url)
128
- this.play()
183
+
184
+ setAppearance(appearance: Appearance) {
185
+ this.controller.setAppearance(appearance)
129
186
  }
130
- this.controller.run((type, keyframe) => this.emit(type, keyframe))
131
- return true
132
- }
133
-
134
- get paused() {
135
- return !this.controller.playing
136
- }
137
-
138
- play() {
139
- if (this.controller.playing) return true
140
- this.controller.setPlaying(true)
141
- return true
142
- }
143
-
144
- pause() {
145
- this.controller.setPlaying(false)
146
- }
147
-
148
- show() {
149
- this.controller.setVisible(true)
150
- }
151
-
152
- hide() {
153
- this.controller.setVisible(false)
154
- }
155
-
156
- dispose() {
157
- this.pause()
158
- this.controller.dispose()
159
-
160
- if (this.configs.containter) {
161
- ReactDOM.unmountComponentAtNode(this.configs.containter as Element)
187
+
188
+ pause() {
189
+ this.controller.setPlaying(false)
190
+ }
191
+
192
+ show() {
193
+ this.controller.setVisible(true)
194
+ }
195
+
196
+ hide() {
197
+ this.controller.setVisible(false)
198
+ }
199
+
200
+ getCurrentTime() {
201
+ return this.controller.currentTime
202
+ }
203
+
204
+ dispose() {
205
+ this.pause()
206
+ this.controller.dispose()
207
+
208
+ if (this.configs.container) {
209
+ ReactDOM.unmountComponentAtNode(this.configs.container as Element)
210
+ }
162
211
  }
163
- }
164
212
  }
165
213
 
166
214
  console.log(`
@@ -172,6 +220,6 @@ console.log(`
172
220
  ┃┃┃┗┓┃┃━┫┃┗┛┗┓┃┗┓┣━━┃┃┃━┫┃┃━┫
173
221
  ┗┛┗━┛┗━━┛┗━━━┛┗━┛┗━━┛┗━━┛┗━━┛
174
222
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
175
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
223
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
176
224
 
177
225
  `)
@@ -0,0 +1,23 @@
1
+ import React from 'react'
2
+ import { addResizeListener, hasResizeListener } from '../../../shared-utils/addResizeListener'
3
+ import { useController } from '../../hooks'
4
+
5
+ export function ResizeObserver() {
6
+ const ref = React.useRef<HTMLDivElement>(null)
7
+ const controller = useController()
8
+
9
+ React.useEffect(() => {
10
+ if (!ref.current) return
11
+ const resizeElement = controller.container.parentElement
12
+ if (hasResizeListener(resizeElement)) return
13
+ const dispose = addResizeListener(resizeElement, (width, height) => {
14
+ controller.setContainerSize(width, height)
15
+ })
16
+
17
+ return () => {
18
+ dispose()
19
+ }
20
+ }, [])
21
+
22
+ return <div className="resizeObserver-element" ref={ref}></div>
23
+ }
@@ -1,6 +1,8 @@
1
1
  import * as THREE from 'three'
2
2
  import { Preloader } from '../../../shared-utils/Preloader'
3
3
  import { makeObservable, observable, runInAction } from 'mobx'
4
+ import AudioLike from '../../../shared-utils/AduioLike'
5
+ import { getMediaType } from '../../../shared-utils/getMediaInfo'
4
6
 
5
7
  const vertexShader = `
6
8
  varying vec2 vUv;
@@ -63,8 +65,20 @@ const cacheInstance: {
63
65
  } = {}
64
66
 
65
67
  export interface VideoAgentMeshOptions {
68
+ /**
69
+ * 自定义视频实例。
70
+ */
66
71
  videoInstance?: HTMLVideoElement
72
+ /**
73
+ * 自定义音频实例。
74
+ */
67
75
  audioInstance?: HTMLAudioElement
76
+ /**
77
+ * 是否开启音频预载能力。**仅对`.mp3`有效**。
78
+ *
79
+ * @description 开启预载能力后会通过 `Fetch/XHR` 方式将音频文件下载转成二进制 [`Blob`](https://developer.mozilla.org/zh-CN/docs/Web/API/Blob) 提供给多媒体实例。这样的好处是 **能够保障音视频播放过程中不卡顿**。 但在部分 iOS 系统中会存在兼容问题——播 25s 之后会静音(`muted` 为 `false`,但是没有声音)。
80
+ */
81
+ preload?: boolean
68
82
  }
69
83
 
70
84
  /**
@@ -73,17 +87,24 @@ export interface VideoAgentMeshOptions {
73
87
  export class VideoAgentMesh extends THREE.Mesh {
74
88
  options: VideoAgentMeshOptions
75
89
  videoUrl?: string
76
- freeze: boolean
90
+ freeze: boolean
77
91
  paused: boolean
78
92
  audioInstance: HTMLAudioElement
93
+ audioLikeInstance: AudioLike
79
94
  $removeEventListener: () => void
80
95
 
81
- get videoInstance(): HTMLAudioElement {
82
- if (this.videoUrl?.endsWith('mp3')) {
96
+ get mediaInstance(): HTMLAudioElement | HTMLVideoElement | AudioLike {
97
+ if (!this.videoUrl) {
98
+ return this.audioLikeInstance
99
+ }
100
+
101
+ if (getMediaType(this.videoUrl) === 'audio') {
83
102
  return this.audioInstance
84
103
  }
104
+
85
105
  const uniforms = (this.material as THREE.ShaderMaterial).uniforms
86
106
  const videoInstance = uniforms.map.value.image as HTMLVideoElement
107
+
87
108
  return videoInstance
88
109
  }
89
110
 
@@ -100,7 +121,9 @@ export class VideoAgentMesh extends THREE.Mesh {
100
121
  height: number,
101
122
  widthSegments: number,
102
123
  heightSegments: number,
103
- options: VideoAgentMeshOptions = {},
124
+ options: VideoAgentMeshOptions = {
125
+ preload: true
126
+ },
104
127
  ) {
105
128
  if (!options.videoInstance) {
106
129
  if (cacheInstance.videoInstance) {
@@ -108,6 +131,7 @@ export class VideoAgentMesh extends THREE.Mesh {
108
131
  } else {
109
132
  const videoInstance = document.createElement('video')
110
133
  videoInstance.style.opacity = '0'
134
+ videoInstance.style.pointerEvents = 'none'
111
135
  videoInstance.style.display = 'none'
112
136
  document.body.append(videoInstance)
113
137
  options.videoInstance = videoInstance
@@ -115,7 +139,6 @@ export class VideoAgentMesh extends THREE.Mesh {
115
139
  videoInstance.playsInline = true
116
140
  videoInstance.controls = false
117
141
  }
118
-
119
142
  }
120
143
 
121
144
  const geometry = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments)
@@ -143,10 +166,8 @@ export class VideoAgentMesh extends THREE.Mesh {
143
166
  audioInstance.crossOrigin = ''
144
167
  // videoInstance.muted = true
145
168
  audioInstance.muted = false
146
- audioInstance.setAttribute('playsinline', 'true')
147
- audioInstance.setAttribute('webkit-playsinline', 'true')
148
- audioInstance.setAttribute('autoplay', 'false')
149
- audioInstance.setAttribute('style', 'display: none;')
169
+ audioInstance.autoplay = false
170
+ audioInstance.style.display = 'none'
150
171
  document.body.appendChild(audioInstance)
151
172
  this.audioInstance = audioInstance
152
173
  cacheInstance.audioInstance = audioInstance
@@ -155,69 +176,104 @@ export class VideoAgentMesh extends THREE.Mesh {
155
176
  this.audioInstance = options.audioInstance
156
177
  }
157
178
 
179
+ this.audioLikeInstance = new AudioLike()
180
+
158
181
  makeObservable(this, { paused: observable })
159
182
 
160
183
  const updatePaused = (paused: boolean) => runInAction(() => (this.paused = paused))
161
184
  const onPause = () => updatePaused(true)
162
185
  const onPlay = () => updatePaused(false)
186
+ const onEnded = () => console.log('vreo: video 播放结束')
163
187
 
164
- this.videoInstance.addEventListener('pause', onPause)
165
- this.videoInstance.addEventListener('play', onPlay)
188
+ this.audioInstance.addEventListener('pause', onPause)
189
+ this.audioInstance.addEventListener('play', onPlay)
190
+ this.options.videoInstance?.addEventListener('pause', onPause)
191
+ this.options.videoInstance?.addEventListener('play', onPlay)
192
+ this.audioLikeInstance.addEventListener('pause', onPause)
193
+ this.audioLikeInstance.addEventListener('play', onPlay)
194
+ this.options.videoInstance?.addEventListener('ended', onEnded)
166
195
 
167
196
  this.$removeEventListener = () => {
168
- this.videoInstance.removeEventListener('pause', onPause)
169
- this.videoInstance.removeEventListener('play', onPlay)
197
+ this.audioInstance.removeEventListener('pause', onPause)
198
+ this.audioInstance.removeEventListener('play', onPlay)
199
+ this.options.videoInstance?.removeEventListener('pause', onPause)
200
+ this.options.videoInstance?.removeEventListener('play', onPlay)
201
+ this.audioLikeInstance.removeEventListener('pause', onPause)
202
+ this.audioLikeInstance.removeEventListener('play', onPlay)
203
+ this.options.videoInstance?.removeEventListener('ended', onEnded)
170
204
  }
171
205
  }
172
206
 
173
-
174
207
  private async update(videoUrl: string) {
208
+
175
209
  if (this.videoUrl === videoUrl) {
176
210
  return
177
211
  }
178
212
 
179
213
  this.videoUrl = videoUrl
214
+
215
+ // // 兼容非视频场景
216
+ // if (this.mediaInstance instanceof HTMLAudioElement) {
217
+ // this.mediaInstance.style.display = 'none'
218
+ // } else if (this.mediaInstance instanceof HTMLVideoElement) {
219
+ // this.mediaInstance.style.display = 'block'
220
+ // }
221
+
180
222
  this.freeze = true
181
- await this.videoInstance.pause()
223
+ await this.mediaInstance.pause()
182
224
 
183
225
  const uniforms = (this.material as THREE.ShaderMaterial).uniforms
184
- this.videoInstance.muted = true
185
- this.videoInstance.src = await URL.createObjectURL((await Preloader.blob(this.videoUrl)) as unknown as Blob)
186
- this.videoInstance.setAttribute('data-src', this.videoUrl)
226
+ this.mediaInstance.muted = true
227
+
228
+ this.mediaInstance.src = (this.options.preload || this.options.preload === undefined || getMediaType(this.videoUrl) === 'video') ?
229
+ await URL.createObjectURL((await Preloader.blob(this.videoUrl)) as unknown as Blob) : this.videoUrl
230
+ this.mediaInstance.setAttribute('data-src', this.videoUrl)
187
231
 
188
232
  const onStart = () => {
189
- if (this.videoInstance.currentTime === 0) return
233
+ if (this.mediaInstance.currentTime === 0) return
190
234
  this.freeze = false
191
- this.videoInstance.muted = false
192
- uniforms.enable.value = this.videoUrl?.endsWith('.mp4') ? 1 : 0
193
- this.videoInstance.removeEventListener('timeupdate', onStart, false)
235
+ this.mediaInstance.muted = false
236
+ uniforms.enable.value = getMediaType(this.videoUrl) ? 1 : 0
237
+ this.mediaInstance.removeEventListener('timeupdate', onStart, false)
238
+
194
239
  }
195
240
 
196
- this.videoInstance.addEventListener('timeupdate', onStart, false)
241
+ this.mediaInstance.addEventListener('timeupdate', onStart, false)
197
242
  }
198
243
 
199
- async play(videoUrl = '') {
244
+ async play(videoUrl = '', currentTime = 0, duration?: number) {
200
245
  videoUrl = videoUrl || ''
246
+
247
+ if (duration && !videoUrl) {
248
+ if (this.currentTime) {
249
+ this.mediaInstance.currentTime = currentTime
250
+ }
251
+ (this.mediaInstance as AudioLike).duration = duration
252
+ this.videoUrl = ''
253
+ this.mediaInstance.play()
254
+ return true
255
+ }
256
+
201
257
  if (!videoUrl) {
202
- if (this.videoUrl) await this.videoInstance.play()
258
+ if (this.videoUrl) await this.mediaInstance.play()
203
259
  else console.warn('警告:视频资源未初始化。')
204
260
  return true
205
261
  }
206
262
 
207
263
  if (videoUrl === this.videoUrl) {
208
- this.videoInstance.currentTime = 0
209
- await this.videoInstance.play()
264
+ this.mediaInstance.currentTime = currentTime
265
+ await this.mediaInstance.play()
210
266
  return true
211
267
  }
212
268
 
213
269
  await this.update(videoUrl)
214
270
 
215
- this.videoInstance.pause()
271
+ this.mediaInstance.pause()
216
272
 
217
273
  return await new Promise((resolve) =>
218
274
  setTimeout(async () => {
219
- this.videoInstance.currentTime = 0
220
- await this.videoInstance.play()
275
+ this.mediaInstance.currentTime = currentTime
276
+ await this.mediaInstance.play()
221
277
  resolve(true)
222
278
  }, 20),
223
279
  )
@@ -227,7 +283,7 @@ export class VideoAgentMesh extends THREE.Mesh {
227
283
  * 转成毫秒,保障精准度
228
284
  */
229
285
  get currentTime() {
230
- return this.videoInstance.currentTime * 1000
286
+ return this.mediaInstance.currentTime * 1000
231
287
  }
232
288
 
233
289
  dispose() {