@realsee/dnalogel 2.0.0-alpha.4 → 2.0.0-alpha.7
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 +14 -0
- package/README.md +44 -5
- package/dist/dnalogel.cjs.js +7 -2
- package/dist/dnalogel.es.js +3668 -184
- package/dist/dnalogel.umd.js +7 -2
- package/dist/style.css +1 -1
- package/libs/CSS3DRenderPlugin/index.js +1 -1
- package/libs/PanoCompassPlugin/Assets/roomInfoIcon.d.ts +1 -0
- package/libs/PanoCompassPlugin/Assets/roomInfoIcon.js +1 -0
- package/libs/PanoCompassPlugin/getRoomInfoInstance.d.ts +8 -0
- package/libs/PanoCompassPlugin/getRoomInfoInstance.js +48 -0
- package/libs/PanoCompassPlugin/index.d.ts +29 -3
- package/libs/PanoCompassPlugin/index.js +126 -44
- package/libs/PanoMeasurePlugin/Controller/BaseController.d.ts +36 -0
- package/libs/PanoMeasurePlugin/Controller/BaseController.js +69 -0
- package/libs/PanoMeasurePlugin/Controller/EditController.d.ts +52 -0
- package/libs/PanoMeasurePlugin/Controller/EditController.js +216 -0
- package/libs/PanoMeasurePlugin/Controller/ShortcutKeyController.d.ts +12 -0
- package/libs/PanoMeasurePlugin/Controller/ShortcutKeyController.js +44 -0
- package/libs/PanoMeasurePlugin/Controller/WatchController.d.ts +25 -0
- package/libs/PanoMeasurePlugin/Controller/WatchController.js +223 -0
- package/libs/PanoMeasurePlugin/Controller/index.d.ts +61 -0
- package/libs/PanoMeasurePlugin/Controller/index.js +176 -0
- package/libs/PanoMeasurePlugin/Model/index.d.ts +38 -0
- package/libs/PanoMeasurePlugin/Model/index.js +114 -0
- package/libs/PanoMeasurePlugin/Model/line.d.ts +30 -0
- package/libs/PanoMeasurePlugin/Model/line.js +64 -0
- package/libs/PanoMeasurePlugin/Model/point.d.ts +16 -0
- package/libs/PanoMeasurePlugin/Model/point.js +28 -0
- package/libs/PanoMeasurePlugin/Model/polyline.d.ts +16 -0
- package/libs/PanoMeasurePlugin/Model/polyline.js +48 -0
- package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete.svg.d.ts +2 -0
- package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete.svg.js +15 -0
- package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_bg.png.d.ts +2 -0
- package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_bg.png.js +2 -0
- package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_hover_bg.png.d.ts +2 -0
- package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_hover_bg.png.js +2 -0
- package/libs/PanoMeasurePlugin/Modules/DeleteDom/index.d.ts +22 -0
- package/libs/PanoMeasurePlugin/Modules/DeleteDom/index.js +108 -0
- package/libs/PanoMeasurePlugin/Modules/FiveHelper.d.ts +11 -0
- package/libs/PanoMeasurePlugin/Modules/FiveHelper.js +33 -0
- package/libs/PanoMeasurePlugin/Modules/GuideController.d.ts +18 -0
- package/libs/PanoMeasurePlugin/Modules/GuideController.js +75 -0
- package/libs/PanoMeasurePlugin/Modules/Magnifier.d.ts +24 -0
- package/libs/PanoMeasurePlugin/Modules/Magnifier.js +103 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/HTML.d.ts +6 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/HTML.js +117 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/MainBtnController.d.ts +18 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/MainBtnController.js +102 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/Revoke/index.d.ts +12 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/Revoke/index.js +35 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/index.d.ts +16 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/index.js +69 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/style.d.ts +17 -0
- package/libs/PanoMeasurePlugin/Modules/UIController/style.js +78 -0
- package/libs/PanoMeasurePlugin/index.d.ts +7 -0
- package/libs/PanoMeasurePlugin/index.js +5 -0
- package/libs/PanoMeasurePlugin/typings/data.d.ts +28 -0
- package/libs/PanoMeasurePlugin/typings/data.js +1 -0
- package/libs/PanoMeasurePlugin/typings/event.type.d.ts +28 -0
- package/libs/PanoMeasurePlugin/typings/event.type.js +1 -0
- package/libs/PanoMeasurePlugin/typings/utils.type.d.ts +1 -0
- package/libs/PanoMeasurePlugin/typings/utils.type.js +1 -0
- package/libs/PanoMeasurePlugin/utils/clearGroup.d.ts +2 -0
- package/libs/PanoMeasurePlugin/utils/clearGroup.js +3 -0
- package/libs/PanoMeasurePlugin/utils/constants.d.ts +4 -0
- package/libs/PanoMeasurePlugin/utils/constants.js +31 -0
- package/libs/PanoMeasurePlugin/utils/distanceDom.d.ts +28 -0
- package/libs/PanoMeasurePlugin/utils/distanceDom.js +114 -0
- package/libs/PanoMeasurePlugin/utils/findAssociatedLines.d.ts +2 -0
- package/libs/PanoMeasurePlugin/utils/findAssociatedLines.js +21 -0
- package/libs/PanoMeasurePlugin/utils/findClosestPoint.d.ts +10 -0
- package/libs/PanoMeasurePlugin/utils/findClosestPoint.js +27 -0
- package/libs/PanoMeasurePlugin/utils/getIntersectionFromEvent.d.ts +4 -0
- package/libs/PanoMeasurePlugin/utils/getIntersectionFromEvent.js +9 -0
- package/libs/PanoMeasurePlugin/utils/getPointFromHammerEvent.d.ts +10 -0
- package/libs/PanoMeasurePlugin/utils/getPointFromHammerEvent.js +14 -0
- package/libs/PanoMeasurePlugin/utils/ironbox.d.ts +1 -0
- package/libs/PanoMeasurePlugin/utils/ironbox.js +1 -0
- package/libs/PanoMeasurePlugin/utils/isNDCPointInScreen.d.ts +2 -0
- package/libs/PanoMeasurePlugin/utils/isNDCPointInScreen.js +6 -0
- package/libs/PanoMeasurePlugin/utils/line.d.ts +17 -0
- package/libs/PanoMeasurePlugin/utils/line.js +32 -0
- package/libs/PanoMeasurePlugin/utils/math.d.ts +17 -0
- package/libs/PanoMeasurePlugin/utils/math.js +44 -0
- package/libs/PanoMeasurePlugin/utils/mouseGroup.d.ts +2 -0
- package/libs/PanoMeasurePlugin/utils/mouseGroup.js +21 -0
- package/libs/PanoMeasurePlugin/utils/ndc2Screen.d.ts +5 -0
- package/libs/PanoMeasurePlugin/utils/ndc2Screen.js +6 -0
- package/libs/PanoRulerPlugin/index.js +1 -0
- package/libs/PanoRulerPlugin/style.d.ts +1 -1
- package/libs/PanoRulerPlugin/style.js +1 -0
- package/libs/floorplan/ModelFloorplanPlugin/Components/Camera.svelte +3 -3
- package/libs/floorplan/ModelFloorplanPlugin/Components/Camera.svelte.map +1 -1
- package/libs/floorplan/ModelFloorplanPlugin/Controller.d.ts +2 -0
- package/libs/floorplan/ModelFloorplanPlugin/Controller.js +3 -1
- package/libs/floorplan/TopviewFloorplanPlugin/Controller.d.ts +2 -0
- package/libs/floorplan/TopviewFloorplanPlugin/Controller.js +4 -3
- package/libs/floorplan/constant.d.ts +5 -0
- package/libs/floorplan/constant.js +6 -0
- package/libs/floorplan/typings/floorplanServerData.d.ts +4 -0
- package/libs/index.d.ts +4 -1
- package/libs/index.js +4 -1
- package/libs/shared-utils/getPxmm.d.ts +6 -1
- package/libs/shared-utils/getPxmm.js +26 -12
- package/package.json +2 -1
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import Hammer from 'hammerjs';
|
|
2
|
+
import { Model } from '../Model';
|
|
3
|
+
import Line from '../Model/line';
|
|
4
|
+
import Point from '../Model/point';
|
|
5
|
+
import throttle from '../../shared-utils/throttle';
|
|
6
|
+
import BaseController from './BaseController';
|
|
7
|
+
import { getIntersectionFromEvent } from '../utils/getIntersectionFromEvent';
|
|
8
|
+
export default class EditController extends BaseController {
|
|
9
|
+
type = 'edit';
|
|
10
|
+
model = new Model({ userDistanceItemCreator: this.userDistanceItemCreator });
|
|
11
|
+
pressPoint;
|
|
12
|
+
hasAppendDashed = false;
|
|
13
|
+
hasAppendMouseGroup = false;
|
|
14
|
+
fiveElement;
|
|
15
|
+
/** 上一个端点位置 */
|
|
16
|
+
lastPoint = null;
|
|
17
|
+
/** 鼠标点到上一个端点连接的虚线 */
|
|
18
|
+
dashed;
|
|
19
|
+
hammer;
|
|
20
|
+
/** 根据 intersection 更新放大镜和吸附点 */
|
|
21
|
+
onIntersectionUpdate = throttle((intersection, mesh) => {
|
|
22
|
+
if (this.hasAppendMouseGroup === false) {
|
|
23
|
+
this.group.add(this.mouseGroup);
|
|
24
|
+
this.magnifier.appendTo(this.container);
|
|
25
|
+
this.hasAppendMouseGroup = true;
|
|
26
|
+
}
|
|
27
|
+
const position = this.updateMouseGroup(intersection, mesh).position;
|
|
28
|
+
this.pressPoint?.position.copy(position);
|
|
29
|
+
this.updateDashed();
|
|
30
|
+
requestAnimationFrame(() => this.magnifier.updateWithPoint(this.mouseGroup.position));
|
|
31
|
+
this.five.needsRender = true;
|
|
32
|
+
}, 20);
|
|
33
|
+
constructor(params) {
|
|
34
|
+
super(params);
|
|
35
|
+
// ==================== 虚线 ====================
|
|
36
|
+
this.dashed = new Line(new Point([0, 0, 0]), new Point([0, 0, 0]), this.model);
|
|
37
|
+
this.dashed.mesh.setMaterial({ dashed: true, dashScale: 100 });
|
|
38
|
+
// ==================== 事件监听 ====================
|
|
39
|
+
// five
|
|
40
|
+
this.five.on('cameraUpdate', this.onCameraUpdate);
|
|
41
|
+
this.five.on('wantsPanGesture', this.onWantsPanGesture);
|
|
42
|
+
this.five.on('wantsTapGesture', this.onWantsTapGesture);
|
|
43
|
+
this.five.on('wantsToMoveToPano', this.onWantsToMoveToPano);
|
|
44
|
+
this.five.on('intersectionOnModelUpdate', this.onIntersectionUpdate);
|
|
45
|
+
// model
|
|
46
|
+
this.model.hook.on('lineAdded', this.onLineChanged);
|
|
47
|
+
this.model.hook.on('lineRemoved', this.onLineChanged);
|
|
48
|
+
// hammer
|
|
49
|
+
const fiveElement = this.five.getElement();
|
|
50
|
+
if (fiveElement) {
|
|
51
|
+
this.fiveElement = fiveElement;
|
|
52
|
+
const hammer = new Hammer(fiveElement);
|
|
53
|
+
this.hammer = hammer;
|
|
54
|
+
hammer.on('tap', this.onTap);
|
|
55
|
+
hammer.on('pan', this.onPan);
|
|
56
|
+
hammer.on('press', this.onPress);
|
|
57
|
+
hammer.on('panend', this.onPanEnd);
|
|
58
|
+
}
|
|
59
|
+
// fiveElement
|
|
60
|
+
this.fiveElement?.addEventListener('mouseleave', this.onMouseLeave);
|
|
61
|
+
// ==================== 其他 ====================
|
|
62
|
+
this.hook.emit('anchorChange', null);
|
|
63
|
+
this.five.refresh();
|
|
64
|
+
}
|
|
65
|
+
dispose() {
|
|
66
|
+
super.dispose();
|
|
67
|
+
this.group.remove(this.mouseGroup, this.dashed.mesh);
|
|
68
|
+
// ==================== 解除事件监听 ====================
|
|
69
|
+
// five
|
|
70
|
+
this.five.off('cameraUpdate', this.onCameraUpdate);
|
|
71
|
+
this.five.off('wantsPanGesture', this.onWantsPanGesture);
|
|
72
|
+
this.five.off('wantsTapGesture', this.onWantsTapGesture);
|
|
73
|
+
this.five.off('wantsToMoveToPano', this.onWantsToMoveToPano);
|
|
74
|
+
this.five.off('intersectionOnModelUpdate', this.onIntersectionUpdate);
|
|
75
|
+
// model
|
|
76
|
+
this.model.hook.off('lineAdded', this.onLineChanged);
|
|
77
|
+
this.model.hook.off('lineRemoved', this.onLineChanged);
|
|
78
|
+
// hammer
|
|
79
|
+
this.hammer?.destroy();
|
|
80
|
+
// fiveElement
|
|
81
|
+
this.fiveElement?.removeEventListener('mouseleave', this.onMouseLeave);
|
|
82
|
+
this.magnifier.dispose();
|
|
83
|
+
this.dashed.distanceItem.remove();
|
|
84
|
+
this.five.needsRender = true;
|
|
85
|
+
}
|
|
86
|
+
getEditingLines() {
|
|
87
|
+
return this.model.lines;
|
|
88
|
+
}
|
|
89
|
+
/** 撤销编辑 */
|
|
90
|
+
revoke = () => {
|
|
91
|
+
// ============ revoke points ============
|
|
92
|
+
// 如果当前没有虚线,只有起始点,需要删除起始点,重置起始状态。并删除虚线实例
|
|
93
|
+
if (this.model.lines.length === 0 && this.lastPoint) {
|
|
94
|
+
this.lastPoint = null;
|
|
95
|
+
this.hasAppendDashed = false;
|
|
96
|
+
this.dashed.distanceItem.remove();
|
|
97
|
+
this.group.remove(this.dashed.mesh);
|
|
98
|
+
this.hook.emit('anchorChange', null);
|
|
99
|
+
this.five.needsRender = true;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (this.model.lines.length === 0 && !this.lastPoint)
|
|
103
|
+
return;
|
|
104
|
+
if (!this.lastPoint)
|
|
105
|
+
return;
|
|
106
|
+
const revokedLine = this.model.lines[this.model.lines.length - 1];
|
|
107
|
+
const lastPoint = revokedLine.findAnotherPoint(this.lastPoint);
|
|
108
|
+
if (!lastPoint)
|
|
109
|
+
return;
|
|
110
|
+
this.lastPoint = lastPoint;
|
|
111
|
+
this.hook.emit('anchorChange', lastPoint.position);
|
|
112
|
+
// ============ revoke lines ============
|
|
113
|
+
this.group.remove(revokedLine.mesh);
|
|
114
|
+
this.model.removeLine(revokedLine);
|
|
115
|
+
// ============ revoke mouse group ============
|
|
116
|
+
this.hasAppendMouseGroup = false;
|
|
117
|
+
this.mouseGroup.position.copy(this.lastPoint.position);
|
|
118
|
+
this.group.remove(this.mouseGroup);
|
|
119
|
+
// ============ revoke lineDistance ============
|
|
120
|
+
revokedLine.distanceItem.remove();
|
|
121
|
+
// ============ revoke dashed ============
|
|
122
|
+
this.updateDashed();
|
|
123
|
+
// ============ revoke magnifier ============
|
|
124
|
+
this.magnifier.dispose();
|
|
125
|
+
this.five.needsRender = true;
|
|
126
|
+
};
|
|
127
|
+
onMouseLeave = () => {
|
|
128
|
+
this.magnifier.dispose();
|
|
129
|
+
this.group.remove(this.mouseGroup);
|
|
130
|
+
this.hasAppendMouseGroup = false;
|
|
131
|
+
if (this.lastPoint) {
|
|
132
|
+
this.mouseGroup.position.copy(this.lastPoint.position);
|
|
133
|
+
this.updateDashed();
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
/** 编辑线条发生改变时通知外部 */
|
|
137
|
+
onLineChanged = () => {
|
|
138
|
+
this.hook.emit('editedLineChange', this.model.lines.map((line) => line.toCompletelyJson()));
|
|
139
|
+
};
|
|
140
|
+
onPress = (e) => {
|
|
141
|
+
const [intersection] = getIntersectionFromEvent(this.five, e);
|
|
142
|
+
if (!intersection || !intersection.face)
|
|
143
|
+
return;
|
|
144
|
+
const nowPoint = new Point(intersection.point);
|
|
145
|
+
this.pressPoint = nowPoint;
|
|
146
|
+
this.onIntersectionUpdate(intersection);
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* 1. 如果之前没有长按行为「即没有长按点时」-> 滑动全景
|
|
150
|
+
* 2. 如果有长按点,把长按点位置更新为当前位置
|
|
151
|
+
*/
|
|
152
|
+
onPan = (e) => {
|
|
153
|
+
if (!this.pressPoint)
|
|
154
|
+
return;
|
|
155
|
+
const [intersection] = getIntersectionFromEvent(this.five, e);
|
|
156
|
+
if (!intersection || !intersection.face)
|
|
157
|
+
return;
|
|
158
|
+
this.onIntersectionUpdate(intersection);
|
|
159
|
+
};
|
|
160
|
+
onPanEnd = (e) => {
|
|
161
|
+
if (!this.pressPoint)
|
|
162
|
+
return;
|
|
163
|
+
this.onTap(e);
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* 1. 如果存在上一个点,需要绘制当前点到上一个点的连线
|
|
167
|
+
* 2. 把上一个点的位置更新为当前点的位置
|
|
168
|
+
* 3. 清除 mouseGroup 和 magnifier
|
|
169
|
+
*/
|
|
170
|
+
onTap = (e) => {
|
|
171
|
+
if (!this.hasAppendDashed) {
|
|
172
|
+
this.dashed.distanceItem.appendTo(this.container);
|
|
173
|
+
this.group.add(this.dashed.mesh);
|
|
174
|
+
}
|
|
175
|
+
this.hasAppendDashed = true;
|
|
176
|
+
const [intersection] = getIntersectionFromEvent(this.five, e);
|
|
177
|
+
this.updateMouseGroup(intersection);
|
|
178
|
+
const nowPoint = new Point(this.mouseGroup.position);
|
|
179
|
+
const lastPoint = this.lastPoint;
|
|
180
|
+
if (nowPoint)
|
|
181
|
+
this.lastPoint = nowPoint;
|
|
182
|
+
if (nowPoint && lastPoint) {
|
|
183
|
+
const line = new Line(lastPoint, nowPoint, this.model);
|
|
184
|
+
line.distanceItem.appendTo(this.container);
|
|
185
|
+
this.model.addLine(line);
|
|
186
|
+
this.group.add(line.mesh);
|
|
187
|
+
line.distanceItem.update(this.five);
|
|
188
|
+
}
|
|
189
|
+
this.pressPoint = undefined;
|
|
190
|
+
this.hasAppendMouseGroup = false;
|
|
191
|
+
this.magnifier.dispose();
|
|
192
|
+
this.group.remove(this.mouseGroup);
|
|
193
|
+
this.updateDashed();
|
|
194
|
+
this.five.needsRender = true;
|
|
195
|
+
this.hook.emit('anchorChange', nowPoint.position);
|
|
196
|
+
};
|
|
197
|
+
onWantsTapGesture = () => false;
|
|
198
|
+
/** 编辑时取消走点 */
|
|
199
|
+
onWantsToMoveToPano = () => false;
|
|
200
|
+
/** 存在长按点时不能移动全景 */
|
|
201
|
+
onWantsPanGesture = () => (this.pressPoint ? false : undefined);
|
|
202
|
+
/** 移动全景时更新 distanceItem 在屏幕上的位置 */
|
|
203
|
+
onCameraUpdate = () => {
|
|
204
|
+
this.updateDistanceUI();
|
|
205
|
+
this.dashed.distanceItem.update(this.five);
|
|
206
|
+
};
|
|
207
|
+
/** 更新虚线 */
|
|
208
|
+
updateDashed = () => {
|
|
209
|
+
if (!this.lastPoint)
|
|
210
|
+
return;
|
|
211
|
+
this.dashed.points[0].position.copy(this.lastPoint.position);
|
|
212
|
+
this.dashed.points[1].position.copy(this.mouseGroup.position);
|
|
213
|
+
this.dashed.mesh.setPoints(this.lastPoint.position, this.mouseGroup.position);
|
|
214
|
+
this.dashed.distanceItem.update(this.five);
|
|
215
|
+
};
|
|
216
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import MeasureController from '.';
|
|
2
|
+
import { Five } from '@realsee/five';
|
|
3
|
+
/** 快捷键控制器 */
|
|
4
|
+
export declare class ShortcutKeyController {
|
|
5
|
+
five: Five;
|
|
6
|
+
measureController: MeasureController;
|
|
7
|
+
constructor(measureController: MeasureController, five: Five);
|
|
8
|
+
dispose(): void;
|
|
9
|
+
private escape;
|
|
10
|
+
private onKeyDown;
|
|
11
|
+
private onMouseDown;
|
|
12
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** 快捷键控制器 */
|
|
2
|
+
export class ShortcutKeyController {
|
|
3
|
+
five;
|
|
4
|
+
measureController;
|
|
5
|
+
constructor(measureController, five) {
|
|
6
|
+
this.five = five;
|
|
7
|
+
this.measureController = measureController;
|
|
8
|
+
const fiveElement = this.five.getElement();
|
|
9
|
+
if (!fiveElement)
|
|
10
|
+
return;
|
|
11
|
+
document.body.addEventListener('keydown', this.onKeyDown);
|
|
12
|
+
fiveElement.addEventListener('mousedown', this.onMouseDown);
|
|
13
|
+
}
|
|
14
|
+
dispose() {
|
|
15
|
+
const fiveElement = this.five.getElement();
|
|
16
|
+
if (!fiveElement)
|
|
17
|
+
return;
|
|
18
|
+
document.body.removeEventListener('keydown', this.onKeyDown);
|
|
19
|
+
fiveElement.removeEventListener('mousedown', this.onMouseDown);
|
|
20
|
+
}
|
|
21
|
+
escape() {
|
|
22
|
+
if (this.measureController.getCurrentMode() === 'Watch')
|
|
23
|
+
return this.measureController.disable();
|
|
24
|
+
return this.measureController.changeMode('Watch');
|
|
25
|
+
}
|
|
26
|
+
onKeyDown = (e) => {
|
|
27
|
+
// Command + S -> 保存 & 更改场景
|
|
28
|
+
if (e.metaKey && e.code === 'KeyS') {
|
|
29
|
+
this.measureController.save().changeMode('Watch');
|
|
30
|
+
e.preventDefault();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Escape -> 切换到观察模式 / 如果已经在观察模式,退出功能
|
|
34
|
+
if (e.code === 'Escape')
|
|
35
|
+
return this.escape();
|
|
36
|
+
};
|
|
37
|
+
onMouseDown = (e) => {
|
|
38
|
+
// 鼠标右键取消
|
|
39
|
+
if (e.button !== 2)
|
|
40
|
+
return;
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
this.escape();
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import Line from '../Model/line';
|
|
2
|
+
import BaseController, { IControllerParams } from './BaseController';
|
|
3
|
+
export default class WatchController extends BaseController {
|
|
4
|
+
type: string;
|
|
5
|
+
private deleteDom;
|
|
6
|
+
private highlightedLines;
|
|
7
|
+
private fiveElement?;
|
|
8
|
+
private editPointState?;
|
|
9
|
+
private hammer?;
|
|
10
|
+
constructor(params: IControllerParams);
|
|
11
|
+
dispose(): void;
|
|
12
|
+
highlightLine(line: Line): void;
|
|
13
|
+
clearHighlightLines(): void;
|
|
14
|
+
private onPanStart;
|
|
15
|
+
private onPanEnd;
|
|
16
|
+
private onPan;
|
|
17
|
+
private onIntersectionUpdate;
|
|
18
|
+
private wantsPanGesture;
|
|
19
|
+
private wantsTapGesture;
|
|
20
|
+
private chooseLine;
|
|
21
|
+
private highlightLines;
|
|
22
|
+
private lineRemoved;
|
|
23
|
+
private onCameraUpdate;
|
|
24
|
+
private deleteDomClickCallback;
|
|
25
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import Hammer from 'hammerjs';
|
|
2
|
+
import DeleteDom from '../Modules/DeleteDom';
|
|
3
|
+
import isNDCPointInScreen from '../utils/isNDCPointInScreen';
|
|
4
|
+
import BaseController from './BaseController';
|
|
5
|
+
import { Raycaster, Vector2 } from 'three';
|
|
6
|
+
import { closestPointOnLine } from '../utils/math';
|
|
7
|
+
import { findClosestPoint } from '../utils/findClosestPoint';
|
|
8
|
+
import { findAssociatedLines } from '../utils/findAssociatedLines';
|
|
9
|
+
import { getPointFromHammerEvent } from '../utils/getPointFromHammerEvent';
|
|
10
|
+
export default class WatchController extends BaseController {
|
|
11
|
+
type = 'watch';
|
|
12
|
+
deleteDom;
|
|
13
|
+
highlightedLines = [];
|
|
14
|
+
fiveElement;
|
|
15
|
+
editPointState;
|
|
16
|
+
hammer;
|
|
17
|
+
constructor(params) {
|
|
18
|
+
super(params);
|
|
19
|
+
this.deleteDom = new DeleteDom(this.five, { onClick: this.deleteDomClickCallback }).appendTo(this.container);
|
|
20
|
+
this.model.lines.forEach((line) => {
|
|
21
|
+
line.distanceItem.appendTo(this.container);
|
|
22
|
+
line.distanceItem.update(this.five);
|
|
23
|
+
line.hook.on('selected', this.chooseLine);
|
|
24
|
+
this.group.add(line.mesh);
|
|
25
|
+
});
|
|
26
|
+
const fiveElement = this.five.getElement();
|
|
27
|
+
if (fiveElement) {
|
|
28
|
+
this.fiveElement = fiveElement;
|
|
29
|
+
const hammer = new Hammer(fiveElement);
|
|
30
|
+
this.hammer = hammer;
|
|
31
|
+
hammer.on('pan', this.onPan);
|
|
32
|
+
hammer.on('panstart', this.onPanStart);
|
|
33
|
+
hammer.on('panend', this.onPanEnd);
|
|
34
|
+
}
|
|
35
|
+
this.model.hook.on('lineRemoved', this.lineRemoved);
|
|
36
|
+
this.five.on('cameraUpdate', this.onCameraUpdate);
|
|
37
|
+
this.five.on('wantsTapGesture', this.wantsTapGesture);
|
|
38
|
+
this.five.on('wantsPanGesture', this.wantsPanGesture);
|
|
39
|
+
this.five.needsRender = true;
|
|
40
|
+
}
|
|
41
|
+
dispose() {
|
|
42
|
+
super.dispose();
|
|
43
|
+
this.deleteDom.dispose();
|
|
44
|
+
this.model.hook.off('lineRemoved', this.lineRemoved);
|
|
45
|
+
this.five.off('cameraUpdate', this.onCameraUpdate);
|
|
46
|
+
this.five.off('wantsPanGesture', this.wantsPanGesture);
|
|
47
|
+
this.five.off('wantsTapGesture', this.wantsTapGesture);
|
|
48
|
+
this.five.needsRender = true;
|
|
49
|
+
this.hook.emit('selectedChange', []);
|
|
50
|
+
this.hammer?.destroy();
|
|
51
|
+
}
|
|
52
|
+
highlightLine(line) {
|
|
53
|
+
if (line.selected)
|
|
54
|
+
return;
|
|
55
|
+
line.selected = true;
|
|
56
|
+
this.group.add(line.lightMesh);
|
|
57
|
+
line.distanceItem.highlight();
|
|
58
|
+
this.five.needsRender = true;
|
|
59
|
+
}
|
|
60
|
+
clearHighlightLines() {
|
|
61
|
+
if (this.group.children.length === 0)
|
|
62
|
+
return;
|
|
63
|
+
this.deleteDom.setLines([]).hide();
|
|
64
|
+
this.model.lines.forEach((line) => {
|
|
65
|
+
line.selected = false;
|
|
66
|
+
line.distanceItem.unHighlight();
|
|
67
|
+
this.group.remove(line.lightMesh);
|
|
68
|
+
});
|
|
69
|
+
this.highlightedLines = [];
|
|
70
|
+
this.five.needsRender = true;
|
|
71
|
+
}
|
|
72
|
+
onPanStart = (e) => {
|
|
73
|
+
if (this.model.points.length === 0 || !this.fiveElement)
|
|
74
|
+
return;
|
|
75
|
+
const mouse = getPointFromHammerEvent(e).point;
|
|
76
|
+
const closestPoint = findClosestPoint(this.five, this.model.points, mouse, 20)?.point;
|
|
77
|
+
if (!closestPoint) {
|
|
78
|
+
this.editPointState = undefined;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const editPointState = {
|
|
82
|
+
point: closestPoint,
|
|
83
|
+
associatedLines: findAssociatedLines(closestPoint.lines[0]),
|
|
84
|
+
};
|
|
85
|
+
const cancelDragLine = this.hook.emit('wantsDragLine', {
|
|
86
|
+
point: closestPoint.id,
|
|
87
|
+
lines: editPointState.associatedLines.map(({ id }) => id),
|
|
88
|
+
});
|
|
89
|
+
if (cancelDragLine)
|
|
90
|
+
return;
|
|
91
|
+
this.editPointState = editPointState;
|
|
92
|
+
this.magnifier.appendTo(this.container);
|
|
93
|
+
this.group.add(this.mouseGroup);
|
|
94
|
+
};
|
|
95
|
+
onPanEnd = () => {
|
|
96
|
+
if (!this.editPointState)
|
|
97
|
+
return;
|
|
98
|
+
// 把拖动的线从虚线转换为实线
|
|
99
|
+
this.editPointState.point.lines.forEach((line) => line.mesh.setMaterial({ dashed: false }));
|
|
100
|
+
// 还原选中态
|
|
101
|
+
this.highlightLines(this.editPointState.associatedLines);
|
|
102
|
+
this.editPointState = undefined;
|
|
103
|
+
this.magnifier.dispose();
|
|
104
|
+
this.group.remove(this.mouseGroup);
|
|
105
|
+
};
|
|
106
|
+
onPan = (e) => {
|
|
107
|
+
if (!this.editPointState || !this.fiveElement)
|
|
108
|
+
return;
|
|
109
|
+
const mouse = getPointFromHammerEvent(e).ndcPoint;
|
|
110
|
+
const raycaster = new Raycaster();
|
|
111
|
+
raycaster.setFromCamera(mouse, this.five.camera);
|
|
112
|
+
const [intersection] = this.five.model.intersectRaycaster(raycaster);
|
|
113
|
+
if (!intersection)
|
|
114
|
+
return;
|
|
115
|
+
this.onIntersectionUpdate(intersection);
|
|
116
|
+
};
|
|
117
|
+
onIntersectionUpdate = (intersection, mesh) => {
|
|
118
|
+
if (!this.editPointState)
|
|
119
|
+
return;
|
|
120
|
+
// 拖动过程中清除选中态
|
|
121
|
+
this.clearHighlightLines();
|
|
122
|
+
// 把拖动点相关的线变成虚线 & 改变相关线的位置
|
|
123
|
+
this.editPointState.point.position.copy(intersection.point);
|
|
124
|
+
this.editPointState.point.lines.forEach((line) => {
|
|
125
|
+
line.mesh.setPoints(line.points[0].position.clone(), line.points[1].position.clone());
|
|
126
|
+
line.lightMesh.setPoints(line.points[0].position.clone(), line.points[1].position.clone());
|
|
127
|
+
line.mesh.setMaterial({ dashed: true });
|
|
128
|
+
});
|
|
129
|
+
this.updateDistanceUI();
|
|
130
|
+
this.magnifier.updateWithPoint(intersection.point);
|
|
131
|
+
this.mouseGroup.position.copy(intersection.point);
|
|
132
|
+
if (mesh) {
|
|
133
|
+
this.mouseGroup.quaternion.copy(mesh.quaternion);
|
|
134
|
+
}
|
|
135
|
+
else if (intersection.face) {
|
|
136
|
+
const face = intersection.face.normal;
|
|
137
|
+
const positionVector = face.clone().multiplyScalar(0.05);
|
|
138
|
+
const position = intersection.point.clone().add(positionVector);
|
|
139
|
+
const lookAtVector = position.clone().add(positionVector);
|
|
140
|
+
this.mouseGroup.lookAt(lookAtVector);
|
|
141
|
+
}
|
|
142
|
+
this.five.needsRender = true;
|
|
143
|
+
this.hook.emit('selectedChange', this.editPointState.associatedLines.map((line) => line.toCompletelyJson()));
|
|
144
|
+
};
|
|
145
|
+
wantsPanGesture = () => {
|
|
146
|
+
if (this.editPointState)
|
|
147
|
+
return false;
|
|
148
|
+
};
|
|
149
|
+
wantsTapGesture = (raycaster) => {
|
|
150
|
+
const [target] = this.five.model.intersectRaycaster(raycaster);
|
|
151
|
+
if (!target)
|
|
152
|
+
return;
|
|
153
|
+
const camera = this.five.camera;
|
|
154
|
+
const ndcTarget = target.point.clone().project(camera);
|
|
155
|
+
const screenWidth = this.container.clientWidth;
|
|
156
|
+
const screenHeight = this.container.clientHeight;
|
|
157
|
+
const targetScreenPosition = new Vector2(ndcTarget.x * screenWidth, ndcTarget.y * screenHeight);
|
|
158
|
+
// 把线的端点全部映射到屏幕上,过滤掉不在视野内的线,同时乘以屏幕宽 & 高
|
|
159
|
+
const screenLines = this.model.lines
|
|
160
|
+
.map((line) => {
|
|
161
|
+
const [startPoint, endPoint] = line.points;
|
|
162
|
+
const ndcStartPoint = startPoint.position.clone().project(camera);
|
|
163
|
+
const ndcEndPoint = endPoint.position.clone().project(camera);
|
|
164
|
+
if (!isNDCPointInScreen(ndcStartPoint) && !isNDCPointInScreen(ndcEndPoint))
|
|
165
|
+
return null;
|
|
166
|
+
const startScreenPosition = new Vector2(ndcStartPoint.x * screenWidth, ndcStartPoint.y * screenHeight);
|
|
167
|
+
const endScreenPosition = new Vector2(ndcEndPoint.x * screenWidth, ndcEndPoint.y * screenHeight);
|
|
168
|
+
return { id: line.id, points: [startScreenPosition, endScreenPosition] };
|
|
169
|
+
})
|
|
170
|
+
.filter((line) => !!line);
|
|
171
|
+
if (screenLines.length === 0)
|
|
172
|
+
return;
|
|
173
|
+
// 找这些线距离鼠标点击位置最近的线
|
|
174
|
+
const distanceLines = screenLines
|
|
175
|
+
.map((line) => {
|
|
176
|
+
const closestPoint = closestPointOnLine(targetScreenPosition, line.points);
|
|
177
|
+
return { id: line.id, distance: closestPoint.distanceTo(targetScreenPosition) };
|
|
178
|
+
})
|
|
179
|
+
.sort((a, b) => a.distance - b.distance);
|
|
180
|
+
const closestScreenLine = distanceLines[0];
|
|
181
|
+
if (closestScreenLine.distance > 20)
|
|
182
|
+
return;
|
|
183
|
+
const closestLine = this.model.lines.find(({ id }) => id === closestScreenLine.id);
|
|
184
|
+
if (!closestLine)
|
|
185
|
+
return;
|
|
186
|
+
this.chooseLine(closestLine);
|
|
187
|
+
return false;
|
|
188
|
+
};
|
|
189
|
+
chooseLine = (line) => {
|
|
190
|
+
const highlightLines = findAssociatedLines(line);
|
|
191
|
+
this.highlightLines(highlightLines);
|
|
192
|
+
this.five.needsRender = true;
|
|
193
|
+
this.hook.emit('selectedChange', highlightLines.map((line) => line.toCompletelyJson()));
|
|
194
|
+
};
|
|
195
|
+
highlightLines(lines) {
|
|
196
|
+
this.clearHighlightLines();
|
|
197
|
+
this.highlightedLines = lines;
|
|
198
|
+
this.deleteDom.setLines(lines).updatePosition().show();
|
|
199
|
+
lines.forEach((line) => this.highlightLine(line));
|
|
200
|
+
}
|
|
201
|
+
lineRemoved = (line) => {
|
|
202
|
+
this.removeLine(line);
|
|
203
|
+
// TODO: 这个逻辑不太好,改进一下
|
|
204
|
+
this.hook.emit('selectedChange', this.model.lines.filter((line) => line.selected).map((line) => line.toCompletelyJson()));
|
|
205
|
+
};
|
|
206
|
+
onCameraUpdate = () => {
|
|
207
|
+
this.updateDistanceUI();
|
|
208
|
+
this.highlightedLines.length > 0 && this.deleteDom.updatePosition();
|
|
209
|
+
};
|
|
210
|
+
deleteDomClickCallback = () => {
|
|
211
|
+
const firstLine = this.highlightedLines[0];
|
|
212
|
+
// TODO: 优化折线的删除逻辑
|
|
213
|
+
firstLine
|
|
214
|
+
.getPolyline()
|
|
215
|
+
.lines.slice()
|
|
216
|
+
.reverse()
|
|
217
|
+
.forEach((line) => this.model.removeLine(line));
|
|
218
|
+
this.highlightedLines = [];
|
|
219
|
+
// this.clearHighlightLines()
|
|
220
|
+
// this.highlightedLines.forEach((line) => this.model.removeLine(line))
|
|
221
|
+
this.deleteDom.setLines([]).hide();
|
|
222
|
+
};
|
|
223
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { PluginData } from '../typings/data';
|
|
2
|
+
import { Five, Subscribe } from '@realsee/five';
|
|
3
|
+
import { PluginEvent } from '../typings/event.type';
|
|
4
|
+
import { UserDistanceItem } from '../utils/distanceDom';
|
|
5
|
+
export declare type Mode = 'Watch' | 'Edit';
|
|
6
|
+
export interface MeasurePluginParameter {
|
|
7
|
+
useUIController?: boolean;
|
|
8
|
+
useGuideController?: boolean;
|
|
9
|
+
userDistanceItemCreator?: () => UserDistanceItem;
|
|
10
|
+
}
|
|
11
|
+
export default class MeasureController {
|
|
12
|
+
hasOpen: boolean;
|
|
13
|
+
hook: Subscribe<PluginEvent>;
|
|
14
|
+
private five;
|
|
15
|
+
private model;
|
|
16
|
+
private group;
|
|
17
|
+
private magnifier;
|
|
18
|
+
private fiveHelper;
|
|
19
|
+
private useUIController?;
|
|
20
|
+
private params;
|
|
21
|
+
private useGuideController?;
|
|
22
|
+
private container;
|
|
23
|
+
private shortcutKeyController?;
|
|
24
|
+
private controller;
|
|
25
|
+
private controllerParams;
|
|
26
|
+
constructor(five: Five, params: MeasurePluginParameter);
|
|
27
|
+
appendTo(parent: HTMLElement): void;
|
|
28
|
+
dispose(): void;
|
|
29
|
+
/** 加载数据
|
|
30
|
+
* @description 数据加载时会覆盖当前已保存的数据
|
|
31
|
+
* @description 如果当前正在编辑中,会自动退出并保存编辑
|
|
32
|
+
*/
|
|
33
|
+
load(data: PluginData): void;
|
|
34
|
+
/** 插件功能入口
|
|
35
|
+
* @description 会隐藏鼠标的默认聚焦环
|
|
36
|
+
* @description 会隐藏当前 VR 内的点位展示
|
|
37
|
+
*/
|
|
38
|
+
enable(): void;
|
|
39
|
+
/** 关闭插件功能
|
|
40
|
+
* @description 清除标尺线条
|
|
41
|
+
* @description 还原点位展示和默认鼠标 UI
|
|
42
|
+
*/
|
|
43
|
+
disable(): void;
|
|
44
|
+
getCurrentMode: () => Mode | null;
|
|
45
|
+
/** 变更场景
|
|
46
|
+
* @description 如果从编辑场景改变到观看场景,不会自动保存,默认丢弃所有改动
|
|
47
|
+
*/
|
|
48
|
+
changeMode: (mode: Mode) => void;
|
|
49
|
+
/** 撤销编辑 */
|
|
50
|
+
revoke(): void;
|
|
51
|
+
removeLineByID(lineID: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* 高亮当前线段
|
|
54
|
+
*/
|
|
55
|
+
highlightLine(lineID: string): boolean;
|
|
56
|
+
clearHighlightLines(): boolean;
|
|
57
|
+
/** 保存编辑 */
|
|
58
|
+
save(): this;
|
|
59
|
+
/** 把当前以保存的数据转换成 JSON 对象 */
|
|
60
|
+
toJson(): PluginData;
|
|
61
|
+
}
|