@realsee/vreo 0.1.6 → 0.2.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.
Files changed (48) hide show
  1. package/docs/assets/search.js +1 -1
  2. package/docs/classes/Player.Player-1.html +11 -11
  3. package/docs/enums/Player.InfoPanelTypeEnum.html +1 -1
  4. package/docs/enums/Player.PanoEffectEnum.html +1 -1
  5. package/docs/enums/Player.PanoTagEnum.html +1 -1
  6. package/docs/enums/Player.VreoKeyframeEnum.html +14 -12
  7. package/docs/enums/fivePlugins.CameraMovementEffect.html +1 -1
  8. package/docs/enums/fivePlugins.Rotation.html +1 -1
  9. package/docs/interfaces/Player.PlayerConfigs.html +4 -2
  10. package/docs/interfaces/Player.Vertex.html +1 -1
  11. package/docs/interfaces/Player.VreoKeyframe.html +1 -1
  12. package/docs/interfaces/Player.VreoUnit.html +1 -1
  13. package/docs/interfaces/Player.VreoVideo.html +1 -1
  14. package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +1 -1
  15. package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +2 -2
  16. package/docs/interfaces/fivePlugins.ModelTVVideoPluginData.html +1 -1
  17. package/docs/interfaces/fivePlugins.ModelTVVideoPluginExportType.html +1 -1
  18. package/docs/interfaces/fivePlugins.ModelTVVideoPluginParameterType.html +1 -1
  19. package/docs/interfaces/react.VreoActionCallbacks.html +6 -6
  20. package/docs/modules/Player.html +12 -12
  21. package/docs/modules/fivePlugins.html +2 -2
  22. package/docs/modules/react.html +1 -1
  23. package/lib/Player/App.js +6 -2
  24. package/lib/Player/index.js +10 -7
  25. package/lib/Player/modules/Drawer/index.js +1 -1
  26. package/lib/Player/modules/VideoAgent/VideoAgentMesh.js +1 -1
  27. package/lib/Player/modules/VideoAgent/VideoAgentScene.js +19 -5
  28. package/lib/Player/modules/keyframes/BgMusic/index.d.ts +2 -0
  29. package/lib/Player/modules/keyframes/BgMusic/index.js +76 -0
  30. package/lib/Player/modules/keyframes/InfoPanel/index.js +39 -5
  31. package/lib/Player/modules/keyframes/ModelVideo/index.js +2 -2
  32. package/lib/Player/modules/keyframes/UpdateVRPanorama/index.js +58 -11
  33. package/lib/Player/typings.d.ts +5 -0
  34. package/lib/typings/VreoUnit.d.ts +31 -3
  35. package/lib/typings/VreoUnit.js +1 -0
  36. package/package.json +3 -3
  37. package/resources/Player/App.tsx +3 -0
  38. package/resources/Player/index.tsx +3 -0
  39. package/resources/Player/modules/Drawer/index.tsx +1 -1
  40. package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +1 -1
  41. package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +9 -0
  42. package/resources/Player/modules/keyframes/BgMusic/index.tsx +66 -0
  43. package/resources/Player/modules/keyframes/InfoPanel/index.tsx +34 -3
  44. package/resources/Player/modules/keyframes/ModelVideo/index.tsx +2 -2
  45. package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +65 -11
  46. package/resources/Player/typings.ts +5 -0
  47. package/resources/typings/VreoUnit.ts +32 -3
  48. package/stylesheets/default.css +35 -2
@@ -22,29 +22,76 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
22
22
  function UpdateVRPanorama() {
23
23
  var controller = (0, _hooks.useController)();
24
24
  var five = (0, _hooks.useFiveInstance)();
25
+ var rawRef = React.useRef(null);
26
+ var workRef = React.useRef(null);
27
+ var restoreCallback = React.useCallback(function () {
28
+ if (rawRef.current) {
29
+ var work = (0, _five.parseWork)(rawRef.current);
30
+ five.load(work);
31
+ }
32
+
33
+ workRef.current = null;
34
+ }, []);
35
+ var pausedCallback = React.useCallback(function () {
36
+ if (rawRef.current) {
37
+ var work = (0, _five.parseWork)(rawRef.current);
38
+ five.load(work);
39
+ }
40
+ }, []);
41
+ var playingCallback = React.useCallback(function () {
42
+ if (!workRef.current) {
43
+ return;
44
+ }
45
+
46
+ five.load(workRef.current);
47
+ }, []);
25
48
  React.useEffect(function () {
26
49
  var callback = function callback(keyframe) {
27
50
  var _five$work;
28
51
 
29
- var _ref = keyframe.data,
30
- panoIndex = _ref.panoIndex,
31
- images = _ref.images;
32
- var newWorkJSON = JSON.parse(JSON.stringify((_five$work = five.work) === null || _five$work === void 0 ? void 0 : _five$work.raw.work)); // // 原Work数据不能被修改
52
+ if (!rawRef.current) {
53
+ rawRef.current = five.work.raw.works;
54
+ }
33
55
 
34
- if (newWorkJSON.panorama && newWorkJSON.panorama.list && newWorkJSON.panorama.list[panoIndex]) {
35
- Object.assign(newWorkJSON.panorama.list[panoIndex], images);
36
- } else if (newWorkJSON.observers && newWorkJSON.observers[panoIndex] && newWorkJSON.observers[panoIndex].images) {
37
- Object.assign(newWorkJSON.observers[panoIndex].images, images);
56
+ var data = keyframe.data; // 如果数据中有新 work 数据,则直接载入
57
+
58
+ if (data.work) {
59
+ workRef.current = (0, _five.parseWork)(data.work);
60
+ five.load(workRef.current);
61
+ return;
38
62
  }
39
63
 
40
- var newWork = (0, _five.parseWork)(newWorkJSON); // // 需要还原么?待定 ...
64
+ var lastRawWork = (_five$work = five.work) === null || _five$work === void 0 ? void 0 : _five$work.raw.works[0]; // 动态场景:不提供完成的签名数据,需重新整理
65
+
66
+ if (data.dynamic_scene && !data.panorama) {
67
+ var lastWork = JSON.parse(lastRawWork);
68
+ var panorama = lastWork.panorama;
69
+ var index = data.dynamic_scene.images.index;
70
+ panorama.list[index] = data.dynamic_scene.images;
71
+ data.panorama = panorama;
72
+ delete data.dynamic_scene;
73
+ }
41
74
 
42
- five.load(newWork);
75
+ workRef.current = (0, _five.parseWork)([lastRawWork, data]);
76
+ five.load(workRef.current);
43
77
  };
44
78
 
45
- controller.on(_VreoUnit.VreoKeyframeEnum.UpdateVRPanorama, callback);
79
+ controller.on(_VreoUnit.VreoKeyframeEnum.UpdateVRPanorama, callback); // 离开 将之前的内容清空
80
+
81
+ controller.on(_VreoUnit.VreoKeyframeEnum.Exit, restoreCallback); // 新载入数据 将之前的内容清空
82
+
83
+ controller.on('loaded', restoreCallback); // 暂停 回到默认状态
84
+
85
+ controller.on('paused', pausedCallback); // 播放 回归暂停前状态
86
+
87
+ controller.on('playing', playingCallback);
46
88
  return function () {
89
+ // 清理事件监听
47
90
  controller.off(_VreoUnit.VreoKeyframeEnum.UpdateVRPanorama, callback);
91
+ controller.off(_VreoUnit.VreoKeyframeEnum.Exit, restoreCallback);
92
+ controller.off('loaded', restoreCallback);
93
+ controller.off('paused', pausedCallback);
94
+ controller.off('playing', playingCallback);
48
95
  };
49
96
  }, [controller]);
50
97
  return /*#__PURE__*/React.createElement(React.Fragment, null);
@@ -1,3 +1,4 @@
1
+ import { ReactNode } from 'react';
1
2
  import { VreoKeyframeConfigMap } from '../typings/VreoUnit';
2
3
  export interface PlayerConfigs {
3
4
  containter?: ReactDOM.Container;
@@ -11,4 +12,8 @@ export interface PlayerConfigs {
11
12
  videoEffect?: HTMLVideoElement;
12
13
  modelTVVideo?: HTMLVideoElement;
13
14
  };
15
+ /**
16
+ * 如果需要在 底部面板添加自定义内容,可以传递个 React 组件。
17
+ */
18
+ customPanelChildren?: ReactNode;
14
19
  }
@@ -1,4 +1,4 @@
1
- import { Mode, Pose, WorkCubeImage } from '@realsee/five';
1
+ import { Mode, Pose } from '@realsee/five';
2
2
  import { CameraMovementEffect, Rotation } from '../fivePlugins/CameraMovementPlugin/typings';
3
3
  export declare enum VreoKeyframeEnum {
4
4
  /** 运镜 */
@@ -35,6 +35,10 @@ export declare enum VreoKeyframeEnum {
35
35
  * 视频特效
36
36
  */
37
37
  VideoEffect = "VideoEffect",
38
+ /**
39
+ * 背景音乐
40
+ */
41
+ BgMusic = "BgMusic",
38
42
  /**
39
43
  * 结束
40
44
  */
@@ -57,6 +61,7 @@ export declare type VreoKeyframeConfigMap = {
57
61
  * 剧本关键帧
58
62
  */
59
63
  export interface VreoKeyframe {
64
+ uuid: string;
60
65
  type: VreoKeyframeEnum;
61
66
  start: number;
62
67
  end: number;
@@ -89,6 +94,7 @@ export interface VreoUnit {
89
94
  export declare type VreoKeyframeEvent = {
90
95
  [key in VreoKeyframeEnum]: (keyframe: VreoKeyframe) => void;
91
96
  } & {
97
+ loaded: (vreoUnit: VreoUnit) => void;
92
98
  paused: () => void;
93
99
  playing: () => void;
94
100
  };
@@ -113,8 +119,22 @@ export declare type PrompterData = {
113
119
  * VR 全景切换
114
120
  */
115
121
  export declare type UpdateVRPanoramaData = {
116
- panoIndex: number;
117
- images: WorkCubeImage;
122
+ _signature: string;
123
+ allow_hosts: string[];
124
+ certificate: string;
125
+ expire_at: string;
126
+ dynamic_scene?: {
127
+ images: {
128
+ index: number;
129
+ right: string;
130
+ left: string;
131
+ up: string;
132
+ down: string;
133
+ front: string;
134
+ back: string;
135
+ };
136
+ };
137
+ [key: string]: any;
118
138
  };
119
139
  /**
120
140
  * 顶点
@@ -195,6 +215,8 @@ export declare enum InfoPanelTypeEnum {
195
215
  export declare type InfoPanelData = {
196
216
  type: InfoPanelTypeEnum;
197
217
  url: string;
218
+ tilte?: string;
219
+ subTitle?: string;
198
220
  };
199
221
  /**
200
222
  * 视频特效
@@ -206,5 +228,11 @@ export declare type VideoEffectData = {
206
228
  direction?: Vertex;
207
229
  vector?: Pick<Pose, 'longitude' | 'latitude'>;
208
230
  };
231
+ /**
232
+ * 背景音乐
233
+ */
234
+ export declare type BgMusicData = {
235
+ url: string;
236
+ };
209
237
  /** 自定义序列帧 */
210
238
  export declare type CustomData = Record<string, any>;
@@ -21,6 +21,7 @@ exports.VreoKeyframeEnum = VreoKeyframeEnum;
21
21
  VreoKeyframeEnum["PanoEffect"] = "PanoEffect";
22
22
  VreoKeyframeEnum["InfoPanel"] = "InfoPanel";
23
23
  VreoKeyframeEnum["VideoEffect"] = "VideoEffect";
24
+ VreoKeyframeEnum["BgMusic"] = "BgMusic";
24
25
  VreoKeyframeEnum["Exit"] = "Exit";
25
26
  VreoKeyframeEnum["Custom"] = "Custom";
26
27
  })(VreoKeyframeEnum || (exports.VreoKeyframeEnum = VreoKeyframeEnum = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@realsee/vreo",
3
- "version": "0.1.6",
3
+ "version": "0.2.0-alpha.1",
4
4
  "description": "Vreo (VR Video 缩写) 是基于如视三维渲染引擎 Five 和 用户界面构建库 React 实现的如视 3D 空间剧本播放器。",
5
5
  "keywords": [
6
6
  "realsee",
@@ -25,7 +25,7 @@
25
25
  "packages": "node ./dev-tools/build-packages.js"
26
26
  },
27
27
  "peerDependencies": {
28
- "@realsee/five": "^5.0.0-alpha.53",
28
+ "@realsee/five": "^5.0.0-alpha.103",
29
29
  "react": "^16.0.0",
30
30
  "react-dom": "^16.0.0"
31
31
  },
@@ -35,7 +35,7 @@
35
35
  "@babel/preset-env": "^7.16.4",
36
36
  "@babel/preset-react": "^7.16.0",
37
37
  "@babel/preset-typescript": "^7.16.0",
38
- "@realsee/five": "^5.0.0-alpha.80",
38
+ "@realsee/five": "^5.0.0-alpha.103",
39
39
  "@types/offscreencanvas": "^2019.6.4",
40
40
  "@types/react": "^17.0.37",
41
41
  "@types/react-dom": "^17.0.11",
@@ -13,6 +13,7 @@ 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 }) => {
18
19
  return (
@@ -35,6 +36,7 @@ const AppView = observer(({ controller }: { controller: Controller }) => {
35
36
  }}
36
37
  />
37
38
  <Prompter />
39
+ {controller.configs?.customPanelChildren}
38
40
  </div>
39
41
  </div>
40
42
  )
@@ -53,6 +55,7 @@ export function App() {
53
55
  <PanoTextLabel />
54
56
  <InfoPanel />
55
57
  <PanoEffect />
58
+ <BgMusic />
56
59
  </>
57
60
  <AppView controller={controller} />
58
61
  </>
@@ -58,6 +58,7 @@ export class Player extends Subscribe<VreoKeyframeEvent> {
58
58
  async load(vreoUnit: VreoUnit, currentTime = 0) {
59
59
  if (!this.controller.visible) {
60
60
  this.controller.setVisible(true)
61
+ // 延迟 500ms 规避跟 DOM 动画冲突
61
62
  await new Promise((resolve) => {
62
63
  setTimeout(() => resolve(true), 500)
63
64
  })
@@ -71,6 +72,8 @@ export class Player extends Subscribe<VreoKeyframeEvent> {
71
72
  this.controller.vreoUnit = vreoUnit
72
73
  this.controller.videoInstance?.pause()
73
74
 
75
+ // 新数据载入就绪
76
+ this.emit('loaded', vreoUnit)
74
77
  if (vreoUnit.video.url) {
75
78
  if (this.controller.videoAgentScene?.videoAgentMesh.videoInstance) {
76
79
  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) {
@@ -196,7 +196,7 @@ export class VideoAgentMesh extends THREE.Mesh {
196
196
  }
197
197
 
198
198
  async play(videoUrl = '') {
199
- videoUrl = (videoUrl || '').replace(/https*:/, '')
199
+ videoUrl = videoUrl || ''
200
200
  if (!videoUrl) {
201
201
  if (this.videoUrl) await this.videoInstance.play()
202
202
  else console.warn('警告:视频资源未初始化。')
@@ -31,10 +31,19 @@ export class VideoAgentScene {
31
31
  }
32
32
 
33
33
  run = () => {
34
+ const domElement = this.renderer.domElement
35
+
34
36
  // 视频开始 1s 不渲染:规避某些设备黑屏闪烁问题。视频前 2s 是最好是静默的。
35
37
  if (!(this.videoAgentMesh.paused || this.videoAgentMesh.freeze) && this.videoAgentMesh.currentTime > 1000) {
36
38
  this.renderer.render(this.scene, this.camera)
37
39
  }
40
+
41
+ // 兼容非视频场景
42
+ if (!this.videoAgentMesh.videoUrl?.endsWith('.mp4')) {
43
+ if (domElement.style.display !== 'none') domElement.style.display = 'none'
44
+ } else {
45
+ if (domElement.style.display !== 'block') domElement.style.display = 'block'
46
+ }
38
47
  requestAnimationFrame(this.run)
39
48
  }
40
49
 
@@ -0,0 +1,66 @@
1
+ import * as React from 'react'
2
+ import { BgMusicData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
3
+ import { useController } from '../../../hooks'
4
+
5
+ export function BgMusic() {
6
+ const controller = useController()
7
+ const timeoutIdRef = React.useRef<NodeJS.Timeout | null>(null)
8
+ const cleanTimeout = React.useCallback( () => {
9
+ if (timeoutIdRef.current) {
10
+ clearTimeout(timeoutIdRef.current)
11
+ timeoutIdRef.current = null
12
+ }
13
+ }, [])
14
+
15
+ React.useEffect(() => {
16
+ const audio = new Audio()
17
+ audio.setAttribute('id', 'vreo-singleton-bgmusic')
18
+ audio.style.display = 'none'
19
+
20
+ audio.setAttribute('playsinline', 'true')
21
+ audio.loop = true
22
+ document.body.append(audio)
23
+
24
+ const callback = (keyframe: VreoKeyframe) => {
25
+ const { start, end } = keyframe
26
+ const { url } = keyframe.data as BgMusicData
27
+ audio.src = url
28
+ const playCallback = () => {
29
+ audio.play()
30
+ }
31
+
32
+ audio.addEventListener('canplaythrough', playCallback)
33
+
34
+ cleanTimeout()
35
+
36
+ const cleanAudio = () => {
37
+ audio.pause()
38
+ audio.currentTime = 0
39
+ audio.src = ''
40
+ cleanTimeout()
41
+ audio.removeEventListener('canplaythrough', playCallback)
42
+ }
43
+
44
+ const duration = (end - start) || 5000
45
+
46
+ timeoutIdRef.current = setTimeout(() => {
47
+ cleanAudio()
48
+ }, duration)
49
+
50
+ controller.once('paused', () => {
51
+ cleanAudio()
52
+ })
53
+
54
+ }
55
+
56
+ controller.on(VreoKeyframeEnum.BgMusic, callback)
57
+
58
+ return () => {
59
+ controller.off(VreoKeyframeEnum.BgMusic, callback)
60
+ document.body.removeChild(audio)
61
+ cleanTimeout()
62
+ }
63
+ })
64
+
65
+ return <></>
66
+ }
@@ -1,23 +1,42 @@
1
1
  import * as React from 'react'
2
+ import { ReactNode } from 'react'
2
3
  import { InfoPanelData, InfoPanelTypeEnum, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
3
4
  import { useController } from '../../../hooks'
4
5
 
5
- function InfoPanelImg({ url }: { url: string }) {
6
+ function InfoPanelImg({ url, children }: { url: string; children?: ReactNode }) {
6
7
  return (
7
8
  <div className="vreo-infoPanel vreo-infoPanel--img">
8
- <img className="vreo-infoPanelImg" src={url} />
9
+ {children}
10
+ <div className="vreo-infoPanelImg" style={{backgroundImage: `url(${url})`}} ></div>
9
11
  </div>
10
12
  )
11
13
  }
12
14
 
13
- function InfoPanelVideo({ url }: { url: string }) {
15
+ function InfoPanelVideo({ url, children }: { url: string; children?: ReactNode }) {
14
16
  return (
15
17
  <div className="vreo-infoPanel vreo-infoPanel--video">
18
+ {children}
16
19
  <video playsInline autoPlay className="vreo-infoPanelVideo" src={url} />
17
20
  </div>
18
21
  )
19
22
  }
20
23
 
24
+ interface TitleProps {
25
+ title?: string
26
+ subTitle?: string
27
+ }
28
+
29
+ const Title = (props: TitleProps) => {
30
+ if (!props.title && !props.subTitle) {
31
+ return null
32
+ }
33
+
34
+ return <div className="vreo-infoPanel-title">
35
+ <div className="vreo-infoPanel-t1">{props.title}</div>
36
+ <div className="vreo-infoPanel-t2">{props.subTitle}</div>
37
+ </div>
38
+ }
39
+
21
40
  export function InfoPanel() {
22
41
  const timeoutRef = React.useRef<NodeJS.Timeout | null>()
23
42
  const controller = useController()
@@ -30,6 +49,8 @@ export function InfoPanel() {
30
49
  const { start, end, data } = keyframe
31
50
 
32
51
  const infoPanelData = data as InfoPanelData
52
+
53
+
33
54
 
34
55
  if (infoPanelData.type === InfoPanelTypeEnum.Image) {
35
56
  controller.openDrawer({ content: <InfoPanelImg url={infoPanelData.url} />, height: '60vh' })
@@ -40,6 +61,16 @@ export function InfoPanel() {
40
61
  }
41
62
  controller.on(VreoKeyframeEnum.InfoPanel, callback)
42
63
 
64
+ Object.assign(window, { $setInfoPanel: () => {
65
+ controller.openDrawer({ content: (
66
+
67
+ // <InfoPanelImg url='//vrlab-public.ljcdn.com/release/seesay/tools/cat_music___f68fb9bbe1f7cd6d00a16456dd0b09ad.gif'>
68
+ <InfoPanelImg url='http://vrlab-public.ljcdn.com/common/images/web/d94e1bd7-0311-4b20-9c41-a1294fe43554.png'>
69
+ <Title title="场景联动抓拍图片" subTitle={"2022.02.17 14:00"} />
70
+ </InfoPanelImg>
71
+ ), height: '60vh' })
72
+ }})
73
+
43
74
  return () => {
44
75
  controller.off(VreoKeyframeEnum.InfoPanel, callback)
45
76
  if (timeoutRef.current) {
@@ -20,8 +20,8 @@ export function ModelVideo() {
20
20
  ref.current.disable()
21
21
  await ref.current.load(
22
22
  {
23
- video_src: videoSrc.replace(/https*:/, ''),
24
- video_poster_src: videoPosterSrc.replace(/https*:/, ''),
23
+ video_src: videoSrc,
24
+ video_poster_src: videoPosterSrc,
25
25
  points: [vertexs],
26
26
  },
27
27
  controller.configs?.videos?.modelTVVideo
@@ -1,34 +1,88 @@
1
1
  import * as React from 'react'
2
- import { parseWork } from '@realsee/five'
2
+ import { parseWork, Work } from '@realsee/five'
3
3
  import { useController, useFiveInstance } from '../../../hooks'
4
4
  import { UpdateVRPanoramaData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
5
5
 
6
6
  export function UpdateVRPanorama() {
7
7
  const controller = useController()
8
8
  const five = useFiveInstance()
9
+ const rawRef = React.useRef<string[] | null>(null)
10
+ const workRef = React.useRef<Work | null>(null)
11
+
12
+ const restoreCallback = React.useCallback(() => {
13
+ if (rawRef.current) {
14
+ const work = parseWork(rawRef.current)
15
+ five.load(work)
16
+ }
17
+
18
+ workRef.current = null
19
+ }, [])
20
+
21
+ const pausedCallback = React.useCallback(() => {
22
+ if (rawRef.current) {
23
+ const work = parseWork(rawRef.current)
24
+ five.load(work)
25
+ }
26
+ }, [])
27
+
28
+ const playingCallback = React.useCallback(() => {
29
+ if (!workRef.current) {
30
+ return
31
+ }
32
+ five.load(workRef.current)
33
+ }, [])
9
34
 
10
35
  React.useEffect(() => {
11
36
  const callback = (keyframe: VreoKeyframe) => {
12
- const { panoIndex, images } = keyframe.data as UpdateVRPanoramaData
37
+ if (!rawRef.current) {
38
+ rawRef.current = five.work.raw.works
39
+ }
13
40
 
14
- const newWorkJSON = JSON.parse(JSON.stringify(five.work?.raw.work))
41
+ const data = keyframe.data as UpdateVRPanoramaData
15
42
 
16
- // // 原Work数据不能被修改
17
- if (newWorkJSON.panorama && newWorkJSON.panorama.list && newWorkJSON.panorama.list[panoIndex]) {
18
- Object.assign(newWorkJSON.panorama.list[panoIndex], images)
19
- } else if (newWorkJSON.observers && newWorkJSON.observers[panoIndex] && newWorkJSON.observers[panoIndex].images) {
20
- Object.assign(newWorkJSON.observers[panoIndex].images, images)
43
+ // 如果数据中有新 work 数据,则直接载入
44
+ if (data.work) {
45
+ workRef.current = parseWork(data.work)
46
+ five.load(workRef.current)
47
+ return
21
48
  }
22
49
 
23
- const newWork = parseWork(newWorkJSON)
50
+ const lastRawWork = five.work?.raw.works[0]
51
+
52
+ // 动态场景:不提供完成的签名数据,需重新整理
53
+ if (data.dynamic_scene && !data.panorama) {
54
+ const lastWork = JSON.parse(lastRawWork)
55
+ const panorama = lastWork.panorama
56
+ const index = data.dynamic_scene.images.index
57
+ panorama.list[index] = data.dynamic_scene.images
58
+ data.panorama = panorama
59
+ delete data.dynamic_scene
60
+ }
24
61
 
25
- // // 需要还原么?待定 ...
26
- five.load(newWork)
62
+ workRef.current = parseWork([lastRawWork, data])
63
+ five.load(workRef.current)
27
64
  }
28
65
 
29
66
  controller.on(VreoKeyframeEnum.UpdateVRPanorama, callback)
67
+
68
+ // 离开 将之前的内容清空
69
+ controller.on(VreoKeyframeEnum.Exit, restoreCallback)
70
+
71
+ // 新载入数据 将之前的内容清空
72
+ controller.on('loaded', restoreCallback)
73
+
74
+ // 暂停 回到默认状态
75
+ controller.on('paused', pausedCallback)
76
+ // 播放 回归暂停前状态
77
+ controller.on('playing', playingCallback)
78
+
30
79
  return () => {
80
+ // 清理事件监听
31
81
  controller.off(VreoKeyframeEnum.UpdateVRPanorama, callback)
82
+ controller.off(VreoKeyframeEnum.Exit, restoreCallback)
83
+ controller.off('loaded', restoreCallback)
84
+ controller.off('paused', pausedCallback)
85
+ controller.off('playing', playingCallback)
32
86
  }
33
87
  }, [controller])
34
88
 
@@ -1,3 +1,4 @@
1
+ import { ReactNode } from 'react';
1
2
  import { VreoKeyframeConfigMap } from '../typings/VreoUnit'
2
3
 
3
4
  export interface PlayerConfigs {
@@ -12,4 +13,8 @@ export interface PlayerConfigs {
12
13
  videoEffect?: HTMLVideoElement
13
14
  modelTVVideo?: HTMLVideoElement
14
15
  }
16
+ /**
17
+ * 如果需要在 底部面板添加自定义内容,可以传递个 React 组件。
18
+ */
19
+ customPanelChildren?: ReactNode
15
20
  }
@@ -1,4 +1,4 @@
1
- import { Mode, Pose, WorkCubeImage } from '@realsee/five'
1
+ import { Mode, Pose, WorkCubeImage, Work } from '@realsee/five'
2
2
  import { CameraMovementEffect, Rotation } from '../fivePlugins/CameraMovementPlugin/typings'
3
3
 
4
4
  export enum VreoKeyframeEnum {
@@ -36,6 +36,10 @@ export enum VreoKeyframeEnum {
36
36
  * 视频特效
37
37
  */
38
38
  VideoEffect = 'VideoEffect',
39
+ /**
40
+ * 背景音乐
41
+ */
42
+ BgMusic = 'BgMusic',
39
43
  /**
40
44
  * 结束
41
45
  */
@@ -61,6 +65,7 @@ export type VreoKeyframeConfigMap = {
61
65
  * 剧本关键帧
62
66
  */
63
67
  export interface VreoKeyframe {
68
+ uuid: string
64
69
  type: VreoKeyframeEnum
65
70
  start: number
66
71
  end: number
@@ -96,6 +101,7 @@ export interface VreoUnit {
96
101
  * 剧本事件
97
102
  */
98
103
  export type VreoKeyframeEvent = { [key in VreoKeyframeEnum]: (keyframe: VreoKeyframe) => void } & {
104
+ loaded: (vreoUnit: VreoUnit) => void
99
105
  paused: () => void
100
106
  playing: () => void
101
107
  }
@@ -123,8 +129,22 @@ export type PrompterData = {
123
129
  * VR 全景切换
124
130
  */
125
131
  export type UpdateVRPanoramaData = {
126
- panoIndex: number
127
- images: WorkCubeImage
132
+ _signature: string
133
+ allow_hosts: string[]
134
+ certificate: string
135
+ expire_at: string
136
+ dynamic_scene?: {
137
+ images: {
138
+ index: number
139
+ right: string
140
+ left: string
141
+ up: string
142
+ down: string
143
+ front: string
144
+ back: string
145
+ }
146
+ }
147
+ [key: string]: any
128
148
  }
129
149
 
130
150
  /**
@@ -215,6 +235,8 @@ export enum InfoPanelTypeEnum {
215
235
  export type InfoPanelData = {
216
236
  type: InfoPanelTypeEnum
217
237
  url: string
238
+ tilte?: string
239
+ subTitle?: string
218
240
  }
219
241
 
220
242
  /**
@@ -228,5 +250,12 @@ export type VideoEffectData = {
228
250
  vector?: Pick<Pose, 'longitude' | 'latitude'>
229
251
  }
230
252
 
253
+ /**
254
+ * 背景音乐
255
+ */
256
+ export type BgMusicData = {
257
+ url: string
258
+ }
259
+
231
260
  /** 自定义序列帧 */
232
261
  export type CustomData = Record<string, any>