@realsee/vreo 0.1.0
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/LICENSE +21 -0
- package/README.md +465 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/custom.css +52 -0
- package/docs/assets/highlight.css +127 -0
- package/docs/assets/icons.css +1043 -0
- package/docs/assets/icons.png +0 -0
- package/docs/assets/icons@2x.png +0 -0
- package/docs/assets/main.js +52 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1388 -0
- package/docs/assets/widgets.png +0 -0
- package/docs/assets/widgets@2x.png +0 -0
- package/docs/classes/Player.Player-1.html +50 -0
- package/docs/enums/Player.InfoPanelTypeEnum.html +3 -0
- package/docs/enums/Player.PanoEffectEnum.html +5 -0
- package/docs/enums/Player.PanoTagEnum.html +3 -0
- package/docs/enums/Player.VreoKeyframeEnum.html +388 -0
- package/docs/enums/fivePlugins.CameraMovementEffect.html +1 -0
- package/docs/enums/fivePlugins.Rotation.html +1 -0
- package/docs/index.html +204 -0
- package/docs/interfaces/Player.PlayerConfigs.html +4 -0
- package/docs/interfaces/Player.Vertex.html +3 -0
- package/docs/interfaces/Player.VreoKeyframe.html +3 -0
- package/docs/interfaces/Player.VreoUnit.html +3 -0
- package/docs/interfaces/Player.VreoVideo.html +3 -0
- package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +1 -0
- package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +7 -0
- package/docs/interfaces/fivePlugins.CameraMovementPluginParameterType.html +1 -0
- package/docs/interfaces/fivePlugins.ModelTVVideoPluginData.html +1 -0
- package/docs/interfaces/fivePlugins.ModelTVVideoPluginExportType.html +1 -0
- package/docs/interfaces/fivePlugins.ModelTVVideoPluginParameterType.html +1 -0
- package/docs/interfaces/react.VreoActionCallbacks.html +15 -0
- package/docs/modules/Player.html +29 -0
- package/docs/modules/fivePlugins.html +3 -0
- package/docs/modules/react.html +1 -0
- package/docs/modules.html +1 -0
- package/lib/Player/App.d.ts +2 -0
- package/lib/Player/App.js +68 -0
- package/lib/Player/Controller.d.ts +39 -0
- package/lib/Player/Controller.js +226 -0
- package/lib/Player/hooks.d.ts +4 -0
- package/lib/Player/hooks.js +41 -0
- package/lib/Player/index.d.ts +15 -0
- package/lib/Player/index.js +191 -0
- package/lib/Player/modules/Drawer/index.d.ts +2 -0
- package/lib/Player/modules/Drawer/index.js +67 -0
- package/lib/Player/modules/VideoAgent/VideoAgentMesh.d.ts +30 -0
- package/lib/Player/modules/VideoAgent/VideoAgentMesh.js +324 -0
- package/lib/Player/modules/VideoAgent/VideoAgentScene.d.ts +10 -0
- package/lib/Player/modules/VideoAgent/VideoAgentScene.js +65 -0
- package/lib/Player/modules/VideoAgent/index.d.ts +4 -0
- package/lib/Player/modules/VideoAgent/index.js +44 -0
- package/lib/Player/modules/keyframes/CameraMovement/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/CameraMovement/index.js +73 -0
- package/lib/Player/modules/keyframes/InfoPanel/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/InfoPanel/index.js +89 -0
- package/lib/Player/modules/keyframes/ModelVideo/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/ModelVideo/index.js +87 -0
- package/lib/Player/modules/keyframes/PanoEffect/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/PanoEffect/index.js +142 -0
- package/lib/Player/modules/keyframes/PanoEffect/lineAnime.d.ts +5 -0
- package/lib/Player/modules/keyframes/PanoEffect/lineAnime.js +46 -0
- package/lib/Player/modules/keyframes/PanoTag/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/PanoTag/index.js +168 -0
- package/lib/Player/modules/keyframes/PanoTextLabel/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/PanoTextLabel/index.js +113 -0
- package/lib/Player/modules/keyframes/Prompter/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/Prompter/index.js +105 -0
- package/lib/Player/modules/keyframes/UpdateVRPanorama/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/UpdateVRPanorama/index.js +51 -0
- package/lib/Player/modules/keyframes/VideoEffect/index.d.ts +2 -0
- package/lib/Player/modules/keyframes/VideoEffect/index.js +176 -0
- package/lib/Player/typings.d.ts +14 -0
- package/lib/Player/typings.js +5 -0
- package/lib/fivePlugins/CameraMovementPlugin/index.d.ts +6 -0
- package/lib/fivePlugins/CameraMovementPlugin/index.js +307 -0
- package/lib/fivePlugins/CameraMovementPlugin/typings.d.ts +48 -0
- package/lib/fivePlugins/CameraMovementPlugin/typings.js +25 -0
- package/lib/fivePlugins/ModelTVVideoPlugin/index.d.ts +20 -0
- package/lib/fivePlugins/ModelTVVideoPlugin/index.js +305 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +13 -0
- package/lib/react/index.d.ts +42 -0
- package/lib/react/index.js +120 -0
- package/lib/shared-utils/Preloader.d.ts +6 -0
- package/lib/shared-utils/Preloader.js +51 -0
- package/lib/shared-utils/animationFrame/BetterTween.d.ts +11 -0
- package/lib/shared-utils/animationFrame/BetterTween.js +102 -0
- package/lib/shared-utils/animationFrame/index.d.ts +15 -0
- package/lib/shared-utils/animationFrame/index.js +68 -0
- package/lib/shared-utils/animationFrame/tween.d.ts +75 -0
- package/lib/shared-utils/animationFrame/tween.js +76 -0
- package/lib/typings/VreoUnit.d.ts +204 -0
- package/lib/typings/VreoUnit.js +65 -0
- package/package.json +55 -0
- package/resources/Player/App.tsx +57 -0
- package/resources/Player/Controller.ts +154 -0
- package/resources/Player/hooks.ts +28 -0
- package/resources/Player/index.tsx +115 -0
- package/resources/Player/modules/Drawer/index.tsx +40 -0
- package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +202 -0
- package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +38 -0
- package/resources/Player/modules/VideoAgent/index.tsx +31 -0
- package/resources/Player/modules/keyframes/CameraMovement/index.tsx +33 -0
- package/resources/Player/modules/keyframes/InfoPanel/index.tsx +52 -0
- package/resources/Player/modules/keyframes/ModelVideo/index.tsx +44 -0
- package/resources/Player/modules/keyframes/PanoEffect/index.tsx +99 -0
- package/resources/Player/modules/keyframes/PanoEffect/lineAnime.ts +31 -0
- package/resources/Player/modules/keyframes/PanoTag/index.tsx +127 -0
- package/resources/Player/modules/keyframes/PanoTextLabel/index.tsx +65 -0
- package/resources/Player/modules/keyframes/Prompter/index.tsx +65 -0
- package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +36 -0
- package/resources/Player/modules/keyframes/VideoEffect/index.tsx +115 -0
- package/resources/Player/typings.ts +15 -0
- package/resources/fivePlugins/CameraMovementPlugin/index.ts +203 -0
- package/resources/fivePlugins/CameraMovementPlugin/typings.ts +57 -0
- package/resources/fivePlugins/ModelTVVideoPlugin/index.ts +278 -0
- package/resources/index.ts +1 -0
- package/resources/react/index.tsx +95 -0
- package/resources/shared-utils/Preloader.ts +35 -0
- package/resources/shared-utils/animationFrame/BetterTween.ts +33 -0
- package/resources/shared-utils/animationFrame/index.ts +48 -0
- package/resources/shared-utils/animationFrame/tween.ts +51 -0
- package/resources/typings/VreoUnit.ts +225 -0
- package/stylesheets/default.css +497 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { InfoPanelData, InfoPanelTypeEnum, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
|
|
3
|
+
import { useController } from '../../../hooks'
|
|
4
|
+
|
|
5
|
+
function InfoPanelImg({ url }: { url: string }) {
|
|
6
|
+
return (
|
|
7
|
+
<div className="vreo-infoPanel vreo-infoPanel--img">
|
|
8
|
+
<img className="vreo-infoPanelImg" src={url} />
|
|
9
|
+
</div>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function InfoPanelVideo({ url }: { url: string }) {
|
|
14
|
+
return (
|
|
15
|
+
<div className="vreo-infoPanel vreo-infoPanel--video">
|
|
16
|
+
<video playsInline autoPlay className="vreo-infoPanelVideo" src={url} />
|
|
17
|
+
</div>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function InfoPanel() {
|
|
22
|
+
const timeoutRef = React.useRef<NodeJS.Timeout | null>()
|
|
23
|
+
const controller = useController()
|
|
24
|
+
|
|
25
|
+
React.useEffect(() => {
|
|
26
|
+
if (controller.configs?.keyframeMap.InfoPanel === false) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
const callback = (keyframe: VreoKeyframe) => {
|
|
30
|
+
const { start, end, data } = keyframe
|
|
31
|
+
|
|
32
|
+
const infoPanelData = data as InfoPanelData
|
|
33
|
+
|
|
34
|
+
if (infoPanelData.type === InfoPanelTypeEnum.Image) {
|
|
35
|
+
controller.openDrawer({ content: <InfoPanelImg url={infoPanelData.url} />, height: '60vh' })
|
|
36
|
+
} else if (infoPanelData.type === InfoPanelTypeEnum.Video) {
|
|
37
|
+
controller.openDrawer({ content: <InfoPanelVideo url={infoPanelData.url} />, height: '60vh' })
|
|
38
|
+
}
|
|
39
|
+
timeoutRef.current = setTimeout(() => controller.openDrawer(false), end - start)
|
|
40
|
+
}
|
|
41
|
+
controller.on(VreoKeyframeEnum.InfoPanel, callback)
|
|
42
|
+
|
|
43
|
+
return () => {
|
|
44
|
+
controller.off(VreoKeyframeEnum.InfoPanel, callback)
|
|
45
|
+
if (timeoutRef.current) {
|
|
46
|
+
clearTimeout(timeoutRef.current)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}, [controller])
|
|
50
|
+
|
|
51
|
+
return <></>
|
|
52
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { ModelTVVideoPlugin } from '../../../../fivePlugins/ModelTVVideoPlugin'
|
|
3
|
+
import { ModelVideoData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
|
|
4
|
+
import { useController, useFiveInstance } from '../../../hooks'
|
|
5
|
+
|
|
6
|
+
export function ModelVideo() {
|
|
7
|
+
const controller = useController()
|
|
8
|
+
const five = useFiveInstance()
|
|
9
|
+
const ref = React.useRef<ReturnType<typeof ModelTVVideoPlugin>>()
|
|
10
|
+
const timeoutRef = React.useRef<NodeJS.Timeout | null>()
|
|
11
|
+
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
const callback = async (keyframe: VreoKeyframe) => {
|
|
14
|
+
if (!ref.current) {
|
|
15
|
+
ref.current = ModelTVVideoPlugin(five, {})
|
|
16
|
+
}
|
|
17
|
+
const { start, end } = keyframe
|
|
18
|
+
const { videoSrc, videoPosterSrc, vertexs } = keyframe.data as ModelVideoData
|
|
19
|
+
|
|
20
|
+
ref.current.disable()
|
|
21
|
+
await ref.current.load(
|
|
22
|
+
{
|
|
23
|
+
video_src: videoSrc.replace(/https*:/, ''),
|
|
24
|
+
video_poster_src: videoPosterSrc.replace(/https*:/, ''),
|
|
25
|
+
points: [vertexs],
|
|
26
|
+
},
|
|
27
|
+
controller.configs?.videos?.modelTVVideo
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
ref.current.enable()
|
|
31
|
+
timeoutRef.current = setTimeout(() => ref.current?.disable(), end - start)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
controller.on(VreoKeyframeEnum.ModelVideo, callback)
|
|
35
|
+
return () => {
|
|
36
|
+
controller.off(VreoKeyframeEnum.ModelVideo, callback)
|
|
37
|
+
if (timeoutRef.current) {
|
|
38
|
+
clearTimeout(timeoutRef.current)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}, [controller])
|
|
42
|
+
|
|
43
|
+
return <></>
|
|
44
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { Vector3 } from 'three'
|
|
3
|
+
import classNames from 'classnames'
|
|
4
|
+
|
|
5
|
+
import lineAnime from './lineAnime'
|
|
6
|
+
import { useController, useFiveInstance, useFiveProject2d } from '../../../hooks'
|
|
7
|
+
import { BetterTween } from '../../../../shared-utils/animationFrame/BetterTween'
|
|
8
|
+
import { PanoEffectData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
|
|
9
|
+
|
|
10
|
+
export function PanoEffect() {
|
|
11
|
+
const [state, setState] = React.useState<{
|
|
12
|
+
center: Vector3
|
|
13
|
+
distance: number
|
|
14
|
+
} | null>(null)
|
|
15
|
+
|
|
16
|
+
const five = useFiveInstance()
|
|
17
|
+
const lineRef = React.useRef<BetterTween<{ progress: number }> | null>(null)
|
|
18
|
+
const [pos, setPos] = React.useState<{ left: number; top: number } | null>(null)
|
|
19
|
+
const timeoutRef = React.useRef<NodeJS.Timeout | null>()
|
|
20
|
+
|
|
21
|
+
const controller = useController()
|
|
22
|
+
const project2d = useFiveProject2d()
|
|
23
|
+
|
|
24
|
+
const delLine = () => {
|
|
25
|
+
if (lineRef.current) {
|
|
26
|
+
lineRef.current.dispose()
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
React.useEffect(() => {
|
|
31
|
+
const callback = (keyframe: VreoKeyframe) => {
|
|
32
|
+
const { start, end, data } = keyframe
|
|
33
|
+
|
|
34
|
+
const videoEffectData = data as PanoEffectData
|
|
35
|
+
|
|
36
|
+
const [v1, v2] = videoEffectData.twoVertexs
|
|
37
|
+
const p1 = new Vector3(v1.x, v1.y, v1.z)
|
|
38
|
+
const p2 = new Vector3(v2.x, v2.y, v2.z)
|
|
39
|
+
|
|
40
|
+
lineRef.current = lineAnime(five, p1.clone(), p2.clone())
|
|
41
|
+
lineRef.current.play()
|
|
42
|
+
|
|
43
|
+
const center = p1.lerp(p2, 0.5)
|
|
44
|
+
const distance = p1.distanceTo(p2)
|
|
45
|
+
|
|
46
|
+
const p = project2d(center)
|
|
47
|
+
if (!p) return
|
|
48
|
+
const { x: left, y: top } = p
|
|
49
|
+
setState({ center, distance })
|
|
50
|
+
setPos({ left, top })
|
|
51
|
+
timeoutRef.current = setTimeout(() => {
|
|
52
|
+
setState(null)
|
|
53
|
+
setPos(null)
|
|
54
|
+
delLine()
|
|
55
|
+
}, end - start)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
controller.on(VreoKeyframeEnum.PanoEffect, callback)
|
|
59
|
+
|
|
60
|
+
return () => {
|
|
61
|
+
controller.off(VreoKeyframeEnum.PanoEffect, callback)
|
|
62
|
+
if (timeoutRef.current) {
|
|
63
|
+
clearTimeout(timeoutRef.current)
|
|
64
|
+
}
|
|
65
|
+
delLine()
|
|
66
|
+
}
|
|
67
|
+
}, [controller])
|
|
68
|
+
|
|
69
|
+
React.useEffect(() => {
|
|
70
|
+
const callback = () => {
|
|
71
|
+
if (!state?.center) return
|
|
72
|
+
const { x, y, z } = state.center
|
|
73
|
+
const res = project2d(new Vector3(x, y, z))
|
|
74
|
+
if (!res) return
|
|
75
|
+
const { x: left, y: top } = res
|
|
76
|
+
setPos({ left, top })
|
|
77
|
+
}
|
|
78
|
+
five.on('currentStateChange', callback)
|
|
79
|
+
return () => {
|
|
80
|
+
five.off('currentStateChange', callback)
|
|
81
|
+
}
|
|
82
|
+
}, [state?.center])
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<>
|
|
86
|
+
<div
|
|
87
|
+
className={classNames('PanoEffect', {
|
|
88
|
+
'PanoEffect--notHidden': state,
|
|
89
|
+
})}
|
|
90
|
+
style={{
|
|
91
|
+
left: (pos?.left || 0) + 'px',
|
|
92
|
+
top: (pos?.top || 0) + 'px',
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
{state?.distance.toFixed(4) + 'm'}
|
|
96
|
+
</div>
|
|
97
|
+
</>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as THREE from 'three'
|
|
2
|
+
import { Five } from '@realsee/five'
|
|
3
|
+
import { Line as FiveLine } from '@realsee/five/line'
|
|
4
|
+
import { tweenProgress } from '../../../../shared-utils/animationFrame/BetterTween'
|
|
5
|
+
|
|
6
|
+
export default function lineAnime(five: Five, startPoint: THREE.Vector3, endPoint: THREE.Vector3) {
|
|
7
|
+
const pointImage =
|
|
8
|
+
'data:image/png;base64,' +
|
|
9
|
+
'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAIVBMVEUAAAD////////////////////////////////////////PIev5AAAACnRSTlMAG/Py2baba05un7UgfgAAAHJJREFUKM9joBpgLHVSCRdA4metAoJlCJHmVWBgAeNzroKCCVCBLpjACqgJVjCBxRBT2FbBQQJYQAohsBAsUIUQWA4WiEIILAULeCEEloAFtBACizAEMLRgGIphLabDMJ2O6TlM72MGECIIMQIZIxqoBQCPvpJ/e9FaAAAAAABJRU5ErkJggg=='
|
|
10
|
+
const pointTexture = new THREE.TextureLoader().load(pointImage)
|
|
11
|
+
const color = new THREE.Color(0xffffff) as any
|
|
12
|
+
const line = new FiveLine()
|
|
13
|
+
line.setMaterial({ linewidth: 2, color })
|
|
14
|
+
const pointMaterial = line.points.material as THREE.PointsMaterial
|
|
15
|
+
pointMaterial.map = pointTexture
|
|
16
|
+
pointMaterial.color.set(color)
|
|
17
|
+
line.line.material.depthTest = false
|
|
18
|
+
return tweenProgress()
|
|
19
|
+
.onUpdate(({ progress }) => {
|
|
20
|
+
const lerpLeft = 0.5 - progress / 2
|
|
21
|
+
const lerpRight = 0.5 + progress / 2
|
|
22
|
+
const leftPoint = startPoint.clone().lerp(endPoint, lerpLeft)
|
|
23
|
+
const rightPoint = startPoint.clone().lerp(endPoint, lerpRight)
|
|
24
|
+
line.setPoints(leftPoint, rightPoint)
|
|
25
|
+
})
|
|
26
|
+
.onStart(() => five.scene.add(line))
|
|
27
|
+
.onDispose(() => {
|
|
28
|
+
five.scene.remove(line)
|
|
29
|
+
five.needsRender = true
|
|
30
|
+
})
|
|
31
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import classNames from 'classnames'
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
import { Vector3 } from 'three'
|
|
4
|
+
import { useController, useFiveInstance, useFiveProject2d } from '../../../hooks'
|
|
5
|
+
import { PanoTagData, PanoTagEnum, Vertex, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
|
|
6
|
+
|
|
7
|
+
export function PanoTag() {
|
|
8
|
+
const [state, setState] = React.useState<{
|
|
9
|
+
vertex: Vertex
|
|
10
|
+
text?: string
|
|
11
|
+
type: PanoTagEnum
|
|
12
|
+
imgUrl?: string
|
|
13
|
+
} | null>(null)
|
|
14
|
+
|
|
15
|
+
const [pos, setPos] = React.useState<{ left: number; top: number } | null>(null)
|
|
16
|
+
const timeoutRef = React.useRef<NodeJS.Timeout | null>()
|
|
17
|
+
|
|
18
|
+
const controller = useController()
|
|
19
|
+
const five = useFiveInstance()
|
|
20
|
+
const project2d = useFiveProject2d()
|
|
21
|
+
|
|
22
|
+
React.useEffect(() => {
|
|
23
|
+
if (controller.configs?.keyframeMap.PanoTag === false) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
const callback = (keyframe: VreoKeyframe) => {
|
|
27
|
+
const { start, end, data } = keyframe
|
|
28
|
+
|
|
29
|
+
const panoTagData = data as PanoTagData
|
|
30
|
+
const vertex = panoTagData.vertex
|
|
31
|
+
const { x, y, z } = panoTagData.vertex
|
|
32
|
+
const res = project2d(new Vector3(x, y, z))
|
|
33
|
+
if (!res) return
|
|
34
|
+
const { x: left, y: top } = res
|
|
35
|
+
setState({
|
|
36
|
+
vertex,
|
|
37
|
+
text: panoTagData.text || PanoTagEnum.Text,
|
|
38
|
+
type: panoTagData.type,
|
|
39
|
+
imgUrl: panoTagData.imgUrl,
|
|
40
|
+
})
|
|
41
|
+
setPos({ left, top })
|
|
42
|
+
timeoutRef.current = setTimeout(() => {
|
|
43
|
+
setState(null)
|
|
44
|
+
setPos(null)
|
|
45
|
+
}, end - start)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
controller.on(VreoKeyframeEnum.PanoTag, callback)
|
|
49
|
+
|
|
50
|
+
return () => {
|
|
51
|
+
controller.off(VreoKeyframeEnum.PanoTag, callback)
|
|
52
|
+
if (timeoutRef.current) {
|
|
53
|
+
clearTimeout(timeoutRef.current)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}, [controller])
|
|
57
|
+
|
|
58
|
+
React.useEffect(() => {
|
|
59
|
+
const callback = () => {
|
|
60
|
+
if (!state?.vertex) return
|
|
61
|
+
const { x, y, z } = state.vertex
|
|
62
|
+
const res = project2d(new Vector3(x, y, z))
|
|
63
|
+
if (!res) return
|
|
64
|
+
const { x: left, y: top } = res
|
|
65
|
+
setPos({ left, top })
|
|
66
|
+
}
|
|
67
|
+
five.on('currentStateChange', callback)
|
|
68
|
+
|
|
69
|
+
return () => {
|
|
70
|
+
five.off('currentStateChange', callback)
|
|
71
|
+
}
|
|
72
|
+
}, [state?.vertex])
|
|
73
|
+
|
|
74
|
+
const boxContent = (() => {
|
|
75
|
+
if (!state) return undefined
|
|
76
|
+
|
|
77
|
+
if (state.type === PanoTagEnum.Text) {
|
|
78
|
+
return (
|
|
79
|
+
<>
|
|
80
|
+
<span>{state.text}</span>
|
|
81
|
+
</>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
if (state.type === PanoTagEnum.Image) {
|
|
85
|
+
return (
|
|
86
|
+
<>
|
|
87
|
+
<img className="PanoTag-img" src={state.imgUrl!} alt={state.text || ''}></img>
|
|
88
|
+
<span className="PanoTag-txt">{state.text}</span>
|
|
89
|
+
</>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
return undefined
|
|
93
|
+
})()
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<>
|
|
97
|
+
<div
|
|
98
|
+
className={classNames('PanoTag', {
|
|
99
|
+
'PanoTag--notHidden': state,
|
|
100
|
+
})}
|
|
101
|
+
style={{
|
|
102
|
+
left: (pos?.left || 0) + 'px',
|
|
103
|
+
top: (pos?.top || 0) + 'px',
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
<div className="PanoTag-point"></div>
|
|
107
|
+
<div className="PanoTag-content">
|
|
108
|
+
<span className="PanoTag-linewrap">
|
|
109
|
+
<span className="PanoTag-slashline"></span>
|
|
110
|
+
<span className="PanoTag-straightline"></span>
|
|
111
|
+
</span>
|
|
112
|
+
<div
|
|
113
|
+
onClick={() => {
|
|
114
|
+
if (state?.imgUrl) {
|
|
115
|
+
// @TODO
|
|
116
|
+
// setDrawerVisible(true)
|
|
117
|
+
}
|
|
118
|
+
}}
|
|
119
|
+
className={'PanoTag-box PanoTag-box--' + (state?.type || '')}
|
|
120
|
+
>
|
|
121
|
+
{boxContent}
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import classNames from 'classnames'
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
import { Vector3 } from 'three'
|
|
4
|
+
import { PanoTextLabelData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
|
|
5
|
+
import { useController, useFiveProject2d } from '../../../hooks'
|
|
6
|
+
|
|
7
|
+
interface PanoTextLabelState {
|
|
8
|
+
text: string
|
|
9
|
+
left: number
|
|
10
|
+
top: number
|
|
11
|
+
fontSize: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function PanoTextLabel() {
|
|
15
|
+
const [state, setState] = React.useState<PanoTextLabelState | null>(null)
|
|
16
|
+
const timeoutRef = React.useRef<NodeJS.Timeout | null>()
|
|
17
|
+
const controller = useController()
|
|
18
|
+
const project2d = useFiveProject2d()
|
|
19
|
+
|
|
20
|
+
React.useEffect(() => {
|
|
21
|
+
if (controller.configs?.keyframeMap.PanoTextLabel === false) {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
const callback = (keyframe: VreoKeyframe) => {
|
|
25
|
+
const { start, end, data } = keyframe
|
|
26
|
+
const panoTextLabelData = data as PanoTextLabelData
|
|
27
|
+
const { x, y, z } = panoTextLabelData.vertex
|
|
28
|
+
|
|
29
|
+
const res = project2d(new Vector3(x, y, z))
|
|
30
|
+
if (!res) return
|
|
31
|
+
const { x: left, y: top } = res
|
|
32
|
+
|
|
33
|
+
Object.assign(window, { $PanoTextLabel: { setState } })
|
|
34
|
+
setState({ left, top, text: data.text || '', fontSize: data.fontSize || 16 })
|
|
35
|
+
timeoutRef.current = setTimeout(() => setState(null), end - start)
|
|
36
|
+
}
|
|
37
|
+
controller.on(VreoKeyframeEnum.PanoTextLabel, callback)
|
|
38
|
+
|
|
39
|
+
Object.assign(window, { $panoTextLabel: { setState } })
|
|
40
|
+
return () => {
|
|
41
|
+
controller.off(VreoKeyframeEnum.PanoTextLabel, callback)
|
|
42
|
+
if (timeoutRef.current) {
|
|
43
|
+
clearTimeout(timeoutRef.current)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}, [controller])
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
className={classNames('PanoTextLabel', {
|
|
51
|
+
'PanoTextLabel--notHidden': state,
|
|
52
|
+
})}
|
|
53
|
+
style={{
|
|
54
|
+
left: (state?.left || 0) + 'px',
|
|
55
|
+
top: (state?.top || 0) + 'px',
|
|
56
|
+
}}
|
|
57
|
+
>
|
|
58
|
+
<div className="PanoTextLabel-wrapper">
|
|
59
|
+
<div style={{ fontSize: `${state?.fontSize || 16}px` }} className="PanoText-innerText">
|
|
60
|
+
{state?.text || ''}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import { useController } from '../../../hooks'
|
|
4
|
+
|
|
5
|
+
import { CSSTransition, TransitionGroup } from 'react-transition-group'
|
|
6
|
+
import { VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
|
|
7
|
+
|
|
8
|
+
export function Prompter() {
|
|
9
|
+
const [text, setText] = React.useState<string>('')
|
|
10
|
+
const [hidden, setHidden] = React.useState<boolean>(true)
|
|
11
|
+
const ref = React.useRef<NodeJS.Timeout | null>(null)
|
|
12
|
+
const controller = useController()
|
|
13
|
+
|
|
14
|
+
React.useEffect(() => {
|
|
15
|
+
if (controller.configs?.keyframeMap.Prompter === false) {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
const callback = (keyframe: VreoKeyframe) => {
|
|
19
|
+
const { start, end, data } = keyframe
|
|
20
|
+
setText(data.text)
|
|
21
|
+
setHidden(false)
|
|
22
|
+
|
|
23
|
+
if (ref.current) {
|
|
24
|
+
clearTimeout(ref.current)
|
|
25
|
+
ref.current = null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
ref.current = setTimeout(() => {
|
|
29
|
+
setHidden(true)
|
|
30
|
+
setTimeout(() => setText(''), 500)
|
|
31
|
+
|
|
32
|
+
if (ref.current) clearTimeout(ref.current)
|
|
33
|
+
ref.current = null
|
|
34
|
+
}, end - start)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
controller.on(VreoKeyframeEnum.Prompter, callback)
|
|
38
|
+
|
|
39
|
+
return () => {
|
|
40
|
+
controller.off(VreoKeyframeEnum.Prompter, callback)
|
|
41
|
+
}
|
|
42
|
+
}, [controller])
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
className={classNames('vreo-prompter', {
|
|
47
|
+
'vreo-prompter--hidden': hidden,
|
|
48
|
+
})}
|
|
49
|
+
>
|
|
50
|
+
{text ? (
|
|
51
|
+
/* @warning "index.js:1 Warning: findDOMNode is deprecated in StrictMode." */
|
|
52
|
+
<TransitionGroup className="vreo-prompter-text">
|
|
53
|
+
<CSSTransition
|
|
54
|
+
key={text}
|
|
55
|
+
classNames="vreo-prompter-text-transition"
|
|
56
|
+
timeout={500}
|
|
57
|
+
addEndListener={(node, done) => node.addEventListener('transitionend', done, false)}
|
|
58
|
+
>
|
|
59
|
+
<div className="vreo-prompter-innerText">{text}</div>
|
|
60
|
+
</CSSTransition>
|
|
61
|
+
</TransitionGroup>
|
|
62
|
+
) : undefined}
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { parseWork } from '@realsee/five'
|
|
3
|
+
import { useController, useFiveInstance } from '../../../hooks'
|
|
4
|
+
import { UpdateVRPanoramaData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
|
|
5
|
+
|
|
6
|
+
export function UpdateVRPanorama() {
|
|
7
|
+
const controller = useController()
|
|
8
|
+
const five = useFiveInstance()
|
|
9
|
+
|
|
10
|
+
React.useEffect(() => {
|
|
11
|
+
const callback = (keyframe: VreoKeyframe) => {
|
|
12
|
+
const { panoIndex, images } = keyframe.data as UpdateVRPanoramaData
|
|
13
|
+
|
|
14
|
+
const newWorkJSON = JSON.parse(JSON.stringify(five.work?.raw.work))
|
|
15
|
+
|
|
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)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const newWork = parseWork(newWorkJSON)
|
|
24
|
+
|
|
25
|
+
// // 需要还原么?待定 ...
|
|
26
|
+
five.load(newWork)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
controller.on(VreoKeyframeEnum.UpdateVRPanorama, callback)
|
|
30
|
+
return () => {
|
|
31
|
+
controller.off(VreoKeyframeEnum.UpdateVRPanorama, callback)
|
|
32
|
+
}
|
|
33
|
+
}, [controller])
|
|
34
|
+
|
|
35
|
+
return <></>
|
|
36
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import classNames from 'classnames'
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
// import { Preloader } from '../../../../shared-utils/Preloader'
|
|
4
|
+
import { VideoEffectData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
|
|
5
|
+
import { useController, useFiveInstance } from '../../../hooks'
|
|
6
|
+
|
|
7
|
+
const inlinePlay = (videoInstance?: HTMLVideoElement | null) => {
|
|
8
|
+
if (!videoInstance) return
|
|
9
|
+
const canplaythrough = () => {
|
|
10
|
+
videoInstance.removeEventListener('canplaythrough', canplaythrough)
|
|
11
|
+
try {
|
|
12
|
+
videoInstance.play()
|
|
13
|
+
} catch (error) {}
|
|
14
|
+
}
|
|
15
|
+
videoInstance.addEventListener('canplaythrough', canplaythrough)
|
|
16
|
+
videoInstance.load()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// const emptyVideo = '//vrlab-static.ljcdn.com/release/web/leisure.69fd3522.mov'
|
|
20
|
+
const PI = Math.PI
|
|
21
|
+
const PI_2 = PI * 2
|
|
22
|
+
|
|
23
|
+
export function VideoEffect() {
|
|
24
|
+
const ref = React.useRef<HTMLDivElement>(null)
|
|
25
|
+
const videoRef = React.useRef<HTMLVideoElement | null>()
|
|
26
|
+
const controller = useController()
|
|
27
|
+
const timeoutRef = React.useRef<NodeJS.Timeout | null>()
|
|
28
|
+
|
|
29
|
+
const [visible, setVisible] = React.useState(false)
|
|
30
|
+
const five = useFiveInstance()
|
|
31
|
+
const setBlobSrc = (blob: string) => {
|
|
32
|
+
if (!videoRef.current) return
|
|
33
|
+
|
|
34
|
+
videoRef.current.src = blob
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
React.useEffect(() => {
|
|
38
|
+
const callback = async (keyframe: VreoKeyframe) => {
|
|
39
|
+
const { start, end } = keyframe
|
|
40
|
+
const { videoSrc, fov, direction, panoIndex, vector } = keyframe.data as VideoEffectData
|
|
41
|
+
const [longitude, latitude] = (() => {
|
|
42
|
+
if (vector) {
|
|
43
|
+
return [vector.longitude, vector.latitude]
|
|
44
|
+
}
|
|
45
|
+
if (!direction) {
|
|
46
|
+
return [0, 0]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let longitude = -Math.atan2(direction.x, -direction.z)
|
|
50
|
+
longitude = ((longitude % PI_2) + PI_2) % PI_2
|
|
51
|
+
const latitude = -Math.asin(direction.y / 1)
|
|
52
|
+
return [longitude, latitude]
|
|
53
|
+
})()
|
|
54
|
+
|
|
55
|
+
five.setState({ fov, panoIndex, longitude, latitude }, true)
|
|
56
|
+
setBlobSrc(videoSrc)
|
|
57
|
+
|
|
58
|
+
inlinePlay(videoRef.current)
|
|
59
|
+
setVisible(true)
|
|
60
|
+
|
|
61
|
+
timeoutRef.current = setTimeout(() => {
|
|
62
|
+
if (!videoRef.current?.paused) {
|
|
63
|
+
videoRef.current?.pause()
|
|
64
|
+
}
|
|
65
|
+
setVisible(false)
|
|
66
|
+
setBlobSrc('')
|
|
67
|
+
}, end - start)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
controller.on(VreoKeyframeEnum.VideoEffect, callback)
|
|
71
|
+
return () => {
|
|
72
|
+
controller.off(VreoKeyframeEnum.VideoEffect, callback)
|
|
73
|
+
if (timeoutRef.current) {
|
|
74
|
+
clearTimeout(timeoutRef.current)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}, [controller])
|
|
78
|
+
|
|
79
|
+
React.useEffect(() => {
|
|
80
|
+
if (!ref.current) return
|
|
81
|
+
const video = controller.configs?.videos?.videoEffect || document.createElement('video')
|
|
82
|
+
// <video playsInline key="VideoEffect-video" className="VideoEffect-video" src={blobSrc} />
|
|
83
|
+
video.setAttribute('playsinline', 'true')
|
|
84
|
+
video.setAttribute('webkit-playsinline', 'true')
|
|
85
|
+
video.setAttribute('autoplay', 'true')
|
|
86
|
+
video.setAttribute('key', 'VideoEffect-video')
|
|
87
|
+
video.setAttribute('class', 'VideoEffect-video')
|
|
88
|
+
|
|
89
|
+
videoRef.current = video
|
|
90
|
+
ref.current.append(videoRef.current)
|
|
91
|
+
document.addEventListener(
|
|
92
|
+
'WeixinJSBridgeReady',
|
|
93
|
+
function () {
|
|
94
|
+
videoRef.current?.play()
|
|
95
|
+
},
|
|
96
|
+
false
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if (!ref.current) return
|
|
100
|
+
// const asyncfunc = async () => {
|
|
101
|
+
// setBlobSrc(await URL.createObjectURL(await Preloader.blob(emptyVideo)))
|
|
102
|
+
// inlinePlay(videoRef.current)
|
|
103
|
+
// }
|
|
104
|
+
// asyncfunc()
|
|
105
|
+
}, [])
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<div
|
|
109
|
+
ref={ref}
|
|
110
|
+
className={classNames('VideoEffect', {
|
|
111
|
+
'VideoEffect--visible': visible,
|
|
112
|
+
})}
|
|
113
|
+
></div>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { VreoKeyframeConfigMap } from '../typings/VreoUnit'
|
|
2
|
+
|
|
3
|
+
export interface PlayerConfigs {
|
|
4
|
+
containter?: ReactDOM.Container
|
|
5
|
+
keyframeMap: VreoKeyframeConfigMap
|
|
6
|
+
/**
|
|
7
|
+
* 微信端自动播放功能实现需要提前初始化 Video 实例。
|
|
8
|
+
*
|
|
9
|
+
* 如果需要支持微信浏览器端自动播放需要接入微信SDK及提前初始化好相关 Video 实例。
|
|
10
|
+
*/
|
|
11
|
+
videos?: {
|
|
12
|
+
videoEffect?: HTMLVideoElement
|
|
13
|
+
modelTVVideo?: HTMLVideoElement
|
|
14
|
+
}
|
|
15
|
+
}
|