@realsee/vreo 0.1.6 → 0.2.0-alpha.3

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 (71) hide show
  1. package/README.md +36 -13
  2. package/docs/assets/custom.css +2 -2
  3. package/docs/assets/search.js +1 -1
  4. package/docs/classes/Player.Controller.html +54 -0
  5. package/docs/classes/Player.Player-1.html +11 -11
  6. package/docs/classes/Player.VideoAgentMesh.html +142 -0
  7. package/docs/classes/Player.VideoAgentScene.html +1 -0
  8. package/docs/enums/Player.InfoPanelTypeEnum.html +1 -1
  9. package/docs/enums/Player.PanoEffectEnum.html +2 -2
  10. package/docs/enums/Player.PanoTagEnum.html +1 -1
  11. package/docs/enums/Player.VreoKeyframeEnum.html +14 -12
  12. package/docs/enums/fivePlugins.CameraMovementEffect.html +1 -1
  13. package/docs/enums/fivePlugins.Rotation.html +1 -1
  14. package/docs/index.html +25 -16
  15. package/docs/interfaces/Player.CustomVreoKeyframeProps.html +1 -0
  16. package/docs/interfaces/Player.PlayerConfigs.html +4 -2
  17. package/docs/interfaces/Player.Vertex.html +1 -1
  18. package/docs/interfaces/Player.VideoAgentMeshOptions.html +1 -0
  19. package/docs/interfaces/Player.VreoKeyframe.html +1 -1
  20. package/docs/interfaces/Player.VreoUnit.html +1 -1
  21. package/docs/interfaces/Player.VreoVideo.html +1 -1
  22. package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +1 -1
  23. package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +3 -3
  24. package/docs/interfaces/fivePlugins.CameraMovementPluginParameterType.html +1 -1
  25. package/docs/interfaces/fivePlugins.ModelTVVideoPluginData.html +1 -1
  26. package/docs/interfaces/fivePlugins.ModelTVVideoPluginExportType.html +1 -1
  27. package/docs/interfaces/fivePlugins.ModelTVVideoPluginParameterType.html +1 -1
  28. package/docs/interfaces/react.VreoActionCallbacks.html +7 -7
  29. package/docs/interfaces/react.VreoProviderProps.html +1 -0
  30. package/docs/modules/Player.html +13 -13
  31. package/docs/modules/custom.html +3 -0
  32. package/docs/modules/fivePlugins.html +2 -2
  33. package/docs/modules/react.html +1 -1
  34. package/docs/modules.html +1 -1
  35. package/lib/Player/App.js +6 -2
  36. package/lib/Player/custom/SpatialScenePanel/index.d.ts +22 -0
  37. package/lib/Player/custom/SpatialScenePanel/index.js +207 -0
  38. package/lib/Player/index.js +27 -8
  39. package/lib/Player/modules/Drawer/index.js +1 -1
  40. package/lib/Player/modules/VideoAgent/VideoAgentMesh.js +1 -1
  41. package/lib/Player/modules/VideoAgent/VideoAgentScene.js +19 -5
  42. package/lib/Player/modules/keyframes/BgMusic/index.d.ts +2 -0
  43. package/lib/Player/modules/keyframes/BgMusic/index.js +76 -0
  44. package/lib/Player/modules/keyframes/InfoPanel/index.js +52 -8
  45. package/lib/Player/modules/keyframes/ModelVideo/index.js +2 -2
  46. package/lib/Player/modules/keyframes/UpdateVRPanorama/index.js +58 -11
  47. package/lib/Player/typings.d.ts +13 -1
  48. package/lib/fivePlugins/CameraMovementPlugin/index.js +6 -4
  49. package/lib/fivePlugins/CameraMovementPlugin/typings.d.ts +2 -2
  50. package/lib/react/index.d.ts +5 -1
  51. package/lib/react/index.js +1 -1
  52. package/lib/typings/VreoUnit.d.ts +32 -3
  53. package/lib/typings/VreoUnit.js +1 -0
  54. package/package.json +4 -3
  55. package/resources/Player/App.tsx +4 -1
  56. package/resources/Player/custom/SpatialScenePanel/index.tsx +161 -0
  57. package/resources/Player/index.tsx +16 -1
  58. package/resources/Player/modules/Drawer/index.tsx +1 -1
  59. package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +1 -1
  60. package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +9 -0
  61. package/resources/Player/modules/keyframes/BgMusic/index.tsx +66 -0
  62. package/resources/Player/modules/keyframes/InfoPanel/index.tsx +59 -6
  63. package/resources/Player/modules/keyframes/ModelVideo/index.tsx +2 -2
  64. package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +65 -11
  65. package/resources/Player/typings.ts +16 -1
  66. package/resources/fivePlugins/CameraMovementPlugin/index.ts +8 -6
  67. package/resources/fivePlugins/CameraMovementPlugin/typings.ts +2 -2
  68. package/resources/react/index.tsx +7 -2
  69. package/resources/typings/VreoUnit.ts +40 -3
  70. package/stylesheets/custom/SpatialScenePanel.css +303 -0
  71. package/stylesheets/default.css +46 -2
@@ -0,0 +1,161 @@
1
+ import * as React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+ import { Five } from '@realsee/five'
4
+ import { Raycaster, Vector3 } from 'three'
5
+ import { tweenProgress } from '@realsee/dnalogel/shared-utils/animationFrame/BetterTween'
6
+ import { CSS3DRenderPlugin, CSS3DRenderPluginExportType } from '@realsee/dnalogel/plugins/CSS3DRenderPlugin'
7
+
8
+ import { VreoKeyframe, VreoKeyframeEnum } from '../../../typings/VreoUnit'
9
+ import { CustomVreoKeyframeProps } from '../../typings'
10
+
11
+ export interface SpatialScenePanelData {
12
+ customType: 'SpatialScenePanel'
13
+ title: string
14
+ temperature: string
15
+ stateList: {
16
+ text: string
17
+ icon: string
18
+ }[]
19
+ position: { x: number; y: number; z: number }
20
+ quaternion: [number, number, number, number]
21
+ }
22
+
23
+ interface SearchParams {
24
+ five: Five
25
+ position: Vector3
26
+ rotation?: Vector3
27
+ quaternion: [number, number, number, number]
28
+ dom: HTMLDivElement
29
+ }
30
+
31
+ const searchV1 = ({ five, position, rotation, dom }: SearchParams) => {
32
+ const cameraDirection = new Vector3()
33
+ five.camera.getWorldDirection(cameraDirection)
34
+ const cameraPosition = five.camera.position
35
+ const [intersect] = five.model.intersectRaycaster(new Raycaster(cameraPosition, cameraDirection))
36
+ const point = five.project2d(intersect.point)
37
+
38
+ // const width = dom!.clientWidth
39
+ const height = dom!.clientHeight
40
+ dom!.style.left = point!.x + 'px'
41
+ dom!.style.top = point!.y - height / 2 + 'px'
42
+ const rect = dom!.getBoundingClientRect()
43
+ const { left, top, bottom, right } = rect
44
+
45
+ const leftBottom = new Vector3(left, bottom)
46
+ const leftTop = new Vector3(left, top)
47
+ const rightTop = new Vector3(right, top)
48
+ const rightBottom = new Vector3(right, bottom)
49
+
50
+ const points = [leftBottom, rightBottom, rightTop, leftTop].map((point) => {
51
+ point.setX((point.x / window.innerWidth) * 2 - 1)
52
+ point.setY(-(point.y / window.innerHeight) * 2 + 1)
53
+ point.setZ(0.5)
54
+ return point.unproject(five.camera).addScaledVector(cameraDirection, 0.2)
55
+ })
56
+
57
+ // const colors = [0xdc143c, 0xffff00, 0x0000ff, 0x008000]
58
+ // points.forEach((p, index) => five.scene.add(getSphere(p, colors[index])))
59
+
60
+ const ratio = leftBottom.distanceTo(rightBottom) / 160
61
+ return { points, ratio }
62
+ }
63
+
64
+ /**
65
+ * 空间场景面板
66
+ * @returns
67
+ */
68
+ export function SpatialScenePanel(props: CustomVreoKeyframeProps) {
69
+ const ref = React.useRef<HTMLDivElement>(null)
70
+ const panelRef = React.useRef<HTMLDivElement | null>(null)
71
+ const rendererRef = React.useRef<CSS3DRenderPluginExportType>(CSS3DRenderPlugin(props.five))
72
+
73
+ React.useEffect(() => {
74
+
75
+ if (!ref.current) {
76
+ return
77
+ }
78
+
79
+ const callback = (keyframe: VreoKeyframe) => {
80
+ if (keyframe.data.customType !== 'SpatialScenePanel') {
81
+ return
82
+ }
83
+
84
+ const data = keyframe.data as SpatialScenePanelData
85
+ // const data = mockData as SpatialScenePanelData
86
+
87
+ const { points, ratio } = searchV1({
88
+ five: props.five,
89
+ position: new Vector3(data.position.x, data.position.y, data.position.z),
90
+ quaternion: data.quaternion,
91
+ dom: ref.current!
92
+ })
93
+
94
+ console.log(points, ratio)
95
+
96
+ const { container, dispose, css3DObject, render } =
97
+ rendererRef.current.create3DDomContainer(points, { ratio, autoRender: false }) || {}
98
+
99
+ if (!container) return
100
+
101
+
102
+ ReactDOM.render(<Panel ref={(ref) => (panelRef.current = ref)} data={data} />, container)
103
+ const startRotateY = -(Math.PI * 2) / 9
104
+ let lastRotateY = 0
105
+ tweenProgress(1000)
106
+ .onUpdate(({ progress }) => {
107
+ const needRotateY = (Math.PI / 90) * 11 * progress
108
+ const rotateY = needRotateY - lastRotateY
109
+ css3DObject?.rotateY(rotateY)
110
+ lastRotateY = needRotateY
111
+ })
112
+ .onStart(() => {
113
+ css3DObject?.rotateY(startRotateY)
114
+ render!()
115
+ })
116
+ .onDispose(() => {
117
+ panelRef.current?.classList.add('show')
118
+ })
119
+ .play()
120
+ const { start, end } = keyframe
121
+ setTimeout(() => {
122
+ panelRef.current?.classList.add('hide')
123
+ setTimeout(() => dispose?.(), 1500)
124
+ }, end - start)
125
+ }
126
+
127
+ Object.assign(window, {$SpatialScenePanelCallback: callback})
128
+ props.subscribe.on(VreoKeyframeEnum.Custom, callback)
129
+
130
+ return () => {
131
+ props.subscribe.off(VreoKeyframeEnum.Custom, callback)
132
+ }
133
+ }, [])
134
+
135
+ return <div className="vreo-SpatialScenePanel" ref={ref}></div>
136
+ }
137
+
138
+ const Panel = React.forwardRef(
139
+ (props: { data: SpatialScenePanelData }, myRef: React.LegacyRef<HTMLDivElement> | undefined) => (
140
+ <div className="SpatialScenePanel" ref={myRef}>
141
+ <div className="SpatialScenePanel-show-area">
142
+ <div className="SpatialScenePanel-bg"></div>
143
+ <div className="SpatialScenePanel-header">
144
+ <div className="SpatialScenePanel-title">{props.data?.title}</div>
145
+ <div className="SpatialScenePanel-temperature">{props.data?.temperature}℃</div>
146
+ </div>
147
+ <div className="SpatialScenePanel-body">
148
+ {props.data?.stateList?.map((state, index) => (
149
+ <div key={`scene-${state.text}`} className={`SpatialScenePanel-item index_${index}`}>
150
+ <img className="SpatialScenePanel-icon" src={state.icon}></img>
151
+ <div className="SpatialScenePanel-text">{state.text}</div>
152
+ <div className="SpatialScenePanel-dot"></div>
153
+ </div>
154
+ ))}
155
+ </div>
156
+ </div>
157
+
158
+ <div className="SpatialScenePanel-disappear-area"></div>
159
+ </div>
160
+ ),
161
+ )
@@ -4,7 +4,7 @@ import { Five, Subscribe } from '@realsee/five'
4
4
 
5
5
  import { App } from './App'
6
6
  import { Controller, ControllerContext } from './Controller'
7
- import { VreoKeyframeEvent, VreoKeyframeConfigMap, VreoUnit } from '../typings/VreoUnit'
7
+ import { VreoKeyframeEvent, VreoUnit } from '../typings/VreoUnit'
8
8
  import { reaction } from 'mobx'
9
9
  import { Drawer } from './modules/Drawer'
10
10
  import { PlayerConfigs } from './typings'
@@ -42,6 +42,18 @@ export class Player extends Subscribe<VreoKeyframeEvent> {
42
42
  <ControllerContext.Provider value={this.controller}>
43
43
  <App></App>
44
44
  <Drawer />
45
+ {this.configs.customKeyframes &&
46
+ this.configs.customKeyframes.map((CustomCmpt, key) => (
47
+ <CustomCmpt
48
+ key={key}
49
+ subscribe={{
50
+ on: (name, callback) => this.on(name, callback),
51
+ once: (name, callback) => this.once(name, callback),
52
+ off: (name, callback) => this.off(name, callback),
53
+ }}
54
+ five={five}
55
+ />
56
+ ))}
45
57
  </ControllerContext.Provider>,
46
58
  configs.containter
47
59
  )
@@ -58,6 +70,7 @@ export class Player extends Subscribe<VreoKeyframeEvent> {
58
70
  async load(vreoUnit: VreoUnit, currentTime = 0) {
59
71
  if (!this.controller.visible) {
60
72
  this.controller.setVisible(true)
73
+ // 延迟 500ms 规避跟 DOM 动画冲突
61
74
  await new Promise((resolve) => {
62
75
  setTimeout(() => resolve(true), 500)
63
76
  })
@@ -71,6 +84,8 @@ export class Player extends Subscribe<VreoKeyframeEvent> {
71
84
  this.controller.vreoUnit = vreoUnit
72
85
  this.controller.videoInstance?.pause()
73
86
 
87
+ // 新数据载入就绪
88
+ this.emit('loaded', vreoUnit)
74
89
  if (vreoUnit.video.url) {
75
90
  if (this.controller.videoAgentScene?.videoAgentMesh.videoInstance) {
76
91
  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,19 +1,40 @@
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">
16
- <video playsInline autoPlay className="vreo-infoPanelVideo" src={url} />
18
+ {children}
19
+ <div className="vreo-infoPanelWrapper"><video playsInline autoPlay className="vreo-infoPanelVideo" src={url} /></div>
20
+ </div>
21
+ )
22
+ }
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 (
35
+ <div className="vreo-infoPanel-title">
36
+ <div className="vreo-infoPanel-t1">{props.title}</div>
37
+ <div className="vreo-infoPanel-t2">{props.subTitle}</div>
17
38
  </div>
18
39
  )
19
40
  }
@@ -31,15 +52,47 @@ export function InfoPanel() {
31
52
 
32
53
  const infoPanelData = data as InfoPanelData
33
54
 
55
+ const { title, subTitle } = infoPanelData
34
56
  if (infoPanelData.type === InfoPanelTypeEnum.Image) {
35
- controller.openDrawer({ content: <InfoPanelImg url={infoPanelData.url} />, height: '60vh' })
57
+ controller.openDrawer({
58
+ content: (
59
+ <InfoPanelImg url={infoPanelData.url}>
60
+ <Title title={title} subTitle={subTitle} />
61
+ </InfoPanelImg>
62
+ ),
63
+ height: '60vh',
64
+ })
36
65
  } else if (infoPanelData.type === InfoPanelTypeEnum.Video) {
37
- controller.openDrawer({ content: <InfoPanelVideo url={infoPanelData.url} />, height: '60vh' })
66
+ controller.openDrawer({
67
+ content: (
68
+ <InfoPanelVideo url={infoPanelData.url}>
69
+ <Title title={title} subTitle={subTitle} />
70
+ </InfoPanelVideo>
71
+ ),
72
+ height: '60vh',
73
+ })
38
74
  }
39
75
  timeoutRef.current = setTimeout(() => controller.openDrawer(false), end - start)
40
76
  }
41
77
  controller.on(VreoKeyframeEnum.InfoPanel, callback)
42
78
 
79
+ // Object.assign(window, {
80
+ // $setInfoPanel: () => {
81
+ // controller.openDrawer({
82
+ // content: (
83
+ // // <InfoPanelImg url='//vrlab-public.ljcdn.com/release/seesay/tools/cat_music___f68fb9bbe1f7cd6d00a16456dd0b09ad.gif'>
84
+ // // <InfoPanelImg url="http://vrlab-public.ljcdn.com/common/images/web/d94e1bd7-0311-4b20-9c41-a1294fe43554.png">
85
+ // // <Title title="场景联动抓拍图片" subTitle={'2022.02.17 14:00'} />
86
+ // // </InfoPanelImg>
87
+ // <InfoPanelVideo url="//vrlab-public.ljcdn.com/release/seesay/tools/2022011713142___b320f74a5e1b5ad4bb46b4dc69d73ecc.mp4">
88
+ // <Title title="场景联动抓拍图片" subTitle={'2022.02.17 14:00'} />
89
+ // </InfoPanelVideo>
90
+ // ),
91
+ // height: '60vh',
92
+ // })
93
+ // },
94
+ // })
95
+
43
96
  return () => {
44
97
  controller.off(VreoKeyframeEnum.InfoPanel, callback)
45
98
  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,4 +1,7 @@
1
- import { VreoKeyframeConfigMap } from '../typings/VreoUnit'
1
+ import React, { ReactNode } from 'react';
2
+ import { Subscribe, Five } from '@realsee/five';
3
+
4
+ import { VreoKeyframeConfigMap, VreoKeyframeEvent } from '../typings/VreoUnit'
2
5
 
3
6
  export interface PlayerConfigs {
4
7
  containter?: ReactDOM.Container
@@ -12,4 +15,16 @@ export interface PlayerConfigs {
12
15
  videoEffect?: HTMLVideoElement
13
16
  modelTVVideo?: HTMLVideoElement
14
17
  }
18
+ /**
19
+ * 如果需要在 底部面板添加自定义内容,可以传递个 React 组件。
20
+ */
21
+ customPanelChildren?: ReactNode
22
+ customKeyframes?: React.FC<CustomVreoKeyframeProps>[]
23
+ }
24
+
25
+ export type VreoSubscribe = Pick<Subscribe<VreoKeyframeEvent>, 'on' | 'once' | 'off'>
26
+
27
+ export interface CustomVreoKeyframeProps {
28
+ subscribe: VreoSubscribe
29
+ five: Five
15
30
  }
@@ -1,4 +1,4 @@
1
- import { Five } from '@realsee/five'
1
+ import { Five, MovePanoOptions } from '@realsee/five'
2
2
  import type { FivePlugin } from '@realsee/five'
3
3
  import * as TWEEN from '@tweenjs/tween.js'
4
4
 
@@ -97,14 +97,16 @@ export const CameraMovementPlugin: FivePlugin<CameraMovementPluginParameterType,
97
97
  return await new Promise<boolean>((resolve, reject) => {
98
98
  const panoIndex = args.panoIndex !== undefined ? args.panoIndex : five.panoIndex
99
99
  if (panoIndex !== undefined) {
100
+ const movePanoOptions: MovePanoOptions = {
101
+ duration, // 移动耗时
102
+ moveEndCallback: () => resolve(true), // 移动结束
103
+ moveCancelCallback: () => reject(false), // 移动开始
104
+ effect: 'fade',
105
+ }
100
106
  five.moveToPano(
101
107
  panoIndex,
102
108
  Object.assign(
103
- {
104
- duration, // 移动耗时
105
- moveEndCallback: () => resolve(true), // 移动结束
106
- moveCancelCallback: () => reject(false), // 移动开始
107
- },
109
+ movePanoOptions,
108
110
  args,
109
111
  ),
110
112
  )
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable prettier/prettier */
2
- import { Mode, Pose } from '@realsee/five'
2
+ import { Mode, MovePanoOptions, Pose } from '@realsee/five'
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
5
5
  export interface CameraMovementPluginParameterType { }
@@ -39,7 +39,7 @@ export interface CameraMovementOptsCallback {
39
39
  export type MoveArgs = {
40
40
  mode: Mode
41
41
  panoIndex: number
42
- } & Pose
42
+ } & Pose & Pick<MovePanoOptions, 'effect'>
43
43
 
44
44
  export type MoveOpts = {
45
45
  preload?: boolean
@@ -1,18 +1,23 @@
1
1
  import { unsafe__useFiveInstance } from '@realsee/five/react'
2
2
  import * as React from 'react'
3
3
  import { Player } from '../Player'
4
+ import { PlayerConfigs } from '../Player/typings'
4
5
  import { VreoKeyframeEvent, VreoUnit } from '../typings/VreoUnit'
5
6
 
6
7
  const VreoContext = React.createContext<Player | null>(null)
7
8
 
8
- export const VreoProvider: React.FC = (props) => {
9
+ export interface VreoProviderProps {
10
+ configs?: Partial<PlayerConfigs>
11
+ }
12
+
13
+ export const VreoProvider: React.FC<VreoProviderProps> = (props ) => {
9
14
  const five = unsafe__useFiveInstance()
10
15
 
11
16
  const [player, setPlayer] = React.useState<Player | null>(null)
12
17
  const playerRef = React.useRef<Player | null>(null)
13
18
 
14
19
  React.useEffect(() => {
15
- playerRef.current = new Player(five)
20
+ playerRef.current = new Player(five, props.configs || {})
16
21
  setPlayer(playerRef.current)
17
22
 
18
23
  return () => {