@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.
- package/CHANGELOG.md +49 -0
- package/README.md +78 -28
- package/dist/ModelItemLabelPlugin/index.js +16 -4
- package/dist/ModelItemLabelPlugin/typings.d.ts +1 -0
- package/dist/ModelTVVideoPlugin/index.d.ts +4 -0
- package/dist/ModelTVVideoPlugin/index.js +326 -0
- package/dist/ModelTVVideoPlugin/typings.d.ts +25 -0
- package/dist/ModelTVVideoPlugin/utils/parseData.d.ts +2 -0
- package/dist/PanoMeasurePlugin/index.js +2 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.es.js +292 -7
- package/dist/index.js +292 -6
- package/dist/index.umd.js +292 -6
- package/docs/assets/main.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/ModelRoomLabelController.html +6 -6
- package/docs/enums/FLOOR_PLAN_ATTACHED_TO.html +1 -1
- package/docs/enums/ModelFloorplanErrorType.html +1 -1
- package/docs/index.html +78 -33
- package/docs/interfaces/LineJson.html +1 -1
- package/docs/interfaces/ModelChassisCompassPluginData.html +1 -1
- package/docs/interfaces/ModelChassisCompassPluginExportType.html +1 -1
- package/docs/interfaces/ModelChassisCompassPluginParameterType.html +1 -1
- package/docs/interfaces/ModelEntryDoorGuidePluginData.html +1 -1
- package/docs/interfaces/ModelEntryDoorGuidePluginExportType.html +1 -1
- package/docs/interfaces/ModelFloorplanParameterType.html +1 -1
- package/docs/interfaces/ModelFloorplanViewEvent.html +2 -2
- package/docs/interfaces/ModelItemLabelPluginData.html +1 -0
- package/docs/interfaces/ModelItemLabelPluginExportReturnsType.html +1 -0
- package/docs/interfaces/ModelItemLabelPluginParametersType.html +1 -0
- package/docs/interfaces/ModelRoomLabelPluginData.html +1 -1
- package/docs/interfaces/ModelTVVideoPluginData.html +1 -0
- package/docs/interfaces/ModelTVVideoPluginExportType.html +1 -0
- package/docs/interfaces/ModelTVVideoPluginParameterType.html +1 -0
- package/docs/interfaces/PanoCompassPluginData.html +1 -1
- package/docs/interfaces/PanoCompassPluginParameterType.html +1 -1
- package/docs/interfaces/PanoCursorRaycasterPluginExportType.html +6 -6
- package/docs/interfaces/PanoRulerPluginExportType.html +1 -1
- package/docs/interfaces/PanoRulerPluginOptions.html +1 -1
- package/docs/interfaces/PanoRulerPluginParameterType.html +1 -1
- package/docs/interfaces/PanoSpatialTagPluginData.html +1 -1
- package/docs/interfaces/PanoSpatialTagPluginExportType.html +1 -1
- package/docs/interfaces/PanoSpatialTagPluginParameterType.html +1 -1
- package/docs/interfaces/PointJson.html +1 -1
- package/docs/interfaces/RoomLabel.html +7 -7
- package/docs/interfaces/TopviewFloorplanPluginParameterType.html +1 -1
- package/docs/modules.html +12 -12
- package/libs/ModelItemLabelPlugin/index.js +16 -4
- package/libs/ModelItemLabelPlugin/typings.d.ts +1 -0
- package/libs/ModelTVVideoPlugin/index.d.ts +4 -0
- package/libs/ModelTVVideoPlugin/index.js +263 -0
- package/libs/ModelTVVideoPlugin/typings.d.ts +25 -0
- package/libs/ModelTVVideoPlugin/typings.js +7 -0
- package/libs/ModelTVVideoPlugin/utils/parseData.d.ts +2 -0
- package/libs/ModelTVVideoPlugin/utils/parseData.js +13 -0
- package/libs/index.d.ts +3 -0
- package/libs/index.js +1 -1
- 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
|
-
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10
|
-
通过 [如视开放 API](https://open-platform.realsee.com/developer/open/api/#/) 并结合 Five 的渲染能力可以制作丰富多彩的三维空间应用。
|
|
17
|
+
<h1 align="center">@realsee/dnalogel</h1>
|
|
11
18
|
|
|
12
|
-
|
|
19
|
+
# 👀 Overview
|
|
13
20
|
|
|
14
|
-
|
|
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
|
-
|
|
25
|
+
# 🔨 Usage
|
|
17
26
|
|
|
18
|
-
|
|
27
|
+
**1、安装**
|
|
19
28
|
|
|
20
|
-
|
|
29
|
+
```bash
|
|
30
|
+
npm install @realsee/dnalogel
|
|
31
|
+
```
|
|
21
32
|
|
|
33
|
+
```bash
|
|
34
|
+
yarn add @realsee/dnalogel
|
|
35
|
+
```
|
|
22
36
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
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();
|
|
@@ -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
|
+
}
|
|
@@ -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';
|