@realsee/vreo 0.2.0-alpha.8 → 1.0.0-alpha.1
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.
- package/CHANGELOG.md +30 -0
- package/README.md +34 -3
- package/docs/assets/highlight.css +1 -1
- package/docs/assets/main.js +2 -2
- package/docs/assets/search.js +1 -1
- package/docs/assets/style.css +28 -2
- package/docs/classes/Player.AudioLike.html +52 -0
- package/docs/classes/Player.Controller.html +13 -13
- package/docs/classes/Player.Player-1.html +11 -11
- package/docs/classes/Player.VideoAgentMesh.html +53 -53
- package/docs/classes/Player.VideoAgentScene.html +1 -1
- package/docs/demo/assets/AppReact.d0ee843a.js +1 -0
- package/docs/demo/assets/default.63925584.js +3984 -0
- package/docs/demo/assets/default.f3f3ca8c.css +1 -0
- package/docs/demo/assets/dynamic.76506c2c.js +1 -0
- package/docs/demo/assets/examples.3d8323db.js +25 -0
- package/docs/demo/assets/examples.dac4a6fe.css +1 -0
- package/docs/demo/assets/index.7e31122c.js +1 -0
- package/docs/demo/assets/index.9331038f.css +1 -0
- package/docs/demo/assets/main.79b11b9d.js +1 -0
- package/docs/demo/assets/react.2ee8565f.css +1 -0
- package/docs/demo/assets/react.c1c07c14.js +25 -0
- package/docs/demo/assets/znRoyv06SZQeqA7m.0057e8ae.js +1 -0
- package/docs/demo/examples.html +17 -0
- package/docs/demo/index-react-dynamic.html +20 -0
- package/docs/demo/index-react.html +20 -0
- package/docs/demo/index.html +19 -0
- package/docs/enums/Player.InfoPanelStyleEnum.html +1 -1
- package/docs/enums/Player.InfoPanelTypeEnum.html +2 -2
- package/docs/enums/Player.PanoEffectEnum.html +2 -2
- package/docs/enums/Player.PanoTagEnum.html +2 -2
- package/docs/enums/Player.PanoTagStyleEnum.html +7 -0
- package/docs/enums/Player.VreoKeyframeEnum.html +12 -12
- package/docs/enums/fivePlugins.CameraMovementEffect.html +1 -1
- package/docs/enums/fivePlugins.Rotation.html +1 -1
- package/docs/index.html +13 -6
- package/docs/interfaces/Player.CustomVreoKeyframeProps.html +1 -1
- package/docs/interfaces/Player.PlayerConfigs.html +3 -3
- package/docs/interfaces/Player.Vertex.html +2 -2
- package/docs/interfaces/Player.VideoAgentMeshOptions.html +8 -1
- package/docs/interfaces/Player.VreoKeyframe.html +2 -2
- package/docs/interfaces/Player.VreoUnit.html +2 -2
- package/docs/interfaces/Player.VreoVideo.html +2 -2
- package/docs/interfaces/fivePlugins.CSS3DRenderPluginExportType.html +4 -0
- package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +1 -1
- package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +2 -2
- package/docs/interfaces/fivePlugins.CameraMovementPluginParameterType.html +1 -1
- package/docs/interfaces/fivePlugins.ModelTVVideoPluginData.html +1 -1
- package/docs/interfaces/fivePlugins.ModelTVVideoPluginExportType.html +1 -1
- package/docs/interfaces/fivePlugins.ModelTVVideoPluginParameterType.html +1 -1
- package/docs/interfaces/fivePlugins.Vector3Position.html +3 -0
- package/docs/interfaces/react.VreoActionCallbacks.html +15 -7
- package/docs/interfaces/react.VreoProviderProps.html +1 -1
- package/docs/modules/Player.html +21 -15
- package/docs/modules/custom.html +1 -1
- package/docs/modules/fivePlugins.html +5 -2
- package/docs/modules/react.html +1 -1
- package/docs/modules.html +1 -1
- package/lib/PlayController/index.js +3 -3
- package/lib/Player/App.js +5 -4
- package/lib/Player/Controller.d.ts +3 -1
- package/lib/Player/Controller.js +24 -5
- package/lib/Player/custom/SpatialScenePanel/index.js +3 -3
- package/lib/Player/index.d.ts +3 -2
- package/lib/Player/index.js +73 -42
- package/lib/Player/modules/Drawer/index.js +1 -1
- package/lib/Player/modules/PopUp/index.js +1 -1
- package/lib/Player/modules/VideoAgent/VideoAgentMesh.d.ts +17 -2
- package/lib/Player/modules/VideoAgent/VideoAgentMesh.js +113 -37
- package/lib/Player/modules/VideoAgent/VideoAgentScene.d.ts +5 -1
- package/lib/Player/modules/VideoAgent/VideoAgentScene.js +9 -4
- package/lib/Player/modules/VideoAgent/index.d.ts +2 -0
- package/lib/Player/modules/VideoAgent/index.js +2 -2
- package/lib/Player/modules/keyframes/BgMusic/index.js +1 -1
- package/lib/Player/modules/keyframes/CameraMovement/index.js +1 -1
- package/lib/Player/modules/keyframes/InfoPanel/index.js +2 -2
- package/lib/Player/modules/keyframes/ModelVideo/index.js +46 -9
- package/lib/Player/modules/keyframes/PanoEffect/index.js +1 -1
- package/lib/Player/modules/keyframes/PanoEffect/lineAnime.js +1 -1
- package/lib/Player/modules/keyframes/PanoTag/index.js +20 -7
- package/lib/Player/modules/keyframes/PanoTextLabel/index.d.ts +3 -0
- package/lib/Player/modules/keyframes/PanoTextLabel/index.js +97 -44
- package/lib/Player/modules/keyframes/Prompter/index.js +5 -19
- package/lib/Player/modules/keyframes/UpdateVRPanorama/index.js +10 -6
- package/lib/Player/modules/keyframes/VideoEffect/index.js +1 -1
- package/lib/Player/typings.d.ts +6 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/centerPoint.d.ts +2 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/centerPoint.js +12 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/createResizeObserver.d.ts +7 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/createResizeObserver.js +32 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/evenNumber.d.ts +3 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/evenNumber.js +11 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/index.d.ts +56 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/index.js +275 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.d.ts +7 -0
- package/lib/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.js +18 -0
- package/lib/fivePlugins/CameraMovementPlugin/index.js +18 -14
- package/lib/fivePlugins/ModelTVVideoPlugin/index.js +1 -1
- package/lib/react/index.d.ts +7 -3
- package/lib/react/index.js +3 -3
- package/lib/shared-utils/AduioLike.d.ts +37 -0
- package/lib/shared-utils/AduioLike.js +165 -0
- package/lib/shared-utils/animationFrame/BetterTween.js +7 -3
- package/lib/shared-utils/animationFrame/tween.js +1 -1
- package/lib/shared-utils/createTransMatrix.d.ts +1 -0
- package/lib/shared-utils/createTransMatrix.js +43 -0
- package/lib/typings/VreoUnit.d.ts +33 -2
- package/lib/typings/VreoUnit.js +13 -1
- package/package.json +10 -10
- package/resources/PlayController/index.ts +0 -13
- package/resources/Player/App.tsx +7 -4
- package/resources/Player/Controller.ts +277 -146
- package/resources/Player/custom/SpatialScenePanel/index.tsx +5 -5
- package/resources/Player/hooks.ts +3 -5
- package/resources/Player/index.tsx +189 -141
- package/resources/Player/modules/ResizeObserver/index.tsx +23 -0
- package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +91 -34
- package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +28 -25
- package/resources/Player/modules/VideoAgent/index.tsx +30 -13
- package/resources/Player/modules/Wave/index.tsx +18 -0
- package/resources/Player/modules/keyframes/InfoPanel/index.tsx +26 -11
- package/resources/Player/modules/keyframes/ModelVideo/index.tsx +36 -3
- package/resources/Player/modules/keyframes/PanoTag/index.tsx +53 -97
- package/resources/Player/modules/keyframes/PanoTextLabel/index.tsx +86 -34
- package/resources/Player/modules/keyframes/Prompter/index.tsx +6 -16
- package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +6 -2
- package/resources/Player/typings.ts +18 -1
- package/resources/fivePlugins/CSS3DRenderPlugin/centerPoint.ts +5 -0
- package/resources/fivePlugins/CSS3DRenderPlugin/createResizeObserver.ts +17 -0
- package/resources/fivePlugins/CSS3DRenderPlugin/evenNumber.ts +4 -0
- package/resources/fivePlugins/CSS3DRenderPlugin/index.ts +254 -0
- package/resources/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.ts +5 -0
- package/resources/fivePlugins/CameraMovementPlugin/index.ts +19 -12
- package/resources/react/index.tsx +7 -3
- package/resources/shared-utils/AduioLike.ts +109 -0
- package/resources/shared-utils/addResizeListener.ts +46 -0
- package/resources/shared-utils/createTransMatrix.ts +12 -0
- package/resources/shared-utils/getFileExpandedName.ts +6 -0
- package/resources/shared-utils/getMediaInfo.ts +52 -0
- package/resources/shared-utils/setElementDataset.ts +18 -0
- package/resources/typings/VreoUnit.ts +41 -3
- package/stylesheets/custom/SpatialScenePanel.css +2 -1
- 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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
32
|
-
|
|
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
|
-
|
|
87
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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,7 +65,20 @@ const cacheInstance: {
|
|
|
63
65
|
} = {}
|
|
64
66
|
|
|
65
67
|
export interface VideoAgentMeshOptions {
|
|
68
|
+
/**
|
|
69
|
+
* 自定义视频实例。
|
|
70
|
+
*/
|
|
66
71
|
videoInstance?: HTMLVideoElement
|
|
72
|
+
/**
|
|
73
|
+
* 自定义音频实例。
|
|
74
|
+
*/
|
|
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
|
|
67
82
|
}
|
|
68
83
|
|
|
69
84
|
/**
|
|
@@ -72,17 +87,24 @@ export interface VideoAgentMeshOptions {
|
|
|
72
87
|
export class VideoAgentMesh extends THREE.Mesh {
|
|
73
88
|
options: VideoAgentMeshOptions
|
|
74
89
|
videoUrl?: string
|
|
75
|
-
freeze: boolean
|
|
90
|
+
freeze: boolean
|
|
76
91
|
paused: boolean
|
|
77
92
|
audioInstance: HTMLAudioElement
|
|
93
|
+
audioLikeInstance: AudioLike
|
|
78
94
|
$removeEventListener: () => void
|
|
79
95
|
|
|
80
|
-
get
|
|
81
|
-
if (this.videoUrl
|
|
96
|
+
get mediaInstance(): HTMLAudioElement | HTMLVideoElement | AudioLike {
|
|
97
|
+
if (!this.videoUrl) {
|
|
98
|
+
return this.audioLikeInstance
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (getMediaType(this.videoUrl) === 'audio') {
|
|
82
102
|
return this.audioInstance
|
|
83
103
|
}
|
|
104
|
+
|
|
84
105
|
const uniforms = (this.material as THREE.ShaderMaterial).uniforms
|
|
85
106
|
const videoInstance = uniforms.map.value.image as HTMLVideoElement
|
|
107
|
+
|
|
86
108
|
return videoInstance
|
|
87
109
|
}
|
|
88
110
|
|
|
@@ -99,7 +121,9 @@ export class VideoAgentMesh extends THREE.Mesh {
|
|
|
99
121
|
height: number,
|
|
100
122
|
widthSegments: number,
|
|
101
123
|
heightSegments: number,
|
|
102
|
-
options: VideoAgentMeshOptions = {
|
|
124
|
+
options: VideoAgentMeshOptions = {
|
|
125
|
+
preload: true
|
|
126
|
+
},
|
|
103
127
|
) {
|
|
104
128
|
if (!options.videoInstance) {
|
|
105
129
|
if (cacheInstance.videoInstance) {
|
|
@@ -107,6 +131,7 @@ export class VideoAgentMesh extends THREE.Mesh {
|
|
|
107
131
|
} else {
|
|
108
132
|
const videoInstance = document.createElement('video')
|
|
109
133
|
videoInstance.style.opacity = '0'
|
|
134
|
+
videoInstance.style.pointerEvents = 'none'
|
|
110
135
|
videoInstance.style.display = 'none'
|
|
111
136
|
document.body.append(videoInstance)
|
|
112
137
|
options.videoInstance = videoInstance
|
|
@@ -114,7 +139,6 @@ export class VideoAgentMesh extends THREE.Mesh {
|
|
|
114
139
|
videoInstance.playsInline = true
|
|
115
140
|
videoInstance.controls = false
|
|
116
141
|
}
|
|
117
|
-
|
|
118
142
|
}
|
|
119
143
|
|
|
120
144
|
const geometry = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments)
|
|
@@ -134,89 +158,122 @@ export class VideoAgentMesh extends THREE.Mesh {
|
|
|
134
158
|
this.freeze = false
|
|
135
159
|
this.paused = true
|
|
136
160
|
|
|
137
|
-
{
|
|
161
|
+
if (!options.audioInstance) {
|
|
138
162
|
if (cacheInstance.audioInstance) {
|
|
139
163
|
this.audioInstance = cacheInstance.audioInstance
|
|
140
|
-
|
|
141
164
|
} else {
|
|
142
165
|
const audioInstance = document.createElement('audio')
|
|
143
166
|
audioInstance.crossOrigin = ''
|
|
144
167
|
// videoInstance.muted = true
|
|
145
168
|
audioInstance.muted = false
|
|
146
|
-
audioInstance.
|
|
147
|
-
audioInstance.
|
|
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
|
|
153
174
|
}
|
|
154
|
-
|
|
175
|
+
} else {
|
|
176
|
+
this.audioInstance = options.audioInstance
|
|
155
177
|
}
|
|
156
178
|
|
|
179
|
+
this.audioLikeInstance = new AudioLike()
|
|
180
|
+
|
|
157
181
|
makeObservable(this, { paused: observable })
|
|
158
182
|
|
|
159
183
|
const updatePaused = (paused: boolean) => runInAction(() => (this.paused = paused))
|
|
160
184
|
const onPause = () => updatePaused(true)
|
|
161
185
|
const onPlay = () => updatePaused(false)
|
|
186
|
+
const onEnded = () => console.log('vreo: video 播放结束')
|
|
162
187
|
|
|
163
|
-
this.
|
|
164
|
-
this.
|
|
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)
|
|
165
195
|
|
|
166
196
|
this.$removeEventListener = () => {
|
|
167
|
-
this.
|
|
168
|
-
this.
|
|
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)
|
|
169
204
|
}
|
|
170
205
|
}
|
|
171
206
|
|
|
172
|
-
|
|
173
207
|
private async update(videoUrl: string) {
|
|
208
|
+
|
|
174
209
|
if (this.videoUrl === videoUrl) {
|
|
175
210
|
return
|
|
176
211
|
}
|
|
177
212
|
|
|
178
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
|
+
|
|
179
222
|
this.freeze = true
|
|
180
|
-
await this.
|
|
223
|
+
await this.mediaInstance.pause()
|
|
181
224
|
|
|
182
225
|
const uniforms = (this.material as THREE.ShaderMaterial).uniforms
|
|
183
|
-
this.
|
|
184
|
-
|
|
185
|
-
this.
|
|
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)
|
|
186
231
|
|
|
187
232
|
const onStart = () => {
|
|
188
|
-
if (this.
|
|
233
|
+
if (this.mediaInstance.currentTime === 0) return
|
|
189
234
|
this.freeze = false
|
|
190
|
-
this.
|
|
191
|
-
uniforms.enable.value = this.videoUrl
|
|
192
|
-
this.
|
|
235
|
+
this.mediaInstance.muted = false
|
|
236
|
+
uniforms.enable.value = getMediaType(this.videoUrl) ? 1 : 0
|
|
237
|
+
this.mediaInstance.removeEventListener('timeupdate', onStart, false)
|
|
238
|
+
|
|
193
239
|
}
|
|
194
240
|
|
|
195
|
-
this.
|
|
241
|
+
this.mediaInstance.addEventListener('timeupdate', onStart, false)
|
|
196
242
|
}
|
|
197
243
|
|
|
198
|
-
async play(videoUrl = '') {
|
|
244
|
+
async play(videoUrl = '', currentTime = 0, duration?: number) {
|
|
199
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
|
+
|
|
200
257
|
if (!videoUrl) {
|
|
201
|
-
if (this.videoUrl) await this.
|
|
258
|
+
if (this.videoUrl) await this.mediaInstance.play()
|
|
202
259
|
else console.warn('警告:视频资源未初始化。')
|
|
203
260
|
return true
|
|
204
261
|
}
|
|
205
262
|
|
|
206
263
|
if (videoUrl === this.videoUrl) {
|
|
207
|
-
this.
|
|
208
|
-
await this.
|
|
264
|
+
this.mediaInstance.currentTime = currentTime
|
|
265
|
+
await this.mediaInstance.play()
|
|
209
266
|
return true
|
|
210
267
|
}
|
|
211
268
|
|
|
212
269
|
await this.update(videoUrl)
|
|
213
270
|
|
|
214
|
-
this.
|
|
271
|
+
this.mediaInstance.pause()
|
|
215
272
|
|
|
216
273
|
return await new Promise((resolve) =>
|
|
217
274
|
setTimeout(async () => {
|
|
218
|
-
this.
|
|
219
|
-
await this.
|
|
275
|
+
this.mediaInstance.currentTime = currentTime
|
|
276
|
+
await this.mediaInstance.play()
|
|
220
277
|
resolve(true)
|
|
221
278
|
}, 20),
|
|
222
279
|
)
|
|
@@ -226,7 +283,7 @@ export class VideoAgentMesh extends THREE.Mesh {
|
|
|
226
283
|
* 转成毫秒,保障精准度
|
|
227
284
|
*/
|
|
228
285
|
get currentTime() {
|
|
229
|
-
return this.
|
|
286
|
+
return this.mediaInstance.currentTime * 1000
|
|
230
287
|
}
|
|
231
288
|
|
|
232
289
|
dispose() {
|