@realsee/vreo 1.0.0-alpha.19 → 1.0.0-alpha.20

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 (112) hide show
  1. package/lib/Player/modules/keyframes/BgMusic/index.js +2 -4
  2. package/package.json +1 -3
  3. package/docs/.nojekyll +0 -1
  4. package/docs/assets/custom.css +0 -78
  5. package/docs/assets/highlight.css +0 -127
  6. package/docs/assets/icons.css +0 -1043
  7. package/docs/assets/icons.png +0 -0
  8. package/docs/assets/icons@2x.png +0 -0
  9. package/docs/assets/main.js +0 -52
  10. package/docs/assets/search.js +0 -1
  11. package/docs/assets/style.css +0 -1414
  12. package/docs/assets/widgets.png +0 -0
  13. package/docs/assets/widgets@2x.png +0 -0
  14. package/docs/classes/Player.AudioLike.html +0 -52
  15. package/docs/classes/Player.Controller.html +0 -54
  16. package/docs/classes/Player.Player-1.html +0 -50
  17. package/docs/classes/Player.VideoAgentMesh.html +0 -142
  18. package/docs/classes/Player.VideoAgentScene.html +0 -1
  19. package/docs/demo/assets/AppReact.20163f9a.js +0 -1
  20. package/docs/demo/assets/default.17872c62.css +0 -1
  21. package/docs/demo/assets/default.5069891b.js +0 -3988
  22. package/docs/demo/assets/dynamic.c8118cc9.js +0 -1
  23. package/docs/demo/assets/examples.5391fc1f.js +0 -25
  24. package/docs/demo/assets/examples.dac4a6fe.css +0 -1
  25. package/docs/demo/assets/index.2272a9ef.js +0 -1
  26. package/docs/demo/assets/index.9331038f.css +0 -1
  27. package/docs/demo/assets/main.b335b989.js +0 -1
  28. package/docs/demo/assets/react.2ee8565f.css +0 -1
  29. package/docs/demo/assets/react.efea3f3f.js +0 -25
  30. package/docs/demo/assets/znRoyv06SZQeqA7m.0057e8ae.js +0 -1
  31. package/docs/demo/examples.html +0 -17
  32. package/docs/demo/index-react-dynamic.html +0 -20
  33. package/docs/demo/index-react.html +0 -20
  34. package/docs/demo/index.html +0 -19
  35. package/docs/enums/Player.InfoPanelStyleEnum.html +0 -1
  36. package/docs/enums/Player.InfoPanelTypeEnum.html +0 -3
  37. package/docs/enums/Player.PanoEffectEnum.html +0 -5
  38. package/docs/enums/Player.PanoTagEnum.html +0 -3
  39. package/docs/enums/Player.PanoTagStyleEnum.html +0 -7
  40. package/docs/enums/Player.VreoKeyframeEnum.html +0 -25
  41. package/docs/enums/fivePlugins.CameraMovementEffect.html +0 -1
  42. package/docs/enums/fivePlugins.Rotation.html +0 -1
  43. package/docs/index.html +0 -248
  44. package/docs/interfaces/Player.CustomVreoKeyframeProps.html +0 -1
  45. package/docs/interfaces/Player.PlayerConfigs.html +0 -7
  46. package/docs/interfaces/Player.Vertex.html +0 -3
  47. package/docs/interfaces/Player.VideoAgentMeshOptions.html +0 -8
  48. package/docs/interfaces/Player.VreoKeyframe.html +0 -3
  49. package/docs/interfaces/Player.VreoUnit.html +0 -3
  50. package/docs/interfaces/Player.VreoVideo.html +0 -3
  51. package/docs/interfaces/fivePlugins.CSS3DRenderPluginExportType.html +0 -4
  52. package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +0 -1
  53. package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +0 -7
  54. package/docs/interfaces/fivePlugins.CameraMovementPluginParameterType.html +0 -1
  55. package/docs/interfaces/fivePlugins.ModelTVVideoPluginData.html +0 -1
  56. package/docs/interfaces/fivePlugins.ModelTVVideoPluginExportType.html +0 -1
  57. package/docs/interfaces/fivePlugins.ModelTVVideoPluginParameterType.html +0 -1
  58. package/docs/interfaces/fivePlugins.Vector3Position.html +0 -3
  59. package/docs/interfaces/react.VreoActionCallbacks.html +0 -23
  60. package/docs/interfaces/react.VreoProviderProps.html +0 -1
  61. package/docs/modules/Player.html +0 -37
  62. package/docs/modules/custom.html +0 -3
  63. package/docs/modules/fivePlugins.html +0 -6
  64. package/docs/modules/react.html +0 -1
  65. package/docs/modules.html +0 -1
  66. package/resources/PlayController/createHTMLAudioElement.ts +0 -53
  67. package/resources/PlayController/index.ts +0 -154
  68. package/resources/Player/App.tsx +0 -66
  69. package/resources/Player/Controller.ts +0 -295
  70. package/resources/Player/custom/SpatialScenePanel/index.tsx +0 -264
  71. package/resources/Player/hooks.ts +0 -26
  72. package/resources/Player/index.tsx +0 -227
  73. package/resources/Player/modules/Drawer/index.tsx +0 -40
  74. package/resources/Player/modules/PopUp/index.tsx +0 -26
  75. package/resources/Player/modules/ResizeObserver/index.tsx +0 -23
  76. package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +0 -302
  77. package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +0 -56
  78. package/resources/Player/modules/VideoAgent/index.tsx +0 -53
  79. package/resources/Player/modules/Wave/index.tsx +0 -150
  80. package/resources/Player/modules/keyframes/BgMusic/index.tsx +0 -75
  81. package/resources/Player/modules/keyframes/CameraMovement/index.tsx +0 -37
  82. package/resources/Player/modules/keyframes/InfoPanel/index.tsx +0 -165
  83. package/resources/Player/modules/keyframes/ModelVideo/index.tsx +0 -77
  84. package/resources/Player/modules/keyframes/PanoEffect/index.tsx +0 -99
  85. package/resources/Player/modules/keyframes/PanoEffect/lineAnime.ts +0 -31
  86. package/resources/Player/modules/keyframes/PanoTag/index.tsx +0 -83
  87. package/resources/Player/modules/keyframes/PanoTextLabel/index.tsx +0 -117
  88. package/resources/Player/modules/keyframes/Prompter/index.tsx +0 -56
  89. package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +0 -99
  90. package/resources/Player/modules/keyframes/VideoEffect/index.tsx +0 -115
  91. package/resources/Player/typings.ts +0 -49
  92. package/resources/fivePlugins/CSS3DRenderPlugin/centerPoint.ts +0 -5
  93. package/resources/fivePlugins/CSS3DRenderPlugin/createResizeObserver.ts +0 -17
  94. package/resources/fivePlugins/CSS3DRenderPlugin/evenNumber.ts +0 -4
  95. package/resources/fivePlugins/CSS3DRenderPlugin/index.ts +0 -254
  96. package/resources/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.ts +0 -5
  97. package/resources/fivePlugins/CameraMovementPlugin/index.ts +0 -226
  98. package/resources/fivePlugins/CameraMovementPlugin/typings.ts +0 -59
  99. package/resources/fivePlugins/ModelTVVideoPlugin/index.ts +0 -278
  100. package/resources/index.ts +0 -1
  101. package/resources/react/index.tsx +0 -121
  102. package/resources/shared-utils/AudioLike.ts +0 -107
  103. package/resources/shared-utils/Preloader.ts +0 -35
  104. package/resources/shared-utils/addResizeListener.ts +0 -46
  105. package/resources/shared-utils/animationFrame/BetterTween.ts +0 -33
  106. package/resources/shared-utils/animationFrame/index.ts +0 -48
  107. package/resources/shared-utils/animationFrame/tween.ts +0 -51
  108. package/resources/shared-utils/createTransMatrix.ts +0 -12
  109. package/resources/shared-utils/getFileExpandedName.ts +0 -6
  110. package/resources/shared-utils/getMediaInfo.ts +0 -52
  111. package/resources/shared-utils/setElementDataset.ts +0 -18
  112. package/resources/typings/VreoUnit.ts +0 -314
@@ -1,302 +0,0 @@
1
- import * as THREE from 'three'
2
- import { Preloader } from '../../../shared-utils/Preloader'
3
- import { makeObservable, observable, runInAction } from 'mobx'
4
- import AudioLike from '../../../shared-utils/AudioLike'
5
- import { getMediaType } from '../../../shared-utils/getMediaInfo'
6
-
7
- const vertexShader = `
8
- varying vec2 vUv;
9
- varying vec2 vColorUv;
10
- varying vec2 vMaskUv;
11
- void main(){
12
- vUv = uv;
13
- vColorUv = vec2(uv.x / 2.0, uv.y);
14
- vMaskUv = vec2(0.5 + uv.x / 2.0, uv.y);
15
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
16
- }
17
- `
18
- const fragmentShaderTpl = () => `
19
- uniform int enable;
20
- uniform sampler2D map;
21
- varying vec2 vUv;
22
- varying vec2 vColorUv;
23
- varying vec2 vMaskUv;
24
-
25
- vec3 hsv2rgb(vec3 c) {
26
- const vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
27
- vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
28
- return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
29
- }
30
-
31
- vec3 rgb2hsv(vec3 c) {
32
- const vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
33
- vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
34
- vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
35
-
36
- float d = q.x - min(q.w, q.y);
37
- return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + 0.001)), d / (q.x + 0.001), q.x);
38
- }
39
-
40
- void main(void) {
41
- vec3 color = texture2D(map, vUv).xyz;
42
- float amask = 1.0;
43
-
44
- float ref = color.r;
45
- if (ref < color.b) ref = color.b;
46
- amask = color.g - ref + 0.1;
47
- amask = smoothstep(0.1, 0.3, amask);
48
- amask = 1.0 - amask;
49
-
50
- vec3 target = rgb2hsv(vec3(0.0 / 255.0, 255.0 / 255.0, 0.0 / 255.0));
51
- vec3 hsv = rgb2hsv(color);
52
- float distance = abs(hsv.x - target.x);
53
- if (distance < 0.15) {
54
- hsv.y = 0.0;
55
- }
56
- color = hsv2rgb(hsv);
57
-
58
- gl_FragColor = vec4(color.rgb, amask * float(enable));
59
- }
60
- `
61
-
62
- const cacheInstance: {
63
- videoInstance?: HTMLVideoElement
64
- audioInstance?: HTMLAudioElement
65
- } = {}
66
-
67
- export interface VideoAgentMeshOptions {
68
- /**
69
- * 自定义视频实例。
70
- */
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
82
- }
83
-
84
- /**
85
- * 视频经纪人MESH
86
- */
87
- export class VideoAgentMesh extends THREE.Mesh {
88
- options: VideoAgentMeshOptions
89
- videoUrl?: string
90
- freeze: boolean
91
- paused: boolean
92
- audioInstance: HTMLAudioElement
93
- audioLikeInstance: AudioLike
94
- $removeEventListener: () => void
95
-
96
- get mediaInstance(): HTMLAudioElement | HTMLVideoElement | AudioLike {
97
- if (!this.videoUrl) {
98
- return this.audioLikeInstance
99
- }
100
-
101
- if (getMediaType(this.videoUrl) === 'audio') {
102
- return this.audioInstance
103
- }
104
-
105
- const uniforms = (this.material as THREE.ShaderMaterial).uniforms
106
- const videoInstance = uniforms.map.value.image as HTMLVideoElement
107
-
108
- return videoInstance
109
- }
110
-
111
- /**
112
- *
113
- * @param width
114
- * @param height
115
- * @param widthSegments
116
- * @param heightSegments
117
- * @param options
118
- */
119
- constructor(
120
- width: number,
121
- height: number,
122
- widthSegments: number,
123
- heightSegments: number,
124
- options: VideoAgentMeshOptions = {
125
- preload: true
126
- },
127
- ) {
128
- if (!options.videoInstance) {
129
- if (cacheInstance.videoInstance) {
130
- options.videoInstance = cacheInstance.videoInstance
131
- } else {
132
- const videoInstance = document.createElement('video')
133
- videoInstance.style.opacity = '0'
134
- videoInstance.style.pointerEvents = 'none'
135
- videoInstance.style.display = 'none'
136
- document.body.append(videoInstance)
137
- options.videoInstance = videoInstance
138
- cacheInstance.videoInstance = videoInstance
139
- videoInstance.playsInline = true
140
- videoInstance.controls = false
141
- }
142
- }
143
-
144
- const geometry = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments)
145
- const videoTexture = new THREE.VideoTexture(options.videoInstance)
146
- const material = new THREE.ShaderMaterial({
147
- uniforms: {
148
- map: { value: videoTexture },
149
- enable: { value: 0 },
150
- },
151
- vertexShader,
152
- fragmentShader: fragmentShaderTpl(),
153
- transparent: true,
154
- })
155
-
156
- super(geometry, material)
157
- this.options = options
158
- this.freeze = false
159
- this.paused = true
160
-
161
- if (!options.audioInstance) {
162
- if (cacheInstance.audioInstance) {
163
- this.audioInstance = cacheInstance.audioInstance
164
- } else {
165
- const audioInstance = document.createElement('audio')
166
- audioInstance.crossOrigin = ''
167
- // videoInstance.muted = true
168
- audioInstance.muted = false
169
- audioInstance.autoplay = false
170
- audioInstance.style.display = 'none'
171
- document.body.appendChild(audioInstance)
172
- this.audioInstance = audioInstance
173
- cacheInstance.audioInstance = audioInstance
174
- }
175
- } else {
176
- this.audioInstance = options.audioInstance
177
- }
178
-
179
- this.audioLikeInstance = new AudioLike()
180
-
181
- makeObservable(this, { paused: observable })
182
-
183
- const updatePaused = (paused: boolean) => runInAction(() => (this.paused = paused))
184
- const onPause = () => updatePaused(true)
185
- const onPlay = () => updatePaused(false)
186
- const onEnded = () => console.log('vreo: video 播放结束')
187
-
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)
195
-
196
- this.$removeEventListener = () => {
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)
204
- }
205
- }
206
-
207
- private async update(videoUrl: string) {
208
-
209
- if (this.videoUrl === videoUrl) {
210
- return
211
- }
212
-
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
-
222
- this.freeze = true
223
- await this.mediaInstance.pause()
224
-
225
- const uniforms = (this.material as THREE.ShaderMaterial).uniforms
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)
231
-
232
- const onStart = () => {
233
- if (this.mediaInstance.currentTime === 0) return
234
- this.freeze = false
235
- this.mediaInstance.muted = false
236
- uniforms.enable.value = getMediaType(this.videoUrl) ? 1 : 0
237
- this.mediaInstance.removeEventListener('timeupdate', onStart, false)
238
-
239
- }
240
-
241
- this.mediaInstance.addEventListener('timeupdate', onStart, false)
242
- }
243
-
244
- async play(videoUrl = '', currentTime = 0, duration?: number) {
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
-
257
- if (!videoUrl) {
258
- if (this.videoUrl) await this.mediaInstance.play()
259
- else console.warn('警告:视频资源未初始化。')
260
- return true
261
- }
262
-
263
- if (videoUrl === this.videoUrl) {
264
- this.mediaInstance.currentTime = currentTime
265
- await this.mediaInstance.play()
266
- return true
267
- }
268
-
269
- await this.update(videoUrl)
270
-
271
- this.mediaInstance.pause()
272
-
273
- return await new Promise((resolve) =>
274
- setTimeout(async () => {
275
- this.mediaInstance.currentTime = currentTime
276
- await this.mediaInstance.play()
277
- resolve(true)
278
- }, 20),
279
- )
280
- }
281
-
282
- /**
283
- * 秒转成毫秒,保障精准度
284
- */
285
- get currentTime() {
286
- return this.mediaInstance.currentTime * 1000
287
- }
288
-
289
- dispose() {
290
- // 销毁事件监听
291
- this.$removeEventListener()
292
- if (cacheInstance.audioInstance) {
293
- document.body.removeChild(cacheInstance.audioInstance)
294
- cacheInstance.audioInstance = undefined
295
- }
296
-
297
- if (cacheInstance.videoInstance) {
298
- document.body.removeChild(cacheInstance.videoInstance)
299
- cacheInstance.videoInstance = undefined
300
- }
301
- }
302
- }
@@ -1,56 +0,0 @@
1
- import * as THREE from 'three'
2
- import { addResizeListener } from '../../../shared-utils/addResizeListener'
3
- import { getMediaType } from '../../../shared-utils/getMediaInfo'
4
- import { VideoAgentMesh, VideoAgentMeshOptions } from './VideoAgentMesh'
5
-
6
- export class VideoAgentScene {
7
- videoAgentMesh: VideoAgentMesh
8
-
9
- scene = new THREE.Scene()
10
- camera = new THREE.OrthographicCamera(-240, 240, 135, -135)
11
- renderer = new THREE.WebGLRenderer({ alpha: true })
12
- disposers: (() => void)[] = []
13
-
14
- constructor(container?: HTMLElement, options?: VideoAgentMeshOptions) {
15
-
16
- this.videoAgentMesh = new VideoAgentMesh(480, 270, 1, 1, options)
17
-
18
- // const needRender = getMediaType(this.videoAgentMesh.videoUrl) === 'video'
19
-
20
- if (container) {
21
-
22
- this.camera.position.set(0, 0, 10)
23
- this.camera.lookAt(0, 0, 0)
24
-
25
- const domElement = this.renderer.domElement
26
- domElement.classList.add('VideoAgent-canvas')
27
-
28
- const dispose = addResizeListener(container, (width, height) => {
29
- this.renderer.setSize(width * window.devicePixelRatio, height * window.devicePixelRatio)
30
- domElement.style.width = `${width}px`
31
- domElement.style.height = `${height}px`
32
- } )
33
-
34
- this.disposers.push(dispose)
35
-
36
- container.append(domElement)
37
- this.scene.add(this.videoAgentMesh)
38
-
39
- this.run()
40
- }
41
- }
42
-
43
- run = () => {
44
- // 视频开始 1s 不渲染:规避某些设备黑屏闪烁问题。视频前 2s 是最好是静默的。
45
- if (!(this.videoAgentMesh.paused || this.videoAgentMesh.freeze) && this.videoAgentMesh.currentTime > 1000) {
46
- this.renderer.render(this.scene, this.camera)
47
- }
48
-
49
- requestAnimationFrame(this.run)
50
- }
51
-
52
- dispose = () => {
53
- this.videoAgentMesh?.dispose()
54
- this.disposers.forEach(disposer => disposer?.())
55
- }
56
- }
@@ -1,53 +0,0 @@
1
- import * as React from 'react'
2
- import { useController } from '../../hooks'
3
- import { VideoAgentMeshOptions } from './VideoAgentMesh'
4
- import { VideoAgentScene } from './VideoAgentScene'
5
- import classNames from 'classnames'
6
-
7
- export function VideoAgent(props: { onClick?: () => void; options?: VideoAgentMeshOptions }) {
8
- const ref = React.useRef<HTMLDivElement>(null)
9
- const controller = useController()
10
-
11
- const showAvatar = React.useMemo(() => {
12
- return controller.avatar?.url && (controller.avatar.force === true)
13
- }, [controller.avatar])
14
-
15
- const showVideoAgent = React.useMemo(() => {
16
- if (showAvatar) return false
17
- return controller.videoAgentScene?.videoAgentMesh.mediaInstance instanceof HTMLVideoElement
18
- }, [controller.videoAgentScene, showAvatar])
19
-
20
- React.useEffect(() => {
21
- if (!ref.current) throw new Error('React 渲染异常,请稍后重试 ...')
22
- if (controller.videoAgentScene) {
23
- console.warn('VideoAgentScene" 重复初始化,已被过滤')
24
- return
25
- }
26
- const videoAgentScene = new VideoAgentScene(ref.current, props.options)
27
- controller.videoAgentScene = videoAgentScene
28
-
29
- return () => {
30
- controller.dispose()
31
- controller.videoAgentScene?.dispose()
32
- }
33
- }, [])
34
-
35
- return (
36
- <>
37
- <div className="Avatar" style={{display: showAvatar ? 'block' : 'none'}}>
38
- <div className="Avatar-wrapper ratio-1-1">
39
- <img className="Avatar-img" src={controller.avatar?.url} onClick={() => props.onClick?.()} />
40
- </div>
41
- </div>
42
- <div className={classNames('VideoAgent', { hide: !showVideoAgent })}>
43
- <div className="VideoAgent-container">
44
- <div className="VideoAgent-wrapper ratio-16-9">
45
- <div className="VideoAgent-inner" ref={ref}>
46
- <div className="VideoAgent-play" onClick={() => props.onClick?.()}></div>
47
- </div>
48
- </div>
49
- </div>
50
- </div>
51
- </>
52
- )
53
- }
@@ -1,150 +0,0 @@
1
- import { WaveAppearance } from '../../typings'
2
- import React, { FC, useState, useCallback, useRef, useEffect, ReactNode } from 'react';
3
-
4
-
5
- const prefix = 'https://vr-public.realsee-cdn.cn/release/static/image/release/'
6
-
7
- const WAVES = {
8
- single: {
9
- width: 766,
10
- height: 60,
11
- frames: 20,
12
- hevc: 'vapor/static/wave-single.140d197f4838c130b69e87dfd0705479.mov',
13
- vp9: 'vapor/static/wave-single.eda65de390a830193fff40d1f1255555.webm',
14
- png: 'vapor/static/wave-single.f51aade2a6e1c59211698a1a24e6135f.png',
15
- },
16
- double: {
17
- width: 766,
18
- height: 60,
19
- frames: 16,
20
- hevc: 'vapor/static/wave-double.3e6d73050ee6958cc3060b107ebe5f39.mov',
21
- vp9: '/vapor/static/wave-double.77dfe8548ebcb3f3d336785d4fe9c7b2.webm',
22
- png: '/vapor/static/wave-double.ab4fe7d8a70395109ca4f759af7bd53f.png',
23
- },
24
- solid: {
25
- width: 1126,
26
- height: 90,
27
- frames: 48,
28
- hevc: 'vapor/static/wave-solid.cf68912a93275d07aa6b5097ea11fdda.mov',
29
- vp9: 'vapor/static/wave-solid.64438b63cbb346906d066bb7b8dc3e20.webm',
30
- png: 'vapor/static/wave-solid.6969d7f3f2f44f7ac1ade30e65660cb1.png',
31
- },
32
- swap: {
33
- width: 2250,
34
- height: 180,
35
- frames: 41,
36
- hevc: 'vapor/static/wave-swap.b38f22e2cf84ee21e9be35f7f56c9cfc.mov',
37
- vp9: 'vapor/static/wave-swap.c02e4b94cf05aecf6e7a0023bc7bb90f.webm',
38
- png: 'vapor/static/wave-swap.772ba526a7210dcc01567062c6319545.png',
39
- },
40
- expand: {
41
- width: 2250,
42
- height: 180,
43
- frames: 45,
44
- hevc: 'vapor/static/wave-expand.9529956c5954740cd4c9d07d51e32822.mov',
45
- vp9: 'vapor/static/wave-expand.a0d2a0074001cd3d4fea56818c6d3c38.webm',
46
- png: 'vapor/static/wave-expand.62fcf27b445533e6eb1b17bab5eafa0d.png',
47
- }
48
- } as const;
49
-
50
- const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : '';
51
- const isAppleDevice = /(iPhone|iPad|iPod)/i.test(userAgent);
52
- const isSafari = /safari/i.test(userAgent) && !/chrome/i.test(userAgent) && /version/i.test(userAgent);
53
- const isMicroMessenger = /microMessenger/i.test(userAgent);
54
- const canPlayHevc = isAppleDevice || isSafari;
55
- const canPlayVp9 = typeof MediaSource !== 'undefined' && MediaSource.isTypeSupported("video/webm; codecs=vp9");
56
-
57
- export function Wave(props?: { appearance?: WaveAppearance }) {
58
-
59
- const wave = React.useMemo(() => {
60
- const appearance = props?.appearance ?? 'solid'
61
- return WAVES[appearance]
62
- }, [props?.appearance])
63
-
64
- const heightWidthRatio = React.useMemo(() => {
65
- return wave.height / wave.width
66
- }, [wave])
67
-
68
- let content: ReactNode = null;
69
- if (isMicroMessenger) {
70
- content = <KeyframeWaveContent wave={wave} />
71
- } else if (canPlayHevc) {
72
- content = <VideoWaveContent format="hevc" wave={wave} />
73
- } else if (canPlayVp9) {
74
- content = <VideoWaveContent format="vp9" wave={wave} />
75
- } else {
76
- content = <KeyframeWaveContent wave={wave} />
77
- }
78
-
79
- return (
80
- <div className="vreo-wave">
81
- <div style={{position: 'relative', width: '100%', paddingTop: `${heightWidthRatio * 100}%`}}>
82
- <div style={{position: 'absolute', width: '100%', height: '100%', left: 0, top: 0}}>
83
- {content}
84
- </div>
85
- </div>
86
- </div>
87
- )
88
- }
89
-
90
- const VideoWaveContent: FC<{ wave: typeof WAVES[keyof typeof WAVES]; format: 'hevc' | 'vp9' }> = ({
91
- wave,
92
- format,
93
- }) => {
94
- const videoRef = useRef<HTMLVideoElement>(null);
95
- const [canPlay, setCanPlay] = useState(false);
96
- const [errored, setErrored] = useState(false);
97
- const source = prefix + wave[format];
98
-
99
- useEffect(() => {
100
- setCanPlay(false);
101
- }, [source]);
102
-
103
- const canPlayHandler = useCallback(() => {
104
- if (videoRef.current) {
105
- videoRef.current.play();
106
- }
107
- setCanPlay(true);
108
- }, []);
109
-
110
- const errorHandler = useCallback(() => {
111
- setErrored(true);
112
- }, []);
113
-
114
- if (errored) {
115
- return <KeyframeWaveContent wave={wave} />;
116
- }
117
-
118
- return <video
119
- style={{ opacity: canPlay ? 1 : 0 }}
120
- preload="auto"
121
- ref={videoRef}
122
- width="100%"
123
- height="100%"
124
- playsInline
125
- autoPlay
126
- onCanPlay={canPlayHandler}
127
- onError={errorHandler}
128
- muted
129
- loop
130
- src={source}
131
- />;
132
- };
133
-
134
- const KeyframeWaveContent: FC<{ wave: typeof WAVES[keyof typeof WAVES] }> = ({
135
- wave,
136
- }) => {
137
- const source = prefix + wave.png;
138
- return <div
139
- style={{
140
- width: "100%",
141
- height: "100%",
142
- backgroundImage: `url(${source})`,
143
- backgroundSize: "100%",
144
- animationName: "vreo-wave-keyframes",
145
- animationTimingFunction: `steps(${wave.frames - 1})`,
146
- animationDuration: `${wave.frames / 25}s`,
147
- animationIterationCount: 'infinite',
148
- }}
149
- />
150
- };
@@ -1,75 +0,0 @@
1
- import * as React from 'react'
2
- import { BgMusicData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
3
- import { useController } from '../../../hooks'
4
-
5
- const audioList: HTMLAudioElement[] = []
6
- function getAudio(src: string = '', currentTime: number = 0) {
7
- const audio = (() => {
8
- const audio = audioList.find(audio => audio.src === src)
9
- if (audio) return audio
10
- else {
11
- const newAudio = new Audio(src)
12
- audioList.push(newAudio)
13
- return newAudio
14
- }
15
- })()
16
- audio.currentTime = currentTime
17
- audio.setAttribute('playsinline', 'true')
18
- audio.loop = true
19
- return audio
20
- }
21
-
22
- export function BgMusic() {
23
- const controller = useController()
24
- const timeoutIdRef = React.useRef<NodeJS.Timeout | null>(null)
25
- const cleanTimeout = React.useCallback( () => {
26
- if (timeoutIdRef.current) {
27
- clearTimeout(timeoutIdRef.current)
28
- timeoutIdRef.current = null
29
- }
30
- }, [])
31
-
32
- React.useEffect(() => {
33
- const callback = (keyframe: VreoKeyframe, currentTime: number) => {
34
- console.log({currentTime})
35
- const { start, end } = keyframe
36
- const audio = getAudio(keyframe.data.url, Math.max(currentTime - start, 0))
37
- const playCallback = () => {
38
- audio.play()
39
- }
40
-
41
- audio.addEventListener('canplaythrough', playCallback)
42
-
43
- cleanTimeout()
44
-
45
- const cleanAudio = () => {
46
- console.log('cleanAudio', keyframe.start)
47
- audio.pause()
48
- audio.src = ''
49
- cleanTimeout()
50
- audio.removeEventListener('canplaythrough', playCallback)
51
- }
52
-
53
- const duration = end - start
54
-
55
- timeoutIdRef.current = setTimeout(() => {
56
- console.log('timeout', duration)
57
- cleanAudio()
58
- }, duration)
59
-
60
- controller.once('paused', () => {
61
- cleanAudio()
62
- })
63
-
64
- }
65
-
66
- controller.on(VreoKeyframeEnum.BgMusic, callback)
67
-
68
- return () => {
69
- controller.off(VreoKeyframeEnum.BgMusic, callback)
70
- cleanTimeout()
71
- }
72
- })
73
-
74
- return <></>
75
- }
@@ -1,37 +0,0 @@
1
- import * as React from 'react'
2
- import { CameraMovementPlugin } from '../../../../fivePlugins/CameraMovementPlugin'
3
- import { CameraMovementEffect, MoveArgs, RotateArgs } from '../../../../fivePlugins/CameraMovementPlugin/typings'
4
- import { CameraMovementData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
5
- import { useController, useFiveInstance } from '../../../hooks'
6
-
7
- export function CameraMovement() {
8
- const controller = useController()
9
- const five = useFiveInstance()
10
- const ref = React.useRef<ReturnType<typeof CameraMovementPlugin>>()
11
-
12
- React.useEffect(() => {
13
- const callback = async (keyframe: VreoKeyframe) => {
14
- if (!ref.current) {
15
- ref.current = CameraMovementPlugin(five, {})
16
- }
17
- const { start, end, data } = keyframe
18
- const cameraMovementData = data as CameraMovementData
19
- const effect = cameraMovementData.effect
20
- if (effect === CameraMovementEffect.Rotate) {
21
- await ref.current.rotate(data as RotateArgs, end - start)
22
- } else if (effect === CameraMovementEffect.Move) {
23
- await ref.current.move(data as MoveArgs, end - start)
24
- } else if (cameraMovementData.panoIndex !== undefined && cameraMovementData.panoIndex !== five.panoIndex) {
25
- await ref.current.move(data as MoveArgs, end - start)
26
- } else {
27
- await ref.current.rotate(data as RotateArgs, end - start)
28
- }
29
- }
30
-
31
- controller.on(VreoKeyframeEnum.CameraMovement, callback)
32
- return () => {
33
- controller.off(VreoKeyframeEnum.CameraMovement, callback)
34
- }
35
- }, [controller])
36
- return <></>
37
- }