@realsee/dnalogel 2.0.0-alpha.13 → 2.0.0-alpha.14

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 (58) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +78 -28
  3. package/dist/ModelItemLabelPlugin/index.js +16 -4
  4. package/dist/ModelItemLabelPlugin/typings.d.ts +1 -0
  5. package/dist/ModelTVVideoPlugin/index.d.ts +4 -0
  6. package/dist/ModelTVVideoPlugin/index.js +326 -0
  7. package/dist/ModelTVVideoPlugin/typings.d.ts +25 -0
  8. package/dist/ModelTVVideoPlugin/utils/parseData.d.ts +2 -0
  9. package/dist/PanoMeasurePlugin/index.js +2 -2
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.es.js +292 -7
  12. package/dist/index.js +292 -6
  13. package/dist/index.umd.js +292 -6
  14. package/docs/assets/main.js +1 -1
  15. package/docs/assets/search.js +1 -1
  16. package/docs/classes/ModelRoomLabelController.html +6 -6
  17. package/docs/enums/FLOOR_PLAN_ATTACHED_TO.html +1 -1
  18. package/docs/enums/ModelFloorplanErrorType.html +1 -1
  19. package/docs/index.html +78 -33
  20. package/docs/interfaces/LineJson.html +1 -1
  21. package/docs/interfaces/ModelChassisCompassPluginData.html +1 -1
  22. package/docs/interfaces/ModelChassisCompassPluginExportType.html +1 -1
  23. package/docs/interfaces/ModelChassisCompassPluginParameterType.html +1 -1
  24. package/docs/interfaces/ModelEntryDoorGuidePluginData.html +1 -1
  25. package/docs/interfaces/ModelEntryDoorGuidePluginExportType.html +1 -1
  26. package/docs/interfaces/ModelFloorplanParameterType.html +1 -1
  27. package/docs/interfaces/ModelFloorplanViewEvent.html +2 -2
  28. package/docs/interfaces/ModelItemLabelPluginData.html +1 -0
  29. package/docs/interfaces/ModelItemLabelPluginExportReturnsType.html +1 -0
  30. package/docs/interfaces/ModelItemLabelPluginParametersType.html +1 -0
  31. package/docs/interfaces/ModelRoomLabelPluginData.html +1 -1
  32. package/docs/interfaces/ModelTVVideoPluginData.html +1 -0
  33. package/docs/interfaces/ModelTVVideoPluginExportType.html +1 -0
  34. package/docs/interfaces/ModelTVVideoPluginParameterType.html +1 -0
  35. package/docs/interfaces/PanoCompassPluginData.html +1 -1
  36. package/docs/interfaces/PanoCompassPluginParameterType.html +1 -1
  37. package/docs/interfaces/PanoCursorRaycasterPluginExportType.html +6 -6
  38. package/docs/interfaces/PanoRulerPluginExportType.html +1 -1
  39. package/docs/interfaces/PanoRulerPluginOptions.html +1 -1
  40. package/docs/interfaces/PanoRulerPluginParameterType.html +1 -1
  41. package/docs/interfaces/PanoSpatialTagPluginData.html +1 -1
  42. package/docs/interfaces/PanoSpatialTagPluginExportType.html +1 -1
  43. package/docs/interfaces/PanoSpatialTagPluginParameterType.html +1 -1
  44. package/docs/interfaces/PointJson.html +1 -1
  45. package/docs/interfaces/RoomLabel.html +7 -7
  46. package/docs/interfaces/TopviewFloorplanPluginParameterType.html +1 -1
  47. package/docs/modules.html +12 -12
  48. package/libs/ModelItemLabelPlugin/index.js +16 -4
  49. package/libs/ModelItemLabelPlugin/typings.d.ts +1 -0
  50. package/libs/ModelTVVideoPlugin/index.d.ts +4 -0
  51. package/libs/ModelTVVideoPlugin/index.js +263 -0
  52. package/libs/ModelTVVideoPlugin/typings.d.ts +25 -0
  53. package/libs/ModelTVVideoPlugin/typings.js +7 -0
  54. package/libs/ModelTVVideoPlugin/utils/parseData.d.ts +2 -0
  55. package/libs/ModelTVVideoPlugin/utils/parseData.js +13 -0
  56. package/libs/index.d.ts +3 -0
  57. package/libs/index.js +1 -1
  58. package/package.json +1 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,49 @@
1
+ # CHANGELOG
2
+
3
+ ## 2.0.0-alpha.14
4
+ - 1.feat: 新增 ModelTVVideoPlugin 插件;
5
+ - 2.fix: 修复 ModelItemLabelPlugin disable & enable 方法逻辑;
6
+ - 3.refactor: 增加 ModelItemLabelPlugin 类型导出。
7
+
8
+ ## 2.0.0-alpha.13
9
+ - 1.chore: 修改 tsconfig.json target 配置项为 es6。
10
+
11
+ ## 2.0.0-alpha.12
12
+ - 1.feat: 新增 ModelItemLabelPlugin
13
+
14
+ ## 2.0.0-alpha.11
15
+ - 1.fix: 修复 ModelRoomLabelPlugin 未监听多楼层切换 rerender 问题。
16
+ - 2.feat: ModelFloorplanPlugin & TopviewFloorplanPlugin 新增 `northDesc?: string` 配置项,支持用户修改指北针名称。
17
+
18
+ ## 2.0.0-alpha.10
19
+ - 1.feat: 新增空间三维标签插件 PanoSpatialTagPlugin
20
+ - 2.feat: 新增轻量 ejs 渲染模板函数 shared-utils/tinyEJSrender.js
21
+
22
+ ## 2.0.0-alpha.9
23
+ - 1.refactor: 增加插件独立 js 输出及对 svelte 的编译。
24
+
25
+ ## 2.0.0-alpha.8
26
+ - 1.fix: 修复 ModelViewPlugin 实景 VR 模型不居中问题;
27
+ - 2.fix: 修复 ModelRoomLabelPlugin fov 更新未 rerender 问题;
28
+ - 2.fix: 修复 ModelRoomLabelPlugin enable 判断问题;
29
+ - 4.fix: 修改 ModelFloorplanPlugin 在全景态满足户型图的俯仰角时会自动切换户型图问题。
30
+
31
+ ## 2.0.0-alpha.7
32
+ - 1.fix: PanoCompassPlugin 向下兼容;
33
+ - 2.feat: 新增 PC 全景测量插件:PanoMeasurePlugin;
34
+ - 3.docs: 修改 README.md;
35
+
36
+ ## 2.0.0-alpha.6
37
+ - 1.fix: 标尺插件 PanoRulerPlugin 所有标尺仅展示一次问题;
38
+ - 2.fix: TopviewFloorplanPlugin && ModelFloorplanPlugin 插件小雷达位置显示不正确问题;
39
+ - 3.feat: 为 TopviewFloorplanPlugin && ModelFloorplanPlugin 插件新增线框图吸附位置配置选项。
40
+ - 可选地板、天花板、模型中心,默认吸附选项为模型中心。
41
+
42
+ ## 2.0.0-alpha.5
43
+ 1.修复全景指南针插件 PanoCompassPlugin 默认导出 name
44
+
45
+ ## 2.0.0-alpha.4
46
+ 1.新增全景标尺插件 PanoRulerPlugin
47
+
48
+ ## 2.0.0-alpha.3
49
+ 1.新增全景指南针插件 PanoCompassPlugin
package/README.md CHANGED
@@ -1,50 +1,100 @@
1
- # 注意
2
- 2.x 版本依赖 `svelte`, 使用时请同时安装
3
- ```bash
4
- npm install svelte
5
- ```
1
+ <p align="center">
2
+ <a href="https://realsee.js.org/"><img src="https://vrlab-public.ljcdn.com/common/file/web/ea031fa5-ad82-46b3-86c8-7b20ec1e635a.jpg" width="60" /></a>
3
+ </p>
6
4
 
7
- # 如视 -- "Dnalogel"
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@realsee/dnalogel">
7
+ <img src="https://img.shields.io/npm/v/@realsee/dnalogel.svg" alt="npm version" >
8
+ </a>
9
+ <a href="https://packagephobia.now.sh/result?p=@realsee/dnalogel">
10
+ <img src="https://packagephobia.now.sh/badge?p=@realsee/dnalogel" alt="install size" >
11
+ </a>
12
+ <a href="https://github.com/realsee-developer/dnalogel/blob/main/plugins/TERMS.txt">
13
+ <img src="https://img.shields.io/npm/l/@realsee/dnalogel.svg" alt="license">
14
+ </a>
15
+ </p>
8
16
 
9
- [如视(realsee.com)](https://realsee.com) 提供了在浏览器环境中的渲染三维空间 [VR 看房 SDK Five](https://open-platform.realsee.com/developer/docs/front/3d-space/get-started/rendering-engine/) 。
10
- 通过 [如视开放 API](https://open-platform.realsee.com/developer/open/api/#/) 并结合 Five 的渲染能力可以制作丰富多彩的三维空间应用。
17
+ <h1 align="center">@realsee/dnalogel</h1>
11
18
 
12
- 除了 Five 强大的三维空间渲染能力之外,我们也积累了大量的 **VR 看房** 常用功能,并以 `Five Plugins` 的形式进行抽象。
19
+ # 👀 Overview
13
20
 
14
- 无论是经过线上环境千锤百炼的刚需功能,还是灵感一现的炫酷尝试,凡是最终落地的功能我们均毫无保留的开源至 github [realsee-developer](https://github.com/realsee-developer) 空间。
21
+ @realsee/dnalogel [如视(realsee.com)](https://realsee.com) **VR 看房** 常用能力沉淀,并以 `Five Plugins` 形式进行抽象。
22
+ 结合[如视 VR 看房 SDK Five](https://open-platform.realsee.com/developer/docs/front/3d-space/get-started/rendering-engine/)
23
+ 与 [如视开放 API](https://open-platform.realsee.com/developer/open/api/#/) ,可以制作出丰富多彩的三维空间应用。不论是经过线上环境千锤百炼的刚需功能,还是灵感一现的炫酷尝试,所有已经落地的功能我们均毫无保留的开源至github [realsee-developer/dnalogel](https://github.com/realsee-developer/dnalogel) 。
15
24
 
16
- 如果插件满足您的需求,`npm install @realsee/dnalogel`一键安装使用。
25
+ # 🔨 Usage
17
26
 
18
- 如果不满足需求,没关系,把我们当作代码示例,我们抛砖引玉。
27
+ **1、安装**
19
28
 
20
- 我们也很期待您基于 [Three.js](https://threejs.org/) 、[Five.js](https://www.npmjs.com/package/@realsee/five) 等这类渲染库做出有意思的功能。
29
+ ```bash
30
+ npm install @realsee/dnalogel
31
+ ```
21
32
 
33
+ ```bash
34
+ yarn add @realsee/dnalogel
35
+ ```
22
36
 
23
- ### 插件列表
24
- - ModelViewPlugin:模型小窗插件
25
- - PanoFloorplanRadarPlugin:全景户型雷达图插件
26
- - ModelRoomLabelPlugin:模型态房屋标签插件
27
- - TopviewFloorplanPlugin:俯视模型户型图插件
28
- - ModelChassisCompassPlugin:模型底盘指南针插件
29
- - ModelEntryDoorGuidePlugin:模型入户门引导插件
30
- - CSS3DRenderPlugin:CSS3D渲染插件
31
- - CameraMovementPlugin:相机运镜插件
32
- - ModelFloorplanPlugin:模型户型图插件
33
- - PanoRulerPlugin:全景标尺插件
34
- - PanoCompassPlugin:全景指南针插件
35
- - ... 待补充
37
+ 2.x 版本依赖 `svelte`, 使用时请同时安装:
38
+ ```bash
39
+ npm install svelte
40
+ ```
41
+
42
+ ```bash
43
+ yarn add svelte
44
+ ```
36
45
 
37
- ### 使用方式
46
+ **2、插件注册**
38
47
 
39
48
  ```js
40
49
  import { Five } from '@realsee/five'
41
- import Plugin from '@realsee/dnalogel/plugins/Plugin'
50
+ import { Plugin } from '@realsee/dnalogel'
42
51
  const five = new Five({
43
52
  plugins: [[Plugin, 'PluginName', initOptions]],
44
53
  })
54
+ ```
55
+
56
+ **3、插件方法使用**
45
57
 
58
+ ```js
46
59
  // 不同插件提供的方法可能存在差异,请参考各插件 API 文档
47
60
  five.plugins.PluginName.load(data)
48
61
  five.plugins.PluginName.enable()
49
62
  five.plugins.PluginName.disable()
63
+ five.plugins.PluginName.dispose()
50
64
  ```
65
+
66
+ **4、插件依赖数据获取**
67
+
68
+ 您可以通过 [open API](https://open-platform.realsee.com/developer/open/api#/) 查看数据获取方式及相关 open API 。
69
+
70
+ # 📖 Documents
71
+
72
+ - [说明文档](https://open-platform.realsee.com/developer/docs/front/3d-space/advanced/dnalogel/ModelViewPlugin/)
73
+ - [API 文档](https://unpkg.com/@realsee/dnalogel/docs/index.html)
74
+ - [demo 源码](https://github.com/realsee-developer/dnalogel/tree/main/examples/src)
75
+ - [数据依赖来源:open API](https://open-platform.realsee.com/developer/open/api/)
76
+ - [CHANGELOG](https://github.com/realsee-developer/dnalogel/blob/main/plugins/CHANGELOG.md)
77
+
78
+ # 💡 Preview
79
+
80
+ 我们为每个插件书写了简单的效果示例,您可点击预览:
81
+ [@realsee/dnalogel showcase](https://realsee.js.org/dnalogel/)
82
+
83
+
84
+ # 🧾 Lists
85
+
86
+ - 🔌 ModelViewPlugin:模型小窗插件
87
+ - 🔌 PanoFloorplanRadarPlugin:全景户型雷达图插件
88
+ - 🔌 ModelRoomLabelPlugin:模型态房屋标签插件
89
+ - 🔌 TopviewFloorplanPlugin:俯视模型户型图插件
90
+ - 🔌 ModelChassisCompassPlugin:模型底盘指南针插件
91
+ - 🔌 ModelEntryDoorGuidePlugin:模型入户门引导插件
92
+ - 🔌 CSS3DRenderPlugin:CSS3D渲染插件
93
+ - 🔌 CameraMovementPlugin:相机运镜插件
94
+ - 🔌 ModelFloorplanPlugin:模型户型图插件
95
+ - 🔌 PanoRulerPlugin:全景标尺插件
96
+ - 🔌 PanoCompassPlugin:全景指南针插件
97
+ - 其他插件持续更新中...
98
+
99
+ # License
100
+ [TERMS](https://github.com/realsee-developer/dnalogel/blob/main/plugins/TERMS.txt)
@@ -519,7 +519,8 @@ const ModelItemLabelPlugin = (five$1, params) => {
519
519
  app: undefined,
520
520
  hooks: new five.Subscribe(),
521
521
  modelOcclusionEnable: (_a = params === null || params === void 0 ? void 0 : params.modelOcclusionEnable) !== null && _a !== void 0 ? _a : true,
522
- displayStrategyType: (_b = params === null || params === void 0 ? void 0 : params.displayStrategyType) !== null && _b !== void 0 ? _b : DISPLAY_STRATEGY_TYPE.SMALL
522
+ displayStrategyType: (_b = params === null || params === void 0 ? void 0 : params.displayStrategyType) !== null && _b !== void 0 ? _b : DISPLAY_STRATEGY_TYPE.SMALL,
523
+ pending: false
523
524
  };
524
525
  pluginState.container.setAttribute('class', 'model-item-label-plugin-container');
525
526
  pluginState.container.style.cssText = `
@@ -528,8 +529,8 @@ const ModelItemLabelPlugin = (five$1, params) => {
528
529
  top: 0;
529
530
  width: 100%;
530
531
  height: 100%;
531
- pointerEvents: none;
532
532
  `;
533
+ pluginState.container.style.pointerEvents = 'none'; // 写到 cssText 里不生效
533
534
  const appendTo = (wrapper) => {
534
535
  pluginState.wrapper = wrapper;
535
536
  wrapper.appendChild(pluginState.container);
@@ -537,7 +538,6 @@ const ModelItemLabelPlugin = (five$1, params) => {
537
538
  return true;
538
539
  };
539
540
  const load = (data) => {
540
- console.log('🐶--当前标签总条数: ', data.model_item_labels.length);
541
541
  pluginState.itemLabels = parseModelItemLabelPluginData(data);
542
542
  render();
543
543
  };
@@ -560,23 +560,30 @@ const ModelItemLabelPlugin = (five$1, params) => {
560
560
  pluginState.container.remove();
561
561
  };
562
562
  const handleRerender = () => {
563
- if (!pluginState.enabled || !pluginState.fiveModeEnabled)
563
+ if (!pluginState.enabled || !pluginState.fiveModeEnabled || pluginState.pending)
564
564
  return;
565
+ pluginState.pending = true;
565
566
  disable();
566
567
  };
567
568
  const rerender = (a, b, c) => {
569
+ if (!pluginState.pending)
570
+ return;
568
571
  if (!pluginState.fiveModeEnabled)
569
572
  return;
570
573
  if (!c)
571
574
  return;
575
+ pluginState.pending = false;
572
576
  enable();
573
577
  render();
574
578
  };
575
579
  const handleInteriaPanRerender = (a, b) => {
580
+ if (!pluginState.pending)
581
+ return;
576
582
  if (!pluginState.fiveModeEnabled)
577
583
  return;
578
584
  if (!b)
579
585
  return;
586
+ pluginState.pending = false;
580
587
  enable();
581
588
  render();
582
589
  };
@@ -586,10 +593,13 @@ const ModelItemLabelPlugin = (five$1, params) => {
586
593
  }
587
594
  };
588
595
  const handlePanGesture = (pose, final) => {
596
+ if (!pluginState.pending)
597
+ return;
589
598
  if (!pluginState.fiveModeEnabled)
590
599
  return;
591
600
  if (!final)
592
601
  return;
602
+ pluginState.pending = false;
593
603
  enable();
594
604
  render();
595
605
  };
@@ -654,6 +664,8 @@ const ModelItemLabelPlugin = (five$1, params) => {
654
664
  five$1.off('pinchGesture', rerender);
655
665
  };
656
666
  const onFiveModeChange = (mode) => {
667
+ if (!pluginState.enabled || pluginState.pending)
668
+ return;
657
669
  if (mode !== five.Five.Mode.Floorplan) {
658
670
  pluginState.fiveModeEnabled = false;
659
671
  render();
@@ -52,4 +52,5 @@ export interface ModelItemLabelPluginState {
52
52
  hooks: Subscribe<PluginEvent>;
53
53
  modelOcclusionEnable: boolean;
54
54
  displayStrategyType: Partial<DISPLAY_STRATEGY_TYPE>;
55
+ pending: boolean;
55
56
  }
@@ -0,0 +1,4 @@
1
+ import type { FivePlugin } from '@realsee/five';
2
+ import { ModelTVVideoPluginExportType, ModelTVVideoPluginParameterType } from "./typings";
3
+ export declare const ModelTVVideoPlugin: FivePlugin<ModelTVVideoPluginParameterType, ModelTVVideoPluginExportType>;
4
+ export default ModelTVVideoPlugin;
@@ -0,0 +1,326 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var THREE = require('three');
6
+
7
+ function _interopNamespace(e) {
8
+ if (e && e.__esModule) return e;
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n["default"] = e;
22
+ return Object.freeze(n);
23
+ }
24
+
25
+ var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
26
+
27
+ /*! *****************************************************************************
28
+ Copyright (c) Microsoft Corporation.
29
+
30
+ Permission to use, copy, modify, and/or distribute this software for any
31
+ purpose with or without fee is hereby granted.
32
+
33
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
34
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
35
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
36
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
37
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
38
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
39
+ PERFORMANCE OF THIS SOFTWARE.
40
+ ***************************************************************************** */
41
+
42
+ function __awaiter(thisArg, _arguments, P, generator) {
43
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
44
+ return new (P || (P = Promise))(function (resolve, reject) {
45
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
46
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
47
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
48
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
49
+ });
50
+ }
51
+
52
+ var DIRECTION;
53
+ (function (DIRECTION) {
54
+ DIRECTION["TOP_LEFT"] = "topLeft";
55
+ DIRECTION["TOP_RIGHT"] = "topRight";
56
+ DIRECTION["BOTTOM_LEFT"] = "bottomLeft";
57
+ DIRECTION["BOTTOM_RIGHT"] = "bottomRight";
58
+ })(DIRECTION || (DIRECTION = {}));
59
+
60
+ function parseModelTVVideoPoints(points) {
61
+ if (points.length === 0)
62
+ return [];
63
+ if (Array.isArray(points[0]))
64
+ return points;
65
+ let newPoints = [];
66
+ points.map(point => {
67
+ const newPoint = [point[DIRECTION.TOP_LEFT], point[DIRECTION.BOTTOM_LEFT], point[DIRECTION.BOTTOM_RIGHT], point[DIRECTION.TOP_RIGHT]];
68
+ newPoints.push(newPoint);
69
+ });
70
+ return newPoints;
71
+ }
72
+
73
+ const ModelTVVideoPlugin = (five, { videoElement }) => {
74
+ const state = {
75
+ videoMeshes: [],
76
+ videoTextureEnabled: false,
77
+ videoSource: '',
78
+ rectPoints: [],
79
+ enabled: false,
80
+ videoElement: videoElement,
81
+ };
82
+ const setMuted = (muted) => {
83
+ if (state.videoTexture) {
84
+ state.videoTexture.image.muted = muted;
85
+ state.videoTexture.image.play();
86
+ }
87
+ };
88
+ const getMuted = () => {
89
+ if (state.videoTexture)
90
+ return state.videoTexture.image.muted;
91
+ else
92
+ return true;
93
+ };
94
+ const enable = () => {
95
+ if (state.enabled)
96
+ return;
97
+ if (!state.videoTexture)
98
+ return;
99
+ state.enabled = true;
100
+ state.videoMeshes = createPanoVideoMeshes();
101
+ console.log('state.videoMeshes', state.videoMeshes);
102
+ state.videoMeshes.forEach((mesh) => five.scene.add(mesh));
103
+ const play = () => {
104
+ console.log('play', state.videoTexture);
105
+ if (!state.videoTexture)
106
+ return;
107
+ const timeupdate = () => {
108
+ var _a;
109
+ if (!state.videoTexture)
110
+ return;
111
+ (_a = state.videoTexture) === null || _a === void 0 ? void 0 : _a.image.removeEventListener('timeupdate', timeupdate);
112
+ state.videoTextureEnabled = true;
113
+ state.videoMeshes.forEach((mesh) => {
114
+ if (mesh.material.map !== state.videoTexture)
115
+ mesh.material.map = state.videoTexture;
116
+ });
117
+ five.needsRender = true;
118
+ };
119
+ state.videoTexture.image.addEventListener('timeupdate', timeupdate);
120
+ if (state.videoTexture && state.videoMeshes.length) {
121
+ state.videoTexture.image.play();
122
+ }
123
+ };
124
+ if (five.model.loaded)
125
+ play();
126
+ else {
127
+ return five.once('modelLoaded', () => play());
128
+ }
129
+ };
130
+ const disable = () => {
131
+ if (!state.enabled)
132
+ return;
133
+ state.enabled = false;
134
+ state.videoMeshes.forEach((mesh) => {
135
+ mesh.geometry.dispose();
136
+ mesh.material.dispose();
137
+ five.scene.remove(mesh);
138
+ if (state.videoTexture)
139
+ state.videoTexture.image.pause();
140
+ });
141
+ state.videoMeshes = [];
142
+ five.needsRender = true;
143
+ };
144
+ const createPanoVideoMeshes = () => {
145
+ return state.rectPoints.map((points, index) => {
146
+ const geometry = new THREE__namespace.BufferGeometry();
147
+ const segments = 128;
148
+ const verticesArray = [];
149
+ verticesArray.push(points[0].x, points[0].y, points[0].z);
150
+ for (let i = 1; i < segments; i++) {
151
+ verticesArray.push(points[0].x + ((points[1].x - points[0].x) * i) / segments, points[0].y + ((points[1].y - points[0].y) * i) / segments, points[0].z + ((points[1].z - points[0].z) * i) / segments);
152
+ }
153
+ verticesArray.push(points[1].x, points[1].y, points[1].z);
154
+ verticesArray.push(points[2].x, points[2].y, points[2].z);
155
+ for (let i = 1; i < segments; i++) {
156
+ verticesArray.push(points[2].x + ((points[3].x - points[2].x) * i) / segments, points[2].y + ((points[3].y - points[2].y) * i) / segments, points[2].z + ((points[3].z - points[2].z) * i) / segments);
157
+ }
158
+ verticesArray.push(points[3].x, points[3].y, points[3].z);
159
+ const uvArray = [];
160
+ uvArray.push(0, 1);
161
+ for (let i = 1; i < segments; i++) {
162
+ uvArray.push(0, 1 - i / segments);
163
+ }
164
+ uvArray.push(0, 0);
165
+ uvArray.push(1, 0);
166
+ for (let i = 1; i < segments; i++) {
167
+ uvArray.push(1, i / segments);
168
+ }
169
+ uvArray.push(1, 1);
170
+ const indicesArray = [];
171
+ for (let i = 0; i < segments; i++) {
172
+ indicesArray.push(i, i + 1, segments * 2 - i, i, segments * 2 - i, segments * 2 + 1 - i);
173
+ }
174
+ geometry.setAttribute('position', new THREE__namespace.BufferAttribute(new Float32Array(verticesArray), 3));
175
+ geometry.setAttribute('uv', new THREE__namespace.BufferAttribute(new Float32Array(uvArray), 2));
176
+ geometry.setIndex(new THREE__namespace.BufferAttribute(new Uint32Array(indicesArray), 1));
177
+ const material = new THREE__namespace.MeshBasicMaterial({
178
+ map: state.videoTextureEnabled ? state.videoTexture : state.imageTexture,
179
+ side: THREE__namespace.DoubleSide,
180
+ });
181
+ const mesh = new THREE__namespace.Mesh(geometry, material);
182
+ mesh.renderOrder = 1;
183
+ mesh.name = `ModelTVVideoPlugin-${index}-${performance.now()}`;
184
+ return mesh;
185
+ });
186
+ };
187
+ const getImageTexture = (source) => {
188
+ const texture = new THREE__namespace.TextureLoader().load(source);
189
+ texture.minFilter = THREE__namespace.LinearFilter;
190
+ texture.magFilter = THREE__namespace.LinearFilter;
191
+ texture.format = THREE__namespace.RGBFormat;
192
+ return texture;
193
+ };
194
+ const getVideoTexture = (source, video) => {
195
+ return new Promise((resolve, reject) => {
196
+ const xhr = new XMLHttpRequest();
197
+ xhr.onreadystatechange = () => {
198
+ if (xhr.readyState == 4) {
199
+ if (xhr.status == 200) {
200
+ const url = window.URL || window.webkitURL;
201
+ video = video || document.createElement('video');
202
+ video.crossOrigin = 'anonymous';
203
+ video.autoplay = true;
204
+ video.muted = true;
205
+ video.loop = true;
206
+ video.playsInline = true;
207
+ video.src = url.createObjectURL(xhr.response);
208
+ const texture = new THREE__namespace.VideoTexture(video);
209
+ texture.minFilter = THREE__namespace.LinearFilter;
210
+ texture.magFilter = THREE__namespace.LinearFilter;
211
+ texture.format = THREE__namespace.RGBFormat;
212
+ resolve(Object.assign(texture, { videoSource: source }));
213
+ }
214
+ else {
215
+ reject(new Error('Video download Error: ' + xhr.status));
216
+ }
217
+ }
218
+ };
219
+ xhr.onerror = (error) => reject(error);
220
+ xhr.open('GET', source);
221
+ xhr.responseType = 'blob';
222
+ xhr.send();
223
+ });
224
+ };
225
+ const load = (data, videoElement) => __awaiter(void 0, void 0, void 0, function* () {
226
+ const { video_src, video_poster_src, points } = data;
227
+ state.videoSource = video_src;
228
+ // TODO 存疑,先处理多一次遍历 o(2n)
229
+ state.rectPoints = parseModelTVVideoPoints(points)
230
+ .map((items) => items.map(({ x, y, z }) => new THREE__namespace.Vector3(x, y, z)));
231
+ state.imageTexture = getImageTexture(video_poster_src);
232
+ if (videoElement) {
233
+ state.videoElement = videoElement;
234
+ }
235
+ state.videoTexture = yield getVideoTexture(state.videoSource, state.videoElement);
236
+ state.enabled = !!data.enable;
237
+ if (state.enabled)
238
+ enable();
239
+ });
240
+ const dispose = () => {
241
+ disable();
242
+ state.videoTexture = undefined;
243
+ five.off('modeChange', () => setMuted(true));
244
+ five.off('wantsTapGesture', (raycaster) => {
245
+ if (!state.enabled)
246
+ return;
247
+ const [intersect] = raycaster.intersectObjects(five.scene.children, true);
248
+ if (!!intersect && /^video/.test(intersect.object.name)) {
249
+ if (state.videoTexture)
250
+ setMuted(!state.videoTexture.image.muted);
251
+ return false;
252
+ }
253
+ });
254
+ five.off('panoArrived', () => {
255
+ if (!state.enabled)
256
+ return;
257
+ if (getMuted())
258
+ return;
259
+ const cameraPosition = five.camera.position;
260
+ const visible = state.rectPoints.find((points) => {
261
+ const centerVector = points.reduce((total, curr) => new THREE__namespace.Vector3(total.x + curr.x / points.length, total.y + curr.y / points.length, total.z + curr.z / points.length), new THREE__namespace.Vector3());
262
+ return (points.map((point) => new THREE__namespace.Vector3((point.x + centerVector.x) / 2, (point.y + centerVector.y) / 2, (point.z + centerVector.z) / 2)).filter((vector) => {
263
+ vector = vector.clone().sub(cameraPosition).normalize();
264
+ const raycaster = new THREE__namespace.Raycaster(cameraPosition, vector);
265
+ const [intersect] = raycaster.intersectObjects(five.scene.children, true);
266
+ return !!intersect && /^video/.test(intersect.object.name);
267
+ }).length >= 2);
268
+ });
269
+ if (!visible)
270
+ setMuted(true);
271
+ });
272
+ five.off('renderFrame', () => {
273
+ // console.log('renderFrame', state.videoMeshes)
274
+ state.videoMeshes.forEach((meshes) => {
275
+ if (meshes)
276
+ //@ts-ignore
277
+ meshes.needsRender = true;
278
+ });
279
+ });
280
+ };
281
+ five.on('modeChange', () => setMuted(true));
282
+ five.on('wantsTapGesture', (raycaster) => {
283
+ if (!state.enabled)
284
+ return;
285
+ const targetMesh = five.scene.children.find(item => /^ModelTVVideoPlugin/.test(item.name));
286
+ if (!targetMesh)
287
+ return;
288
+ const intersectObjects = raycaster.intersectObjects([targetMesh]);
289
+ if (intersectObjects.length === 0)
290
+ return;
291
+ if (state.videoTexture)
292
+ setMuted(!state.videoTexture.image.muted); // TODO toggle video play
293
+ return false;
294
+ });
295
+ five.on('panoArrived', () => {
296
+ if (!state.enabled)
297
+ return;
298
+ if (getMuted())
299
+ return;
300
+ const cameraPosition = five.camera.position;
301
+ const visible = state.rectPoints.find((points) => {
302
+ const centerVector = points.reduce((total, curr) => new THREE__namespace.Vector3(total.x + curr.x / points.length, total.y + curr.y / points.length, total.z + curr.z / points.length), new THREE__namespace.Vector3());
303
+ return (points.map((point) => new THREE__namespace.Vector3((point.x + centerVector.x) / 2, (point.y + centerVector.y) / 2, (point.z + centerVector.z) / 2)).filter((vector) => {
304
+ vector = vector.clone().sub(cameraPosition).normalize();
305
+ const raycaster = new THREE__namespace.Raycaster(cameraPosition, vector);
306
+ const [intersect] = raycaster.intersectObjects(five.scene.children, true);
307
+ return !!intersect && /^video/.test(intersect.object.name);
308
+ }).length >= 2);
309
+ });
310
+ if (!visible)
311
+ setMuted(true);
312
+ });
313
+ five.on('renderFrame', () => {
314
+ // console.log('renderFrame', state.videoMeshes)
315
+ state.videoMeshes.forEach((meshes) => {
316
+ if (meshes)
317
+ //@ts-ignore
318
+ meshes.needsRender = true;
319
+ });
320
+ });
321
+ Object.assign(window, { $state: state });
322
+ return { enable, disable, load, dispose };
323
+ };
324
+
325
+ exports.ModelTVVideoPlugin = ModelTVVideoPlugin;
326
+ exports["default"] = ModelTVVideoPlugin;
@@ -0,0 +1,25 @@
1
+ export interface ModelTVVideoPluginParameterType {
2
+ videoElement?: HTMLVideoElement;
3
+ }
4
+ export declare enum DIRECTION {
5
+ TOP_LEFT = "topLeft",
6
+ TOP_RIGHT = "topRight",
7
+ BOTTOM_LEFT = "bottomLeft",
8
+ BOTTOM_RIGHT = "bottomRight"
9
+ }
10
+ export interface Point {
11
+ x: number;
12
+ y: number;
13
+ z: number;
14
+ }
15
+ export interface ModelTVVideoPluginData {
16
+ enable?: boolean;
17
+ video_src: string;
18
+ video_poster_src: string;
19
+ points: Point[][] | Record<DIRECTION, Point>[];
20
+ }
21
+ export interface ModelTVVideoPluginExportType {
22
+ enable: () => void;
23
+ disable: () => void;
24
+ load: (data: ModelTVVideoPluginData, videoElement?: HTMLVideoElement) => Promise<void>;
25
+ }
@@ -0,0 +1,2 @@
1
+ import { DIRECTION, Point } from "../typings";
2
+ export declare function parseModelTVVideoPoints(points: Point[][] | Record<DIRECTION, Point>[]): Point[][];
@@ -2875,10 +2875,10 @@ if (typeof undefined$1 === 'function' && undefined$1.amd) {
2875
2875
 
2876
2876
  var Hammer = hammer.exports;
2877
2877
 
2878
- var Hammer$1 = /*#__PURE__*/_mergeNamespaces({
2878
+ var Hammer$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/_mergeNamespaces({
2879
2879
  __proto__: null,
2880
2880
  'default': Hammer
2881
- }, [hammer.exports]);
2881
+ }, [hammer.exports]));
2882
2882
 
2883
2883
  // uuid
2884
2884
  function S4() {
package/dist/index.d.ts CHANGED
@@ -24,4 +24,7 @@ export type { PluginReturns, PluginEvent, LineJson, PointJson } from './PanoMeas
24
24
  export { default as PanoMeasurePlugin } from './PanoMeasurePlugin';
25
25
  export type { PanoSpatialTagPluginParameterType, PanoSpatialTagPluginData, PanoSpatialTagPluginExportType } from './PanoSpatialTagPlugin';
26
26
  export { default as PanoSpatialTagPlugin } from './PanoSpatialTagPlugin';
27
+ export type { ModelItemLabelPluginData, ModelItemLabelPluginExportReturnsType, ModelItemLabelPluginParametersType } from './ModelItemLabelPlugin/typings';
27
28
  export { default as ModelItemLabelPlugin } from './ModelItemLabelPlugin';
29
+ export type { ModelTVVideoPluginData, ModelTVVideoPluginParameterType, ModelTVVideoPluginExportType } from './ModelTVVideoPlugin/typings';
30
+ export { default as ModelTVVideoPlugin } from './ModelTVVideoPlugin';