@realsee/vreo 0.2.0-alpha.9 → 1.0.0-alpha.2

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 (156) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +16 -5
  3. package/docs/assets/highlight.css +1 -1
  4. package/docs/assets/main.js +2 -2
  5. package/docs/assets/search.js +1 -1
  6. package/docs/assets/style.css +28 -2
  7. package/docs/classes/Player.AudioLike.html +52 -0
  8. package/docs/classes/Player.Controller.html +13 -13
  9. package/docs/classes/Player.Player-1.html +11 -11
  10. package/docs/classes/Player.VideoAgentMesh.html +53 -53
  11. package/docs/classes/Player.VideoAgentScene.html +1 -1
  12. package/docs/demo/assets/AppReact.d0ee843a.js +1 -0
  13. package/docs/demo/assets/default.63925584.js +3984 -0
  14. package/docs/demo/assets/default.f3f3ca8c.css +1 -0
  15. package/docs/demo/assets/dynamic.76506c2c.js +1 -0
  16. package/docs/demo/assets/examples.3d8323db.js +25 -0
  17. package/docs/demo/assets/examples.dac4a6fe.css +1 -0
  18. package/docs/demo/assets/index.7e31122c.js +1 -0
  19. package/docs/demo/assets/index.9331038f.css +1 -0
  20. package/docs/demo/assets/main.79b11b9d.js +1 -0
  21. package/docs/demo/assets/react.2ee8565f.css +1 -0
  22. package/docs/demo/assets/react.c1c07c14.js +25 -0
  23. package/docs/demo/assets/znRoyv06SZQeqA7m.0057e8ae.js +1 -0
  24. package/docs/demo/examples.html +17 -0
  25. package/docs/demo/index-react-dynamic.html +20 -0
  26. package/docs/demo/index-react.html +20 -0
  27. package/docs/demo/index.html +19 -0
  28. package/docs/enums/Player.InfoPanelStyleEnum.html +1 -1
  29. package/docs/enums/Player.InfoPanelTypeEnum.html +2 -2
  30. package/docs/enums/Player.PanoEffectEnum.html +2 -2
  31. package/docs/enums/Player.PanoTagEnum.html +2 -2
  32. package/docs/enums/Player.PanoTagStyleEnum.html +7 -0
  33. package/docs/enums/Player.VreoKeyframeEnum.html +12 -12
  34. package/docs/enums/fivePlugins.CameraMovementEffect.html +1 -1
  35. package/docs/enums/fivePlugins.Rotation.html +1 -1
  36. package/docs/index.html +13 -6
  37. package/docs/interfaces/Player.CustomVreoKeyframeProps.html +1 -1
  38. package/docs/interfaces/Player.PlayerConfigs.html +4 -3
  39. package/docs/interfaces/Player.Vertex.html +2 -2
  40. package/docs/interfaces/Player.VideoAgentMeshOptions.html +8 -1
  41. package/docs/interfaces/Player.VreoKeyframe.html +2 -2
  42. package/docs/interfaces/Player.VreoUnit.html +2 -2
  43. package/docs/interfaces/Player.VreoVideo.html +2 -2
  44. package/docs/interfaces/fivePlugins.CSS3DRenderPluginExportType.html +4 -0
  45. package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +1 -1
  46. package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +2 -2
  47. package/docs/interfaces/fivePlugins.CameraMovementPluginParameterType.html +1 -1
  48. package/docs/interfaces/fivePlugins.ModelTVVideoPluginData.html +1 -1
  49. package/docs/interfaces/fivePlugins.ModelTVVideoPluginExportType.html +1 -1
  50. package/docs/interfaces/fivePlugins.ModelTVVideoPluginParameterType.html +1 -1
  51. package/docs/interfaces/fivePlugins.Vector3Position.html +3 -0
  52. package/docs/interfaces/react.VreoActionCallbacks.html +15 -7
  53. package/docs/interfaces/react.VreoProviderProps.html +1 -1
  54. package/docs/modules/Player.html +21 -15
  55. package/docs/modules/custom.html +1 -1
  56. package/docs/modules/fivePlugins.html +5 -2
  57. package/docs/modules/react.html +1 -1
  58. package/docs/modules.html +1 -1
  59. package/lib/PlayController/index.js +4 -5
  60. package/lib/Player/App.js +9 -7
  61. package/lib/Player/Controller.d.ts +29 -8
  62. package/lib/Player/Controller.js +193 -27
  63. package/lib/Player/custom/SpatialScenePanel/index.js +5 -4
  64. package/lib/Player/hooks.js +2 -2
  65. package/lib/Player/index.d.ts +5 -3
  66. package/lib/Player/index.js +97 -53
  67. package/lib/Player/modules/Drawer/index.js +1 -1
  68. package/lib/Player/modules/PopUp/index.js +1 -1
  69. package/lib/Player/modules/ResizeObserver/index.d.ts +2 -0
  70. package/lib/Player/modules/ResizeObserver/index.js +37 -0
  71. package/lib/Player/modules/VideoAgent/VideoAgentMesh.d.ts +16 -2
  72. package/lib/Player/modules/VideoAgent/VideoAgentMesh.js +132 -59
  73. package/lib/Player/modules/VideoAgent/VideoAgentScene.d.ts +3 -6
  74. package/lib/Player/modules/VideoAgent/VideoAgentScene.js +31 -36
  75. package/lib/Player/modules/VideoAgent/index.js +53 -12
  76. package/lib/Player/modules/Wave/index.d.ts +5 -0
  77. package/lib/Player/modules/Wave/index.js +51 -0
  78. package/lib/Player/modules/keyframes/BgMusic/index.js +1 -1
  79. package/lib/Player/modules/keyframes/CameraMovement/index.js +1 -1
  80. package/lib/Player/modules/keyframes/InfoPanel/index.js +22 -10
  81. package/lib/Player/modules/keyframes/ModelVideo/index.js +46 -9
  82. package/lib/Player/modules/keyframes/PanoEffect/index.js +1 -1
  83. package/lib/Player/modules/keyframes/PanoEffect/lineAnime.js +1 -1
  84. package/lib/Player/modules/keyframes/PanoTag/index.d.ts +1 -2
  85. package/lib/Player/modules/keyframes/PanoTag/index.js +79 -119
  86. package/lib/Player/modules/keyframes/PanoTextLabel/index.d.ts +3 -0
  87. package/lib/Player/modules/keyframes/PanoTextLabel/index.js +96 -44
  88. package/lib/Player/modules/keyframes/Prompter/index.js +10 -23
  89. package/lib/Player/modules/keyframes/UpdateVRPanorama/index.js +10 -6
  90. package/lib/Player/modules/keyframes/VideoEffect/index.js +1 -1
  91. package/lib/Player/typings.d.ts +12 -1
  92. package/lib/fivePlugins/CSS3DRenderPlugin/centerPoint.d.ts +2 -0
  93. package/lib/fivePlugins/CSS3DRenderPlugin/centerPoint.js +12 -0
  94. package/lib/fivePlugins/CSS3DRenderPlugin/createResizeObserver.d.ts +7 -0
  95. package/lib/fivePlugins/CSS3DRenderPlugin/createResizeObserver.js +32 -0
  96. package/lib/fivePlugins/CSS3DRenderPlugin/evenNumber.d.ts +3 -0
  97. package/lib/fivePlugins/CSS3DRenderPlugin/evenNumber.js +11 -0
  98. package/lib/fivePlugins/CSS3DRenderPlugin/index.d.ts +56 -0
  99. package/lib/fivePlugins/CSS3DRenderPlugin/index.js +275 -0
  100. package/lib/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.d.ts +7 -0
  101. package/lib/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.js +18 -0
  102. package/lib/fivePlugins/CameraMovementPlugin/index.js +13 -12
  103. package/lib/fivePlugins/ModelTVVideoPlugin/index.js +1 -1
  104. package/lib/react/index.d.ts +8 -4
  105. package/lib/react/index.js +3 -3
  106. package/lib/shared-utils/AduioLike.d.ts +37 -0
  107. package/lib/shared-utils/AduioLike.js +166 -0
  108. package/lib/shared-utils/addResizeListener.d.ts +4 -0
  109. package/lib/shared-utils/addResizeListener.js +51 -0
  110. package/lib/shared-utils/animationFrame/BetterTween.js +7 -3
  111. package/lib/shared-utils/animationFrame/tween.js +1 -1
  112. package/lib/shared-utils/createTransMatrix.d.ts +1 -0
  113. package/lib/shared-utils/createTransMatrix.js +43 -0
  114. package/lib/shared-utils/getFileExpandedName.d.ts +1 -0
  115. package/lib/shared-utils/getFileExpandedName.js +13 -0
  116. package/lib/shared-utils/getMediaInfo.d.ts +9 -0
  117. package/lib/shared-utils/getMediaInfo.js +75 -0
  118. package/lib/shared-utils/setElementDataset.d.ts +1 -0
  119. package/lib/shared-utils/setElementDataset.js +24 -0
  120. package/lib/typings/VreoUnit.d.ts +37 -2
  121. package/lib/typings/VreoUnit.js +13 -1
  122. package/package.json +10 -10
  123. package/resources/PlayController/index.ts +0 -13
  124. package/resources/Player/App.tsx +5 -4
  125. package/resources/Player/Controller.ts +277 -146
  126. package/resources/Player/custom/SpatialScenePanel/index.tsx +5 -5
  127. package/resources/Player/hooks.ts +3 -5
  128. package/resources/Player/index.tsx +189 -141
  129. package/resources/Player/modules/ResizeObserver/index.tsx +23 -0
  130. package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +87 -31
  131. package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +27 -24
  132. package/resources/Player/modules/VideoAgent/index.tsx +28 -12
  133. package/resources/Player/modules/Wave/index.tsx +18 -0
  134. package/resources/Player/modules/keyframes/InfoPanel/index.tsx +26 -11
  135. package/resources/Player/modules/keyframes/ModelVideo/index.tsx +36 -3
  136. package/resources/Player/modules/keyframes/PanoTag/index.tsx +53 -97
  137. package/resources/Player/modules/keyframes/PanoTextLabel/index.tsx +86 -34
  138. package/resources/Player/modules/keyframes/Prompter/index.tsx +6 -16
  139. package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +6 -2
  140. package/resources/Player/typings.ts +15 -1
  141. package/resources/fivePlugins/CSS3DRenderPlugin/centerPoint.ts +5 -0
  142. package/resources/fivePlugins/CSS3DRenderPlugin/createResizeObserver.ts +17 -0
  143. package/resources/fivePlugins/CSS3DRenderPlugin/evenNumber.ts +4 -0
  144. package/resources/fivePlugins/CSS3DRenderPlugin/index.ts +254 -0
  145. package/resources/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.ts +5 -0
  146. package/resources/fivePlugins/CameraMovementPlugin/index.ts +19 -12
  147. package/resources/react/index.tsx +7 -3
  148. package/resources/shared-utils/AduioLike.ts +109 -0
  149. package/resources/shared-utils/addResizeListener.ts +46 -0
  150. package/resources/shared-utils/createTransMatrix.ts +12 -0
  151. package/resources/shared-utils/getFileExpandedName.ts +6 -0
  152. package/resources/shared-utils/getMediaInfo.ts +52 -0
  153. package/resources/shared-utils/setElementDataset.ts +18 -0
  154. package/resources/typings/VreoUnit.ts +41 -3
  155. package/stylesheets/custom/SpatialScenePanel.css +2 -1
  156. package/stylesheets/default.css +348 -84
@@ -1,5 +1,7 @@
1
1
  import * as THREE from 'three'
2
- import { VideoAgentMesh } from './VideoAgentMesh'
2
+ import { addResizeListener } from '../../../shared-utils/addResizeListener'
3
+ import { getMediaType } from '../../../shared-utils/getMediaInfo'
4
+ import { VideoAgentMesh, VideoAgentMeshOptions } from './VideoAgentMesh'
3
5
 
4
6
  export class VideoAgentScene {
5
7
  videoAgentMesh: VideoAgentMesh
@@ -7,47 +9,48 @@ export class VideoAgentScene {
7
9
  scene = new THREE.Scene()
8
10
  camera = new THREE.OrthographicCamera(-240, 240, 135, -135)
9
11
  renderer = new THREE.WebGLRenderer({ alpha: true })
10
- container: HTMLElement
11
-
12
- constructor(container: HTMLElement, needRender = true, options: { videoInstance?: HTMLVideoElement, audioInstance?: HTMLAudioElement } = {}) {
13
- this.container = container
14
- this.camera.position.set(0, 0, 10)
15
- this.camera.lookAt(0, 0, 0)
16
- const state = {
17
- width: container.offsetWidth,
18
- height: container.offsetHeight,
19
- }
20
- const domElement = this.renderer.domElement
21
- domElement.classList.add('VideoAgent-canvas')
22
- this.renderer.setSize(state.width * window.devicePixelRatio, state.height * window.devicePixelRatio)
23
- domElement.setAttribute('style', `width: ${state.width}px;height: ${state.height}px;`)
12
+ disposers: (() => void)[] = []
13
+
14
+ constructor(container?: HTMLElement, options?: VideoAgentMeshOptions) {
24
15
 
25
16
  this.videoAgentMesh = new VideoAgentMesh(480, 270, 1, 1, options)
26
- if (needRender) {
17
+
18
+ // const needRender = getMediaType(this.videoAgentMesh.videoUrl) === 'video'
19
+
20
+ if (container) {
21
+
22
+ this.camera.position.set(0, 0, 10)
23
+ this.camera.lookAt(0, 0, 0)
24
+
25
+ const domElement = this.renderer.domElement
26
+ domElement.classList.add('VideoAgent-canvas')
27
+
28
+ const dispose = addResizeListener(container, (width, height) => {
29
+ this.renderer.setSize(width * window.devicePixelRatio, height * window.devicePixelRatio)
30
+ domElement.style.width = `${width}px`
31
+ domElement.style.height = `${height}px`
32
+ } )
33
+
34
+ this.disposers.push(dispose)
35
+
27
36
  container.append(domElement)
28
37
  this.scene.add(this.videoAgentMesh)
38
+
29
39
  this.run()
30
40
  }
31
41
  }
32
42
 
33
43
  run = () => {
34
- const domElement = this.renderer.domElement
35
-
36
44
  // 视频开始 1s 不渲染:规避某些设备黑屏闪烁问题。视频前 2s 是最好是静默的。
37
45
  if (!(this.videoAgentMesh.paused || this.videoAgentMesh.freeze) && this.videoAgentMesh.currentTime > 1000) {
38
46
  this.renderer.render(this.scene, this.camera)
39
47
  }
40
48
 
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
- }
47
49
  requestAnimationFrame(this.run)
48
50
  }
49
51
 
50
52
  dispose = () => {
51
53
  this.videoAgentMesh?.dispose()
54
+ this.disposers.forEach(disposer => disposer?.())
52
55
  }
53
56
  }
@@ -2,18 +2,28 @@ import * as React from 'react'
2
2
  import { useController } from '../../hooks'
3
3
  import { VideoAgentMeshOptions } from './VideoAgentMesh'
4
4
  import { VideoAgentScene } from './VideoAgentScene'
5
+ import classNames from 'classnames'
5
6
 
6
7
  export function VideoAgent(props: { onClick?: () => void; options?: VideoAgentMeshOptions }) {
7
8
  const ref = React.useRef<HTMLDivElement>(null)
8
9
  const controller = useController()
9
10
 
11
+ const showAvatar = React.useMemo(() => {
12
+ return controller.avatar?.url && (controller.avatar.force === true)
13
+ }, [controller.avatar])
14
+
15
+ const showVideoAgent = React.useMemo(() => {
16
+ if (showAvatar) return false
17
+ return controller.videoAgentScene?.videoAgentMesh.mediaInstance instanceof HTMLVideoElement
18
+ }, [controller.videoAgentScene])
19
+
10
20
  React.useEffect(() => {
11
21
  if (!ref.current) throw new Error('React 渲染异常,请稍后重试 ...')
12
22
  if (controller.videoAgentScene) {
13
- console.warn('"VideoAgentScene" 重复初始化,已被过滤 ...')
23
+ console.warn('VideoAgentScene" 重复初始化,已被过滤')
14
24
  return
15
25
  }
16
- const videoAgentScene = new VideoAgentScene(ref.current, true, props.options || {})
26
+ const videoAgentScene = new VideoAgentScene(ref.current, props.options)
17
27
  controller.videoAgentScene = videoAgentScene
18
28
 
19
29
  return () => {
@@ -23,15 +33,21 @@ export function VideoAgent(props: { onClick?: () => void; options?: VideoAgentMe
23
33
  }, [])
24
34
 
25
35
  return (
26
- <div
27
- className="VideoAgent"
28
- onClick={() => {
29
- if (!props.onClick) return
30
- props.onClick()
31
- }}
32
- ref={ref}
33
- >
34
- <div className="VideoAgent-play"></div>
35
- </div>
36
+ <>
37
+ <div className="Avatar" style={{display: showAvatar ? 'block' : 'none'}}>
38
+ <div className="Avatar-wrapper ratio-1-1">
39
+ <img className="Avatar-img" src={controller.avatar?.url} onClick={() => props.onClick?.()} />
40
+ </div>
41
+ </div>
42
+ <div className={classNames('VideoAgent', { hide: !showVideoAgent })}>
43
+ <div className="VideoAgent-container">
44
+ <div className="VideoAgent-wrapper ratio-16-9">
45
+ <div className="VideoAgent-inner" ref={ref}>
46
+ <div className="VideoAgent-play" onClick={() => props.onClick?.()}></div>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ </div>
51
+ </>
36
52
  )
37
53
  }
@@ -0,0 +1,18 @@
1
+ import React from 'react'
2
+ import { WaveAppearance } from '../../typings'
3
+
4
+ export function Wave(props?: { appearance?: WaveAppearance }) {
5
+ const waveUrl = React.useMemo(() => {
6
+ const appearance = props?.appearance ?? 'solid'
7
+ switch (appearance) {
8
+ default: return 'https://vr-public.realsee-cdn.cn/release/static/image/release/vapor/static/wave-solid.64438b63cbb346906d066bb7b8dc3e20.webm'
9
+ case 'solid': return 'https://vr-public.realsee-cdn.cn/release/static/image/release/vapor/static/wave-solid.64438b63cbb346906d066bb7b8dc3e20.webm'
10
+ case 'single': return 'https://vr-public.realsee-cdn.cn/release/static/image/release/vapor/static/wave-single.eda65de390a830193fff40d1f1255555.webm'
11
+ case 'double': return 'https://vr-public.realsee-cdn.cn/release/static/image/release/vapor/static/wave-double.77dfe8548ebcb3f3d336785d4fe9c7b2.webm'
12
+ case 'swap': return 'https://vr-public.realsee-cdn.cn/release/static/image/release/vapor/static/wave-swap.c02e4b94cf05aecf6e7a0023bc7bb90f.webm'
13
+ case 'expand': return 'https://vr-public.realsee-cdn.cn/release/static/image/release/vapor/static/wave-expand.a0d2a0074001cd3d4fea56818c6d3c38.webm'
14
+ }
15
+ }, [props?.appearance])
16
+
17
+ return <video className='vreo-wave' width="100%" preload="auto" muted autoPlay loop playsInline disablePictureInPicture controls={false} src={waveUrl} />
18
+ }
@@ -11,19 +11,31 @@ import { useController } from '../../../hooks'
11
11
 
12
12
  function InfoPanelImg({ url, children }: { url: string; children?: ReactNode }) {
13
13
  return (
14
- <div className="vreo-infoPanel vreo-infoPanel--img">
15
- {children}
16
- <div className="vreo-infoPanelImg" style={{ backgroundImage: `url(${url})` }}></div>
14
+ <div className="vreo-infoPanel-container">
15
+ <div className="vreo-infoPanel vreo-infoPanel--img">
16
+ <div className="ratio-4-5 vreo-infoPanel-wrapper">
17
+ <div className="vreo-infoPanel-inner">
18
+ {children}
19
+ <img className="vreo-infoPanelImg" src={url}></img>
20
+ </div>
21
+ </div>
22
+ </div>
17
23
  </div>
18
24
  )
19
25
  }
20
26
 
21
27
  function InfoPanelVideo({ url, children }: { url: string; children?: ReactNode }) {
22
28
  return (
23
- <div className="vreo-infoPanel vreo-infoPanel--video">
24
- {children}
25
- <div className="vreo-infoPanelWrapper">
26
- <video playsInline autoPlay className="vreo-infoPanelVideo" src={url} />
29
+ <div className="vreo-infoPanel-container">
30
+ <div className="vreo-infoPanel vreo-infoPanel--video">
31
+ <div className="ratio-4-5 vreo-infoPanel-wrapper">
32
+ <div className="vreo-infoPanel-inner">
33
+ {children}
34
+ <div className="vreo-infoPanelVideo">
35
+ <video playsInline autoPlay className="vreo-infoPanelVideo" src={url} />
36
+ </div>
37
+ </div>
38
+ </div>
27
39
  </div>
28
40
  </div>
29
41
  )
@@ -40,10 +52,13 @@ const Title = (props: TitleProps) => {
40
52
  }
41
53
 
42
54
  return (
43
- <div className="vreo-infoPanel-title">
44
- <div className="vreo-infoPanel-t1">{props.title}</div>
45
- <div className="vreo-infoPanel-t2">{props.subTitle}</div>
46
- </div>
55
+ <>
56
+ <div className="vreo-infoPanel-title-shadow"></div>
57
+ <div className="vreo-infoPanel-title">
58
+ <div className="vreo-infoPanel-t1">{props.title}</div>
59
+ <div className="vreo-infoPanel-t2">{props.subTitle}</div>
60
+ </div>
61
+ </>
47
62
  )
48
63
  }
49
64
 
@@ -1,7 +1,9 @@
1
1
  import * as React from 'react'
2
+ import * as THREE from 'three'
3
+ import { useController, useFiveInstance } from '../../../hooks'
2
4
  import { ModelTVVideoPlugin } from '../../../../fivePlugins/ModelTVVideoPlugin'
5
+ import { createTransMatrix } from '../../../../shared-utils/createTransMatrix'
3
6
  import { ModelVideoData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
4
- import { useController, useFiveInstance } from '../../../hooks'
5
7
 
6
8
  export function ModelVideo() {
7
9
  const controller = useController()
@@ -15,14 +17,45 @@ export function ModelVideo() {
15
17
  ref.current = ModelTVVideoPlugin(five, {})
16
18
  }
17
19
  const { start, end } = keyframe
18
- const { videoSrc, videoPosterSrc, vertexs } = keyframe.data as ModelVideoData
20
+ const { videoSrc, videoPosterSrc, vertexs, matrixWorld } = keyframe.data as ModelVideoData
21
+
22
+ const position = (() => {
23
+ if (vertexs.length < 4) {
24
+ throw new Error('ModelVideo: 顶点数据集合不够,无法组成矩形 ....')
25
+ }
26
+ if (vertexs.length === 4) {
27
+ return vertexs
28
+ }
29
+
30
+ const box = new THREE.Box3()
31
+ vertexs.forEach((v) => box.expandByPoint(new THREE.Vector3(v.x, v.y, v.z)))
32
+ return [
33
+ new THREE.Vector3(box.min.x, box.max.y, box.max.z),
34
+ new THREE.Vector3(box.min.x, box.min.y, box.max.z),
35
+ new THREE.Vector3(box.max.x, box.min.y, box.max.z),
36
+ new THREE.Vector3(box.max.x, box.max.y, box.max.z),
37
+ ]
38
+ })()
39
+
40
+ const points = (() => {
41
+ if (matrixWorld) {
42
+ const transMatrix = createTransMatrix(matrixWorld)
43
+ return [
44
+ position.map((p) => {
45
+ const res = transMatrix([p.x, p.y, p.z])
46
+ return { x: res[0], y: res[1], z: res[2] }
47
+ }),
48
+ ]
49
+ }
50
+ return [position]
51
+ })()
19
52
 
20
53
  ref.current.disable()
21
54
  await ref.current.load(
22
55
  {
23
56
  video_src: videoSrc,
24
57
  video_poster_src: videoPosterSrc,
25
- points: [vertexs],
58
+ points,
26
59
  },
27
60
  controller.configs?.videos?.modelTVVideo
28
61
  )
@@ -1,47 +1,71 @@
1
- import classNames from 'classnames'
2
1
  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'
2
+ import { useController, useFiveInstance } from '../../../hooks'
3
+ import { PanoTagData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
6
4
 
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)
5
+ import { ContentType, DimensionType, PanoTagPlugin, PointType, Tag } from '@realsee/dnalogel'
14
6
 
15
- const [pos, setPos] = React.useState<{ left: number; top: number } | null>(null)
7
+ export function PanoTag() {
16
8
  const timeoutRef = React.useRef<NodeJS.Timeout | null>()
17
-
18
9
  const controller = useController()
19
10
  const five = useFiveInstance()
20
- const project2d = useFiveProject2d()
11
+ const panoTagPlugin = React.useRef(PanoTagPlugin(five as any, {
12
+ config: {
13
+ globalConfig: {
14
+ visibleConfig: {
15
+ keep: 'visible'
16
+ },
17
+ unfoldedConfig: {
18
+ autoUnfold: {
19
+ strategy: 'MinimumDistance'
20
+ },
21
+ unfoldDistance: { max: 100 }
22
+ }
23
+ }
24
+ }
25
+ }))
21
26
 
22
27
  React.useEffect(() => {
23
28
  if (controller.configs?.keyframeMap.PanoTag === false) {
24
29
  return
25
30
  }
26
31
  const callback = (keyframe: VreoKeyframe) => {
32
+ if (!panoTagPlugin.current) return
33
+
27
34
  const { start, end, data } = keyframe
28
35
 
29
36
  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 })
37
+
38
+ const id = 'any-id'
39
+ const pointType = PointType.PointTag
40
+ const dimensionType = DimensionType.Two
41
+ const position = [panoTagData.vertex.x, panoTagData.vertex.y, panoTagData.vertex.z]
42
+ const tag: Tag = (() => {
43
+ if (panoTagData.imgUrl) {
44
+ return { id, pointType, position, dimensionType, contentType: ContentType.ImageText, data: { text: panoTagData.text, mediaData: [{ type: 'Image', url: panoTagData.imgUrl }] }}
45
+ } else {
46
+ return { id, pointType, position, dimensionType, contentType: ContentType.Text, data: { text: panoTagData.text }}
47
+ }
48
+ })()
49
+
50
+ // show
51
+ panoTagPlugin.current.load({ tagList: [tag] })
52
+
42
53
  timeoutRef.current = setTimeout(() => {
43
- setState(null)
44
- setPos(null)
54
+ const id = Date.now()
55
+ // clear
56
+ const tag = panoTagPlugin.current.getTagById(id)
57
+ if (tag.state) {
58
+ tag.state.unfolded = false
59
+ ;(panoTagPlugin.current as any).updateRenderAllTags()
60
+ }
61
+ tag.hooks?.on('folded', () => {
62
+ setTimeout(() => {
63
+ if (tag.state) {
64
+ tag.state.visible = false
65
+ panoTagPlugin.current.destroyTagById(id)
66
+ }
67
+ }, 1500)
68
+ })
45
69
  }, end - start)
46
70
  }
47
71
 
@@ -55,73 +79,5 @@ export function PanoTag() {
55
79
  }
56
80
  }, [controller])
57
81
 
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
- )
82
+ return null
127
83
  }
@@ -1,21 +1,65 @@
1
- import classNames from 'classnames'
2
1
  import * as React from 'react'
3
- import { Vector3 } from 'three'
2
+ import * as THREE from 'three'
3
+ import ReactDOM from 'react-dom'
4
+ import { Vector3, Quaternion } from 'three'
5
+
6
+ import { useController, useFiveInstance } from '../../../hooks'
7
+ import { CSS3DRenderPlugin } from '../../../../fivePlugins/CSS3DRenderPlugin'
4
8
  import { PanoTextLabelData, VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
5
- import { useController, useFiveProject2d } from '../../../hooks'
6
9
 
7
- interface PanoTextLabelState {
8
- text: string
9
- left: number
10
- top: number
11
- fontSize: number
10
+ /**
11
+ * 通过传入中心点确定矩形框架容器的四个点:
12
+ * 1. 已知矩形长宽和中心点
13
+ * 2. 借助planeGeometry生成垂直相机视角的平面上的四个点
14
+ * 3. 通过向量相加,平行四边形法则获取到移动position后的面上四个点
15
+ */
16
+ const calcPoints = (
17
+ centerPoint: Vector3,
18
+ normal: THREE.Vector3 | undefined,
19
+ wrapperLength: number,
20
+ wrapperWidth: number
21
+ ) => {
22
+ // 375px 对应 1m
23
+ const length = wrapperLength / 375
24
+ const width = wrapperWidth / 375
25
+
26
+ const geometry = new THREE.PlaneGeometry(length, width)
27
+ if (normal) {
28
+ const lookPoint = new THREE.Vector3(normal.x + centerPoint.x, normal.y + centerPoint.y, normal.z + centerPoint.z)
29
+ geometry.lookAt(lookPoint)
30
+ }
31
+ // const pointgeometry = new THREE.Geometry()
32
+ // pointgeometry.vertices.push(cameraPosition)
33
+ // const pointmaterial = new THREE.PointsMaterial({
34
+ // color: 0xffffff,
35
+ // size: 0.4,
36
+ // })
37
+ // _point = new THREE.Points(pointgeometry, pointmaterial)
38
+
39
+ const material = new THREE.MeshBasicMaterial({ color: 0xffff00, side: THREE.DoubleSide })
40
+ const plane = new THREE.Mesh(geometry, material)
41
+ const v0 = centerPoint.clone()
42
+ plane.position.copy(v0)
43
+
44
+ // 计算传入的四个点的坐标
45
+ const [v1, v2, v3, v4] = plane.geometry.vertices
46
+ const downLeft = v0.clone().add(v4)
47
+ const downRight = v0.clone().add(v3)
48
+ const upLeft = v0.clone().add(v2)
49
+ const upRight = v0.clone().add(v1)
50
+
51
+ // 插件使用要求:矩形四个点位数据,顺序为**必须**为左下、右下、右上、左上
52
+ return [downLeft, downRight, upRight, upLeft]
12
53
  }
13
54
 
55
+ /**
56
+ * 空间文本标签。
57
+ */
14
58
  export function PanoTextLabel() {
15
- const [state, setState] = React.useState<PanoTextLabelState | null>(null)
16
59
  const timeoutRef = React.useRef<NodeJS.Timeout | null>()
17
60
  const controller = useController()
18
- const project2d = useFiveProject2d()
61
+ const five = useFiveInstance()
62
+ const ref = React.useRef<ReturnType<typeof CSS3DRenderPlugin>>()
19
63
 
20
64
  React.useEffect(() => {
21
65
  if (controller.configs?.keyframeMap.PanoTextLabel === false) {
@@ -24,19 +68,43 @@ export function PanoTextLabel() {
24
68
  const callback = (keyframe: VreoKeyframe) => {
25
69
  const { start, end, data } = keyframe
26
70
  const panoTextLabelData = data as PanoTextLabelData
71
+ // 增加无文本情况的判断
72
+ if (data.text === '') return
73
+
27
74
  const { x, y, z } = panoTextLabelData.vertex
75
+ const centerPoint = new Vector3(x, y, z)
76
+ const normal = new Vector3(panoTextLabelData.normal?.x, panoTextLabelData.normal?.y, panoTextLabelData.normal?.z)
77
+ // 生成传入的四个点,将文本框最大宽度定在200px,最高高度在30px
78
+ const wrapperLength = 200
79
+ const wrapperWidth = 30
80
+ const points = calcPoints(centerPoint, panoTextLabelData.normal && normal, wrapperLength, wrapperWidth)
28
81
 
29
- const res = project2d(new Vector3(x, y, z))
30
- if (!res) return
31
- const { x: left, y: top } = res
82
+ if (!ref.current) ref.current = CSS3DRenderPlugin(five)
83
+ const container = ref.current.create3DDomContainer(points)
84
+ const css3DObject = container?.css3DObject
85
+ // 将获取的mesh进行旋转操作,根据欧拉角去进行mesh的变换
86
+ if (data.quaternion) {
87
+ const quaternion = new Quaternion(data.quaternion.x, data.quaternion.y, data.quaternion.z, data.quaternion.w)
88
+ css3DObject?.quaternion.copy(quaternion)
89
+ }
90
+ if (container?.container)
91
+ ReactDOM.render(
92
+ <div className="PanoTextLabel PanoTextLabel--notHidden">
93
+ <div className="PanoTextLabel-wrapper">
94
+ <div style={{ fontSize: `${data.fontSize || 16}px` }} className="PanoText-innerText">
95
+ {data.text || ''}
96
+ </div>
97
+ </div>
98
+ </div>,
99
+ container?.container
100
+ )
32
101
 
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)
102
+ timeoutRef.current = setTimeout(() => {
103
+ ref.current?.disposeAll()
104
+ }, end - start)
36
105
  }
37
106
  controller.on(VreoKeyframeEnum.PanoTextLabel, callback)
38
107
 
39
- // Object.assign(window, { $panoTextLabel: { setState } })
40
108
  return () => {
41
109
  controller.off(VreoKeyframeEnum.PanoTextLabel, callback)
42
110
  if (timeoutRef.current) {
@@ -45,21 +113,5 @@ export function PanoTextLabel() {
45
113
  }
46
114
  }, [controller])
47
115
 
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
- )
116
+ return <></>
65
117
  }
@@ -2,7 +2,6 @@ import * as React from 'react'
2
2
  import classNames from 'classnames'
3
3
  import { useController } from '../../../hooks'
4
4
 
5
- import { CSSTransition, TransitionGroup } from 'react-transition-group'
6
5
  import { VreoKeyframe, VreoKeyframeEnum } from '../../../../typings/VreoUnit'
7
6
 
8
7
  export function Prompter() {
@@ -27,7 +26,8 @@ export function Prompter() {
27
26
 
28
27
  ref.current = setTimeout(() => {
29
28
  setHidden(true)
30
- setTimeout(() => setText(''), 500)
29
+ setText('')
30
+ // setTimeout(() => setText(''), 500)
31
31
 
32
32
  if (ref.current) clearTimeout(ref.current)
33
33
  ref.current = null
@@ -45,22 +45,12 @@ export function Prompter() {
45
45
  <div
46
46
  className={classNames('vreo-prompter', {
47
47
  'vreo-prompter--hidden': hidden,
48
- 'vreo-prompter--audio': controller.isAudio,
48
+ [`vreo-prompter-left--${controller.agentType}`]: true,
49
49
  })}
50
50
  >
51
- {text ? (
52
- /* @warning "index.js:1 Warning: findDOMNode is deprecated in StrictMode." */
53
- <TransitionGroup className="vreo-prompter-text">
54
- <CSSTransition
55
- key={text}
56
- classNames="vreo-prompter-text-transition"
57
- timeout={500}
58
- addEndListener={(node, done) => node.addEventListener('transitionend', done, false)}
59
- >
60
- <div className="vreo-prompter-innerText">{text}</div>
61
- </CSSTransition>
62
- </TransitionGroup>
63
- ) : undefined}
51
+ <div className="vreo-prompter-text">
52
+ <div className="vreo-prompter-innerText">{text}</div>
53
+ </div>
64
54
  </div>
65
55
  )
66
56
  }