@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.
- package/README.md +36 -13
- package/docs/assets/custom.css +2 -2
- package/docs/assets/search.js +1 -1
- package/docs/classes/Player.Controller.html +54 -0
- package/docs/classes/Player.Player-1.html +11 -11
- package/docs/classes/Player.VideoAgentMesh.html +142 -0
- package/docs/classes/Player.VideoAgentScene.html +1 -0
- package/docs/enums/Player.InfoPanelTypeEnum.html +1 -1
- package/docs/enums/Player.PanoEffectEnum.html +2 -2
- package/docs/enums/Player.PanoTagEnum.html +1 -1
- package/docs/enums/Player.VreoKeyframeEnum.html +14 -12
- package/docs/enums/fivePlugins.CameraMovementEffect.html +1 -1
- package/docs/enums/fivePlugins.Rotation.html +1 -1
- package/docs/index.html +25 -16
- package/docs/interfaces/Player.CustomVreoKeyframeProps.html +1 -0
- package/docs/interfaces/Player.PlayerConfigs.html +4 -2
- package/docs/interfaces/Player.Vertex.html +1 -1
- package/docs/interfaces/Player.VideoAgentMeshOptions.html +1 -0
- package/docs/interfaces/Player.VreoKeyframe.html +1 -1
- package/docs/interfaces/Player.VreoUnit.html +1 -1
- package/docs/interfaces/Player.VreoVideo.html +1 -1
- package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +1 -1
- package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +3 -3
- 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/react.VreoActionCallbacks.html +7 -7
- package/docs/interfaces/react.VreoProviderProps.html +1 -0
- package/docs/modules/Player.html +13 -13
- package/docs/modules/custom.html +3 -0
- package/docs/modules/fivePlugins.html +2 -2
- package/docs/modules/react.html +1 -1
- package/docs/modules.html +1 -1
- package/lib/Player/App.js +6 -2
- package/lib/Player/custom/SpatialScenePanel/index.d.ts +22 -0
- package/lib/Player/custom/SpatialScenePanel/index.js +207 -0
- package/lib/Player/index.js +27 -8
- package/lib/Player/modules/Drawer/index.js +1 -1
- package/lib/Player/modules/VideoAgent/VideoAgentMesh.js +1 -1
- package/lib/Player/modules/VideoAgent/VideoAgentScene.js +19 -5
- package/lib/Player/modules/keyframes/BgMusic/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/BgMusic/index.js +76 -0
- package/lib/Player/modules/keyframes/InfoPanel/index.js +52 -8
- package/lib/Player/modules/keyframes/ModelVideo/index.js +2 -2
- package/lib/Player/modules/keyframes/UpdateVRPanorama/index.js +58 -11
- package/lib/Player/typings.d.ts +13 -1
- package/lib/fivePlugins/CameraMovementPlugin/index.js +6 -4
- package/lib/fivePlugins/CameraMovementPlugin/typings.d.ts +2 -2
- package/lib/react/index.d.ts +5 -1
- package/lib/react/index.js +1 -1
- package/lib/typings/VreoUnit.d.ts +32 -3
- package/lib/typings/VreoUnit.js +1 -0
- package/package.json +4 -3
- package/resources/Player/App.tsx +4 -1
- package/resources/Player/custom/SpatialScenePanel/index.tsx +161 -0
- package/resources/Player/index.tsx +16 -1
- package/resources/Player/modules/Drawer/index.tsx +1 -1
- package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +1 -1
- package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +9 -0
- package/resources/Player/modules/keyframes/BgMusic/index.tsx +66 -0
- package/resources/Player/modules/keyframes/InfoPanel/index.tsx +59 -6
- package/resources/Player/modules/keyframes/ModelVideo/index.tsx +2 -2
- package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +65 -11
- package/resources/Player/typings.ts +16 -1
- package/resources/fivePlugins/CameraMovementPlugin/index.ts +8 -6
- package/resources/fivePlugins/CameraMovementPlugin/typings.ts +2 -2
- package/resources/react/index.tsx +7 -2
- package/resources/typings/VreoUnit.ts +40 -3
- package/stylesheets/custom/SpatialScenePanel.css +303 -0
- 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,
|
|
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 = '
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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({
|
|
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({
|
|
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
|
|
24
|
-
video_poster_src: videoPosterSrc
|
|
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
|
-
|
|
37
|
+
if (!rawRef.current) {
|
|
38
|
+
rawRef.current = five.work.raw.works
|
|
39
|
+
}
|
|
13
40
|
|
|
14
|
-
const
|
|
41
|
+
const data = keyframe.data as UpdateVRPanoramaData
|
|
15
42
|
|
|
16
|
-
//
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
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(
|
|
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 {
|
|
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
|
|
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 () => {
|