@realsee/dnalogel 2.0.0-alpha.12 → 2.0.0-alpha.15
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 +11 -0
- package/README.md +78 -28
- package/dist/CSS3DRenderPlugin/index.js +17 -14
- package/dist/CameraMovementPlugin/index.js +40 -15
- package/dist/ModelChassisCompassPlugin/index.js +32 -6
- package/dist/ModelEntryDoorGuidePlugin/index.js +48 -18
- package/dist/ModelItemLabelPlugin/index.js +81 -95
- package/dist/ModelRoomLabelPlugin/index.js +67 -26
- 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/PanoCompassPlugin/index.js +311 -164
- package/dist/PanoCursorRaycasterPlugin/index.js +5 -3
- package/dist/PanoMeasurePlugin/index.js +1335 -581
- package/dist/PanoRulerPlugin/index.js +32 -5
- package/dist/PanoSpatialTagPlugin/index.js +64 -29
- package/dist/floorplan/ModelFloorplanPlugin/index.js +586 -362
- package/dist/floorplan/PanoFloorplanRadarPlugin/index.js +164 -72
- package/dist/floorplan/TopviewFloorplanPlugin/index.js +311 -153
- package/dist/index.d.ts +3 -0
- package/dist/index.es.js +2999 -1419
- package/dist/index.js +3003 -1422
- package/dist/index.umd.js +3003 -1422
- 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/CSS3DRenderPlugin/index.js +16 -13
- package/libs/CameraMovementPlugin/index.js +24 -15
- package/libs/ModelChassisCompassPlugin/index.js +14 -5
- package/libs/ModelEntryDoorGuidePlugin/index.js +24 -12
- package/libs/ModelItemLabelPlugin/ItemLabelComponent.js +54 -67
- package/libs/ModelItemLabelPlugin/index.js +8 -59
- package/libs/ModelItemLabelPlugin/utils/parseData.js +1 -4
- package/libs/ModelRoomLabelPlugin/Controller.js +64 -23
- package/libs/ModelRoomLabelPlugin/RoomLabelItems.js +3 -3
- 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/PanoCompassPlugin/index.js +225 -128
- package/libs/PanoCursorRaycasterPlugin/index.js +5 -3
- package/libs/PanoMeasurePlugin/Controller/BaseController.js +68 -13
- package/libs/PanoMeasurePlugin/Controller/EditController.js +267 -154
- package/libs/PanoMeasurePlugin/Controller/ShortcutKeyController.js +40 -20
- package/libs/PanoMeasurePlugin/Controller/WatchController.js +234 -152
- package/libs/PanoMeasurePlugin/Controller/index.js +131 -47
- package/libs/PanoMeasurePlugin/Model/index.js +30 -5
- package/libs/PanoMeasurePlugin/Model/line.js +60 -10
- package/libs/PanoMeasurePlugin/Model/point.js +24 -4
- package/libs/PanoMeasurePlugin/Model/polyline.js +20 -3
- package/libs/PanoMeasurePlugin/Modules/DeleteDom/index.js +59 -14
- package/libs/PanoMeasurePlugin/Modules/FiveHelper.js +23 -8
- package/libs/PanoMeasurePlugin/Modules/GuideController.js +61 -26
- package/libs/PanoMeasurePlugin/Modules/Magnifier.js +60 -10
- package/libs/PanoMeasurePlugin/Modules/UIController/MainBtnController.js +83 -37
- package/libs/PanoMeasurePlugin/Modules/UIController/Revoke/index.js +52 -17
- package/libs/PanoMeasurePlugin/Modules/UIController/index.js +61 -30
- package/libs/PanoMeasurePlugin/utils/distanceDom.js +3 -2
- package/libs/PanoMeasurePlugin/utils/line.js +8 -7
- package/libs/PanoRulerPlugin/index.js +16 -5
- package/libs/PanoSpatialTagPlugin/index.js +11 -9
- package/libs/floorplan/Components/BaseImage.js +10 -5
- package/libs/floorplan/Components/RoomHighlight/RoomHighlight.js +3 -1
- package/libs/floorplan/Components/RoomMaterials/RoomMaterial.js +5 -6
- package/libs/floorplan/ModelFloorplanPlugin/Components/Compass.js +7 -2
- package/libs/floorplan/ModelFloorplanPlugin/Components/RoomLabels/RoomLabel.js +3 -1
- package/libs/floorplan/ModelFloorplanPlugin/Controller.js +456 -273
- package/libs/floorplan/ModelFloorplanPlugin/utils/correctFiveState.js +33 -22
- package/libs/floorplan/PanoFloorplanRadarPlugin/Components/CurrentFloor/CurrentFloor.js +3 -1
- package/libs/floorplan/PanoFloorplanRadarPlugin/Controller.js +97 -36
- package/libs/floorplan/TopviewFloorplanPlugin/Controller.js +231 -108
- package/libs/floorplan/utils/formatData.js +43 -28
- package/libs/floorplan/utils/formatPosition.js +1 -1
- package/libs/index.d.ts +3 -0
- package/libs/index.js +1 -1
- package/libs/shared-utils/Subscribe.js +8 -1
- package/libs/shared-utils/animationFrame/BetterTween.js +47 -18
- package/libs/shared-utils/createCanvasTextTexture.js +6 -5
- package/libs/shared-utils/five/changeMode.js +23 -12
- package/libs/shared-utils/getPxmm.js +1 -1
- package/libs/shared-utils/math/evenNumber.js +1 -1
- package/libs/shared-utils/three/loadFbxObj.js +20 -9
- package/libs/shared-utils/three/loadTexture.js +17 -6
- package/libs/shared-utils/three/transfromToMeshBasicMaterial.js +2 -1
- package/libs/shared-utils/tinyEJSrender.js +36 -6
- package/libs/shared-utils/to.js +21 -10
- package/libs/shared-utils/useDebounce.js +1 -1
- package/libs/shared-utils/useThrottle.js +2 -1
- package/package.json +2 -1
|
@@ -3,6 +3,7 @@ import ItemLabelComponent from './ItemLabelComponent';
|
|
|
3
3
|
import { DISPLAY_STRATEGY_TYPE } from "./typings";
|
|
4
4
|
import { parseModelItemLabelPluginData } from "./utils/parseData";
|
|
5
5
|
export const ModelItemLabelPlugin = (five, params) => {
|
|
6
|
+
var _a, _b;
|
|
6
7
|
const pluginState = {
|
|
7
8
|
container: document.createElement('div'),
|
|
8
9
|
data: null,
|
|
@@ -12,8 +13,8 @@ export const ModelItemLabelPlugin = (five, params) => {
|
|
|
12
13
|
wrapper: null,
|
|
13
14
|
app: undefined,
|
|
14
15
|
hooks: new Subscribe(),
|
|
15
|
-
modelOcclusionEnable: params
|
|
16
|
-
displayStrategyType: params
|
|
16
|
+
modelOcclusionEnable: (_a = params === null || params === void 0 ? void 0 : params.modelOcclusionEnable) !== null && _a !== void 0 ? _a : true,
|
|
17
|
+
displayStrategyType: (_b = params === null || params === void 0 ? void 0 : params.displayStrategyType) !== null && _b !== void 0 ? _b : DISPLAY_STRATEGY_TYPE.SMALL,
|
|
17
18
|
};
|
|
18
19
|
pluginState.container.setAttribute('class', 'model-item-label-plugin-container');
|
|
19
20
|
pluginState.container.style.cssText = `
|
|
@@ -22,8 +23,8 @@ export const ModelItemLabelPlugin = (five, params) => {
|
|
|
22
23
|
top: 0;
|
|
23
24
|
width: 100%;
|
|
24
25
|
height: 100%;
|
|
25
|
-
pointerEvents: none;
|
|
26
26
|
`;
|
|
27
|
+
pluginState.container.style.pointerEvents = 'none'; // 写到 cssText 里不生效
|
|
27
28
|
const appendTo = (wrapper) => {
|
|
28
29
|
pluginState.wrapper = wrapper;
|
|
29
30
|
wrapper.appendChild(pluginState.container);
|
|
@@ -31,7 +32,6 @@ export const ModelItemLabelPlugin = (five, params) => {
|
|
|
31
32
|
return true;
|
|
32
33
|
};
|
|
33
34
|
const load = (data) => {
|
|
34
|
-
console.log('🐶--当前标签总条数: ', data.model_item_labels.length);
|
|
35
35
|
pluginState.itemLabels = parseModelItemLabelPluginData(data);
|
|
36
36
|
render();
|
|
37
37
|
};
|
|
@@ -53,46 +53,13 @@ export const ModelItemLabelPlugin = (five, params) => {
|
|
|
53
53
|
removeListener4Five();
|
|
54
54
|
pluginState.container.remove();
|
|
55
55
|
};
|
|
56
|
-
const handleRerender = () => {
|
|
57
|
-
if (!pluginState.enabled || !pluginState.fiveModeEnabled)
|
|
58
|
-
return;
|
|
59
|
-
disable();
|
|
60
|
-
};
|
|
61
|
-
const rerender = (a, b, c) => {
|
|
62
|
-
if (!pluginState.fiveModeEnabled)
|
|
63
|
-
return;
|
|
64
|
-
if (!c)
|
|
65
|
-
return;
|
|
66
|
-
enable();
|
|
67
|
-
render();
|
|
68
|
-
};
|
|
69
|
-
const handleInteriaPanRerender = (a, b) => {
|
|
70
|
-
if (!pluginState.fiveModeEnabled)
|
|
71
|
-
return;
|
|
72
|
-
if (!b)
|
|
73
|
-
return;
|
|
74
|
-
enable();
|
|
75
|
-
render();
|
|
76
|
-
};
|
|
77
|
-
const handleWantsPanGesture = (pose, final) => {
|
|
78
|
-
if (pose) {
|
|
79
|
-
handleRerender();
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
const handlePanGesture = (pose, final) => {
|
|
83
|
-
if (!pluginState.fiveModeEnabled)
|
|
84
|
-
return;
|
|
85
|
-
if (!final)
|
|
86
|
-
return;
|
|
87
|
-
enable();
|
|
88
|
-
render();
|
|
89
|
-
};
|
|
90
56
|
const render = () => {
|
|
57
|
+
var _a;
|
|
91
58
|
if (!pluginState.wrapper)
|
|
92
59
|
return;
|
|
93
60
|
// 只要不可展示,销毁容器
|
|
94
61
|
if (!pluginState.enabled || !pluginState.fiveModeEnabled) {
|
|
95
|
-
pluginState.app
|
|
62
|
+
(_a = pluginState.app) === null || _a === void 0 ? void 0 : _a.$destroy();
|
|
96
63
|
pluginState.app = undefined;
|
|
97
64
|
return;
|
|
98
65
|
}
|
|
@@ -121,32 +88,14 @@ export const ModelItemLabelPlugin = (five, params) => {
|
|
|
121
88
|
const addListener4Five = () => {
|
|
122
89
|
five.on('modeChange', onFiveModeChange);
|
|
123
90
|
five.once('dispose', dispose);
|
|
124
|
-
// five.on('wantsGesture', handleRerender)
|
|
125
|
-
// five.on('gesture', rerender)
|
|
126
|
-
five.on('wantsMouseWheel', handleRerender);
|
|
127
|
-
five.on('mouseWheel', rerender);
|
|
128
|
-
five.on('wantsInteriaPan', handleRerender);
|
|
129
|
-
five.on('interiaPan', handleInteriaPanRerender);
|
|
130
|
-
five.on('wantsPanGesture', handleWantsPanGesture);
|
|
131
|
-
five.on('panGesture', handlePanGesture);
|
|
132
|
-
five.on('wantsPinchGesture', handleRerender);
|
|
133
|
-
five.on('pinchGesture', rerender);
|
|
134
91
|
};
|
|
135
92
|
// 取消 five 监听
|
|
136
93
|
const removeListener4Five = () => {
|
|
137
94
|
five.off('modeChange', onFiveModeChange);
|
|
138
|
-
// five.off('wantsGesture', handleRerender)
|
|
139
|
-
// five.off('gesture', rerender)
|
|
140
|
-
five.off('wantsMouseWheel', handleRerender);
|
|
141
|
-
five.off('mouseWheel', rerender);
|
|
142
|
-
five.off('wantsInteriaPan', handleRerender);
|
|
143
|
-
five.off('interiaPan', handleInteriaPanRerender);
|
|
144
|
-
five.off('wantsPanGesture', handleWantsPanGesture);
|
|
145
|
-
five.off('panGesture', handlePanGesture);
|
|
146
|
-
five.off('wantsPinchGesture', handleRerender);
|
|
147
|
-
five.off('pinchGesture', rerender);
|
|
148
95
|
};
|
|
149
96
|
const onFiveModeChange = (mode) => {
|
|
97
|
+
if (!pluginState.enabled)
|
|
98
|
+
return;
|
|
150
99
|
if (mode !== Five.Mode.Floorplan) {
|
|
151
100
|
pluginState.fiveModeEnabled = false;
|
|
152
101
|
render();
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
/** @description 转成内部所需数据 */
|
|
2
2
|
export function parseModelItemLabelPluginData(data) {
|
|
3
|
-
return data.model_item_labels.map(label => ({
|
|
4
|
-
modelPosition: [label.position[0], label.position[1] + label.size[1], label.position[2]],
|
|
5
|
-
...label
|
|
6
|
-
}));
|
|
3
|
+
return data.model_item_labels.map(label => (Object.assign({ modelPosition: [label.position[0], label.position[1] + label.size[1], label.position[2]] }, label)));
|
|
7
4
|
}
|
|
@@ -1,14 +1,69 @@
|
|
|
1
1
|
import RoomLabelItems from './RoomLabelItems';
|
|
2
2
|
import { parseModelRoomLabelPluginData } from './utils/parseData';
|
|
3
3
|
export class ModelRoomLabelController {
|
|
4
|
-
five;
|
|
5
|
-
enabled = true;
|
|
6
|
-
fiveModeEnabled;
|
|
7
|
-
app = undefined;
|
|
8
|
-
wrapper;
|
|
9
|
-
roomLabels = [];
|
|
10
|
-
container = document.createElement('div');
|
|
11
4
|
constructor(five) {
|
|
5
|
+
Object.defineProperty(this, "five", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true,
|
|
9
|
+
value: void 0
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(this, "enabled", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
value: true
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(this, "fiveModeEnabled", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
writable: true,
|
|
21
|
+
value: void 0
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(this, "app", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
writable: true,
|
|
27
|
+
value: undefined
|
|
28
|
+
});
|
|
29
|
+
Object.defineProperty(this, "wrapper", {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
configurable: true,
|
|
32
|
+
writable: true,
|
|
33
|
+
value: void 0
|
|
34
|
+
});
|
|
35
|
+
Object.defineProperty(this, "roomLabels", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
writable: true,
|
|
39
|
+
value: []
|
|
40
|
+
});
|
|
41
|
+
Object.defineProperty(this, "container", {
|
|
42
|
+
enumerable: true,
|
|
43
|
+
configurable: true,
|
|
44
|
+
writable: true,
|
|
45
|
+
value: document.createElement('div')
|
|
46
|
+
});
|
|
47
|
+
/** 监听 Five Mode 变化
|
|
48
|
+
* @description
|
|
49
|
+
* Mode 不符合要求时,立刻消失,满足要求时,需要等待动画结束再展示
|
|
50
|
+
*/
|
|
51
|
+
Object.defineProperty(this, "onFiveModeChange", {
|
|
52
|
+
enumerable: true,
|
|
53
|
+
configurable: true,
|
|
54
|
+
writable: true,
|
|
55
|
+
value: (mode) => {
|
|
56
|
+
if (mode !== 'Floorplan') {
|
|
57
|
+
this.fiveModeEnabled = false;
|
|
58
|
+
this.render();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
this.five.once('initAnimationEnded', () => {
|
|
62
|
+
this.fiveModeEnabled = this.five.currentMode === 'Floorplan';
|
|
63
|
+
this.render();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
});
|
|
12
67
|
this.five = five;
|
|
13
68
|
this.fiveModeEnabled = this.five.currentMode === 'Floorplan';
|
|
14
69
|
// init container style
|
|
@@ -61,26 +116,12 @@ export class ModelRoomLabelController {
|
|
|
61
116
|
this.render();
|
|
62
117
|
return this;
|
|
63
118
|
}
|
|
64
|
-
/** 监听 Five Mode 变化
|
|
65
|
-
* @description
|
|
66
|
-
* Mode 不符合要求时,立刻消失,满足要求时,需要等待动画结束再展示
|
|
67
|
-
*/
|
|
68
|
-
onFiveModeChange = (mode) => {
|
|
69
|
-
if (mode !== 'Floorplan') {
|
|
70
|
-
this.fiveModeEnabled = false;
|
|
71
|
-
this.render();
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
this.five.once('initAnimationEnded', () => {
|
|
75
|
-
this.fiveModeEnabled = this.five.currentMode === 'Floorplan';
|
|
76
|
-
this.render();
|
|
77
|
-
});
|
|
78
|
-
};
|
|
79
119
|
render() {
|
|
120
|
+
var _a;
|
|
80
121
|
if (!this.wrapper)
|
|
81
122
|
return;
|
|
82
123
|
if (!this.enabled || !this.fiveModeEnabled) {
|
|
83
|
-
this.app
|
|
124
|
+
(_a = this.app) === null || _a === void 0 ? void 0 : _a.$destroy();
|
|
84
125
|
this.app = undefined;
|
|
85
126
|
return;
|
|
86
127
|
}
|
|
@@ -194,12 +194,12 @@ function instance($$self, $$props, $$invalidate) {
|
|
|
194
194
|
// 计算是否可见,如果不可见,不会更新位置
|
|
195
195
|
const visible = getLabelVisible(five, roomLabelItem);
|
|
196
196
|
|
|
197
|
-
if (!visible) return {
|
|
197
|
+
if (!visible) return Object.assign(Object.assign({}, roomLabelItem), { visible });
|
|
198
198
|
|
|
199
199
|
// 更新位置
|
|
200
200
|
const transform = getLabelTransform(five, roomLabelItem);
|
|
201
201
|
|
|
202
|
-
return {
|
|
202
|
+
return Object.assign(Object.assign({}, roomLabelItem), { visible, transform });
|
|
203
203
|
});
|
|
204
204
|
|
|
205
205
|
const sortedRoomLabelItems = newLabels.filter(({ visible }) => visible).map(roomLabelItem => ({
|
|
@@ -209,7 +209,7 @@ function instance($$self, $$props, $$invalidate) {
|
|
|
209
209
|
|
|
210
210
|
return newLabels.map(roomLabelItem => {
|
|
211
211
|
const sortIndex = sortedRoomLabelItems.findIndex(item => item.roomLabelItem.id === roomLabelItem.id);
|
|
212
|
-
if (sortIndex !== undefined) return {
|
|
212
|
+
if (sortIndex !== undefined) return Object.assign(Object.assign({}, roomLabelItem), { zIndex: sortIndex * 10 });
|
|
213
213
|
return roomLabelItem;
|
|
214
214
|
});
|
|
215
215
|
}
|
|
@@ -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,263 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import * as THREE from 'three';
|
|
11
|
+
import { parseModelTVVideoPoints } from "./utils/parseData";
|
|
12
|
+
export const ModelTVVideoPlugin = (five, { videoElement }) => {
|
|
13
|
+
const state = {
|
|
14
|
+
videoMeshes: [],
|
|
15
|
+
videoTextureEnabled: false,
|
|
16
|
+
videoSource: '',
|
|
17
|
+
rectPoints: [],
|
|
18
|
+
enabled: false,
|
|
19
|
+
videoElement: videoElement,
|
|
20
|
+
};
|
|
21
|
+
const setMuted = (muted) => {
|
|
22
|
+
if (state.videoTexture) {
|
|
23
|
+
state.videoTexture.image.muted = muted;
|
|
24
|
+
state.videoTexture.image.play();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const getMuted = () => {
|
|
28
|
+
if (state.videoTexture)
|
|
29
|
+
return state.videoTexture.image.muted;
|
|
30
|
+
else
|
|
31
|
+
return true;
|
|
32
|
+
};
|
|
33
|
+
const enable = () => {
|
|
34
|
+
if (state.enabled)
|
|
35
|
+
return;
|
|
36
|
+
if (!state.videoTexture)
|
|
37
|
+
return;
|
|
38
|
+
state.enabled = true;
|
|
39
|
+
state.videoMeshes = createPanoVideoMeshes();
|
|
40
|
+
console.log('state.videoMeshes', state.videoMeshes);
|
|
41
|
+
state.videoMeshes.forEach((mesh) => five.scene.add(mesh));
|
|
42
|
+
const play = () => {
|
|
43
|
+
console.log('play', state.videoTexture);
|
|
44
|
+
if (!state.videoTexture)
|
|
45
|
+
return;
|
|
46
|
+
const timeupdate = () => {
|
|
47
|
+
var _a;
|
|
48
|
+
if (!state.videoTexture)
|
|
49
|
+
return;
|
|
50
|
+
(_a = state.videoTexture) === null || _a === void 0 ? void 0 : _a.image.removeEventListener('timeupdate', timeupdate);
|
|
51
|
+
state.videoTextureEnabled = true;
|
|
52
|
+
state.videoMeshes.forEach((mesh) => {
|
|
53
|
+
if (mesh.material.map !== state.videoTexture)
|
|
54
|
+
mesh.material.map = state.videoTexture;
|
|
55
|
+
});
|
|
56
|
+
five.needsRender = true;
|
|
57
|
+
};
|
|
58
|
+
state.videoTexture.image.addEventListener('timeupdate', timeupdate);
|
|
59
|
+
if (state.videoTexture && state.videoMeshes.length) {
|
|
60
|
+
state.videoTexture.image.play();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
if (five.model.loaded)
|
|
64
|
+
play();
|
|
65
|
+
else {
|
|
66
|
+
return five.once('modelLoaded', () => play());
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const disable = () => {
|
|
70
|
+
if (!state.enabled)
|
|
71
|
+
return;
|
|
72
|
+
state.enabled = false;
|
|
73
|
+
state.videoMeshes.forEach((mesh) => {
|
|
74
|
+
mesh.geometry.dispose();
|
|
75
|
+
mesh.material.dispose();
|
|
76
|
+
five.scene.remove(mesh);
|
|
77
|
+
if (state.videoTexture)
|
|
78
|
+
state.videoTexture.image.pause();
|
|
79
|
+
});
|
|
80
|
+
state.videoMeshes = [];
|
|
81
|
+
five.needsRender = true;
|
|
82
|
+
};
|
|
83
|
+
const createPanoVideoMeshes = () => {
|
|
84
|
+
return state.rectPoints.map((points, index) => {
|
|
85
|
+
const geometry = new THREE.BufferGeometry();
|
|
86
|
+
const segments = 128;
|
|
87
|
+
const verticesArray = [];
|
|
88
|
+
verticesArray.push(points[0].x, points[0].y, points[0].z);
|
|
89
|
+
for (let i = 1; i < segments; i++) {
|
|
90
|
+
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);
|
|
91
|
+
}
|
|
92
|
+
verticesArray.push(points[1].x, points[1].y, points[1].z);
|
|
93
|
+
verticesArray.push(points[2].x, points[2].y, points[2].z);
|
|
94
|
+
for (let i = 1; i < segments; i++) {
|
|
95
|
+
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);
|
|
96
|
+
}
|
|
97
|
+
verticesArray.push(points[3].x, points[3].y, points[3].z);
|
|
98
|
+
const uvArray = [];
|
|
99
|
+
uvArray.push(0, 1);
|
|
100
|
+
for (let i = 1; i < segments; i++) {
|
|
101
|
+
uvArray.push(0, 1 - i / segments);
|
|
102
|
+
}
|
|
103
|
+
uvArray.push(0, 0);
|
|
104
|
+
uvArray.push(1, 0);
|
|
105
|
+
for (let i = 1; i < segments; i++) {
|
|
106
|
+
uvArray.push(1, i / segments);
|
|
107
|
+
}
|
|
108
|
+
uvArray.push(1, 1);
|
|
109
|
+
const indicesArray = [];
|
|
110
|
+
for (let i = 0; i < segments; i++) {
|
|
111
|
+
indicesArray.push(i, i + 1, segments * 2 - i, i, segments * 2 - i, segments * 2 + 1 - i);
|
|
112
|
+
}
|
|
113
|
+
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(verticesArray), 3));
|
|
114
|
+
geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvArray), 2));
|
|
115
|
+
geometry.setIndex(new THREE.BufferAttribute(new Uint32Array(indicesArray), 1));
|
|
116
|
+
const material = new THREE.MeshBasicMaterial({
|
|
117
|
+
map: state.videoTextureEnabled ? state.videoTexture : state.imageTexture,
|
|
118
|
+
side: THREE.DoubleSide,
|
|
119
|
+
});
|
|
120
|
+
const mesh = new THREE.Mesh(geometry, material);
|
|
121
|
+
mesh.renderOrder = 1;
|
|
122
|
+
mesh.name = `ModelTVVideoPlugin-${index}-${performance.now()}`;
|
|
123
|
+
return mesh;
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
const getImageTexture = (source) => {
|
|
127
|
+
const texture = new THREE.TextureLoader().load(source);
|
|
128
|
+
texture.minFilter = THREE.LinearFilter;
|
|
129
|
+
texture.magFilter = THREE.LinearFilter;
|
|
130
|
+
texture.format = THREE.RGBFormat;
|
|
131
|
+
return texture;
|
|
132
|
+
};
|
|
133
|
+
const getVideoTexture = (source, video) => {
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const xhr = new XMLHttpRequest();
|
|
136
|
+
xhr.onreadystatechange = () => {
|
|
137
|
+
if (xhr.readyState == 4) {
|
|
138
|
+
if (xhr.status == 200) {
|
|
139
|
+
const url = window.URL || window.webkitURL;
|
|
140
|
+
video = video || document.createElement('video');
|
|
141
|
+
video.crossOrigin = 'anonymous';
|
|
142
|
+
video.autoplay = true;
|
|
143
|
+
video.muted = true;
|
|
144
|
+
video.loop = true;
|
|
145
|
+
video.playsInline = true;
|
|
146
|
+
video.src = url.createObjectURL(xhr.response);
|
|
147
|
+
const texture = new THREE.VideoTexture(video);
|
|
148
|
+
texture.minFilter = THREE.LinearFilter;
|
|
149
|
+
texture.magFilter = THREE.LinearFilter;
|
|
150
|
+
texture.format = THREE.RGBFormat;
|
|
151
|
+
resolve(Object.assign(texture, { videoSource: source }));
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
reject(new Error('Video download Error: ' + xhr.status));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
xhr.onerror = (error) => reject(error);
|
|
159
|
+
xhr.open('GET', source);
|
|
160
|
+
xhr.responseType = 'blob';
|
|
161
|
+
xhr.send();
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
const load = (data, videoElement) => __awaiter(void 0, void 0, void 0, function* () {
|
|
165
|
+
const { video_src, video_poster_src, points } = data;
|
|
166
|
+
state.videoSource = video_src;
|
|
167
|
+
// TODO 存疑,先处理多一次遍历 o(2n)
|
|
168
|
+
state.rectPoints = parseModelTVVideoPoints(points)
|
|
169
|
+
.map((items) => items.map(({ x, y, z }) => new THREE.Vector3(x, y, z)));
|
|
170
|
+
state.imageTexture = getImageTexture(video_poster_src);
|
|
171
|
+
if (videoElement) {
|
|
172
|
+
state.videoElement = videoElement;
|
|
173
|
+
}
|
|
174
|
+
state.videoTexture = yield getVideoTexture(state.videoSource, state.videoElement);
|
|
175
|
+
state.enabled = !!data.enable;
|
|
176
|
+
if (state.enabled)
|
|
177
|
+
enable();
|
|
178
|
+
});
|
|
179
|
+
const dispose = () => {
|
|
180
|
+
disable();
|
|
181
|
+
state.videoTexture = undefined;
|
|
182
|
+
five.off('modeChange', () => setMuted(true));
|
|
183
|
+
five.off('wantsTapGesture', (raycaster) => {
|
|
184
|
+
if (!state.enabled)
|
|
185
|
+
return;
|
|
186
|
+
const [intersect] = raycaster.intersectObjects(five.scene.children, true);
|
|
187
|
+
if (!!intersect && /^video/.test(intersect.object.name)) {
|
|
188
|
+
if (state.videoTexture)
|
|
189
|
+
setMuted(!state.videoTexture.image.muted);
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
five.off('panoArrived', () => {
|
|
194
|
+
if (!state.enabled)
|
|
195
|
+
return;
|
|
196
|
+
if (getMuted())
|
|
197
|
+
return;
|
|
198
|
+
const cameraPosition = five.camera.position;
|
|
199
|
+
const visible = state.rectPoints.find((points) => {
|
|
200
|
+
const centerVector = points.reduce((total, curr) => new THREE.Vector3(total.x + curr.x / points.length, total.y + curr.y / points.length, total.z + curr.z / points.length), new THREE.Vector3());
|
|
201
|
+
return (points.map((point) => new THREE.Vector3((point.x + centerVector.x) / 2, (point.y + centerVector.y) / 2, (point.z + centerVector.z) / 2)).filter((vector) => {
|
|
202
|
+
vector = vector.clone().sub(cameraPosition).normalize();
|
|
203
|
+
const raycaster = new THREE.Raycaster(cameraPosition, vector);
|
|
204
|
+
const [intersect] = raycaster.intersectObjects(five.scene.children, true);
|
|
205
|
+
return !!intersect && /^video/.test(intersect.object.name);
|
|
206
|
+
}).length >= 2);
|
|
207
|
+
});
|
|
208
|
+
if (!visible)
|
|
209
|
+
setMuted(true);
|
|
210
|
+
});
|
|
211
|
+
five.off('renderFrame', () => {
|
|
212
|
+
// console.log('renderFrame', state.videoMeshes)
|
|
213
|
+
state.videoMeshes.forEach((meshes) => {
|
|
214
|
+
if (meshes)
|
|
215
|
+
//@ts-ignore
|
|
216
|
+
meshes.needsRender = true;
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
five.on('modeChange', () => setMuted(true));
|
|
221
|
+
five.on('wantsTapGesture', (raycaster) => {
|
|
222
|
+
if (!state.enabled)
|
|
223
|
+
return;
|
|
224
|
+
const targetMesh = five.scene.children.find(item => /^ModelTVVideoPlugin/.test(item.name));
|
|
225
|
+
if (!targetMesh)
|
|
226
|
+
return;
|
|
227
|
+
const intersectObjects = raycaster.intersectObjects([targetMesh]);
|
|
228
|
+
if (intersectObjects.length === 0)
|
|
229
|
+
return;
|
|
230
|
+
if (state.videoTexture)
|
|
231
|
+
setMuted(!state.videoTexture.image.muted); // TODO toggle video play
|
|
232
|
+
return false;
|
|
233
|
+
});
|
|
234
|
+
five.on('panoArrived', () => {
|
|
235
|
+
if (!state.enabled)
|
|
236
|
+
return;
|
|
237
|
+
if (getMuted())
|
|
238
|
+
return;
|
|
239
|
+
const cameraPosition = five.camera.position;
|
|
240
|
+
const visible = state.rectPoints.find((points) => {
|
|
241
|
+
const centerVector = points.reduce((total, curr) => new THREE.Vector3(total.x + curr.x / points.length, total.y + curr.y / points.length, total.z + curr.z / points.length), new THREE.Vector3());
|
|
242
|
+
return (points.map((point) => new THREE.Vector3((point.x + centerVector.x) / 2, (point.y + centerVector.y) / 2, (point.z + centerVector.z) / 2)).filter((vector) => {
|
|
243
|
+
vector = vector.clone().sub(cameraPosition).normalize();
|
|
244
|
+
const raycaster = new THREE.Raycaster(cameraPosition, vector);
|
|
245
|
+
const [intersect] = raycaster.intersectObjects(five.scene.children, true);
|
|
246
|
+
return !!intersect && /^video/.test(intersect.object.name);
|
|
247
|
+
}).length >= 2);
|
|
248
|
+
});
|
|
249
|
+
if (!visible)
|
|
250
|
+
setMuted(true);
|
|
251
|
+
});
|
|
252
|
+
five.on('renderFrame', () => {
|
|
253
|
+
// console.log('renderFrame', state.videoMeshes)
|
|
254
|
+
state.videoMeshes.forEach((meshes) => {
|
|
255
|
+
if (meshes)
|
|
256
|
+
//@ts-ignore
|
|
257
|
+
meshes.needsRender = true;
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
Object.assign(window, { $state: state });
|
|
261
|
+
return { enable, disable, load, dispose };
|
|
262
|
+
};
|
|
263
|
+
export 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,13 @@
|
|
|
1
|
+
import { DIRECTION } from "../typings";
|
|
2
|
+
export function parseModelTVVideoPoints(points) {
|
|
3
|
+
if (points.length === 0)
|
|
4
|
+
return [];
|
|
5
|
+
if (Array.isArray(points[0]))
|
|
6
|
+
return points;
|
|
7
|
+
let newPoints = [];
|
|
8
|
+
points.map(point => {
|
|
9
|
+
const newPoint = [point[DIRECTION.TOP_LEFT], point[DIRECTION.BOTTOM_LEFT], point[DIRECTION.BOTTOM_RIGHT], point[DIRECTION.TOP_RIGHT]];
|
|
10
|
+
newPoints.push(newPoint);
|
|
11
|
+
});
|
|
12
|
+
return newPoints;
|
|
13
|
+
}
|