fl-web-component 2.0.16 → 2.0.18
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/README.md +6 -0
- package/dist/fl-web-component.common.js +1044 -214
- package/dist/fl-web-component.common.js.map +1 -1
- package/dist/fl-web-component.css +1 -1
- package/package.json +1 -1
- package/packages/components/com-graphics/index.vue +73 -11
- package/src/utils/threejs/measure-angle.js +172 -41
- package/src/utils/threejs/measure-area.js +144 -46
- package/src/utils/threejs/measure-clear-distance.js +346 -0
- package/src/utils/threejs/measure-distance.js +135 -18
- package/src/utils/threejs/measure-height.js +59 -15
|
@@ -2,10 +2,11 @@ import * as THREE from 'three';
|
|
|
2
2
|
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
|
|
3
3
|
import { Message } from 'element-ui';
|
|
4
4
|
var _this = null;
|
|
5
|
-
var MeasureDistance = function (renderer, scene, camera, width, height) {
|
|
5
|
+
var MeasureDistance = function (renderer, scene, camera, width, height, options = {}) {
|
|
6
6
|
this.renderer = renderer;
|
|
7
7
|
this.scene = scene;
|
|
8
8
|
this.camera = camera;
|
|
9
|
+
this.pickRoots = options.pickRoots || null;
|
|
9
10
|
this.pointArray = []; // 保存当前操作所添加的点
|
|
10
11
|
this.raycaster = new THREE.Raycaster();
|
|
11
12
|
this.points = []; // 保存页面中所添加的点
|
|
@@ -16,11 +17,12 @@ var MeasureDistance = function (renderer, scene, camera, width, height) {
|
|
|
16
17
|
this.tempLabel = undefined;
|
|
17
18
|
this.tipsLabel = undefined;
|
|
18
19
|
this.isCompleted = false;
|
|
20
|
+
this.hasTempPoint = false;
|
|
19
21
|
this.timer = null;
|
|
20
22
|
this.width = width;
|
|
21
23
|
this.height = height;
|
|
22
24
|
this.firstTime = 0;
|
|
23
|
-
this.measureName = 'measureObj'
|
|
25
|
+
this.measureName = 'measureObj';
|
|
24
26
|
// 创建一个辅助平面来捕获鼠标事件
|
|
25
27
|
this.plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
|
|
26
28
|
};
|
|
@@ -41,7 +43,78 @@ MeasureDistance.prototype = {
|
|
|
41
43
|
this.width = width;
|
|
42
44
|
this.height = height;
|
|
43
45
|
},
|
|
44
|
-
|
|
46
|
+
getPickRoots() {
|
|
47
|
+
const roots = typeof _this.pickRoots === 'function' ? _this.pickRoots() : _this.pickRoots;
|
|
48
|
+
if (Array.isArray(roots) && roots.length > 0) {
|
|
49
|
+
return roots.filter(Boolean);
|
|
50
|
+
}
|
|
51
|
+
if (roots) {
|
|
52
|
+
return [roots];
|
|
53
|
+
}
|
|
54
|
+
return _this.scene && _this.scene.children ? _this.scene.children : [];
|
|
55
|
+
},
|
|
56
|
+
isExcludedIntersection(object) {
|
|
57
|
+
let current = object;
|
|
58
|
+
while (current) {
|
|
59
|
+
const userData = current.userData || {};
|
|
60
|
+
if (current.visible === false) return true;
|
|
61
|
+
if (current.name === _this.measureName || userData.isMeasureObject === true) return true;
|
|
62
|
+
if (userData.transformControlHelper === true || userData.outlineProxy === true) return true;
|
|
63
|
+
if (current.isCamera || current.isLight) return true;
|
|
64
|
+
if (
|
|
65
|
+
typeof current.type === 'string' &&
|
|
66
|
+
(/Helper$/i.test(current.type) ||
|
|
67
|
+
current.type === 'CSS2DObject' ||
|
|
68
|
+
current.type === 'TransformControlsRoot')
|
|
69
|
+
) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
current = current.parent;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
},
|
|
76
|
+
markMeasureObject(object) {
|
|
77
|
+
object.name = this.measureName;
|
|
78
|
+
if (!object.userData) {
|
|
79
|
+
object.userData = {};
|
|
80
|
+
}
|
|
81
|
+
object.userData.isMeasureObject = true;
|
|
82
|
+
return object;
|
|
83
|
+
},
|
|
84
|
+
disposeObject(object) {
|
|
85
|
+
if (!object) return;
|
|
86
|
+
if (object.geometry) {
|
|
87
|
+
object.geometry.dispose();
|
|
88
|
+
}
|
|
89
|
+
if (object.material) {
|
|
90
|
+
object.material.dispose();
|
|
91
|
+
}
|
|
92
|
+
this.scene.remove(object);
|
|
93
|
+
},
|
|
94
|
+
removeArrayItem(array, item) {
|
|
95
|
+
if (!item) return;
|
|
96
|
+
const index = array.indexOf(item);
|
|
97
|
+
if (index !== -1) {
|
|
98
|
+
array.splice(index, 1);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
clearTempMeasure() {
|
|
102
|
+
// 清理未确认的预览点,避免空点位残留在回退平面上。
|
|
103
|
+
if (this.hasTempPoint && this.pointArray.length > 0) {
|
|
104
|
+
this.pointArray.pop();
|
|
105
|
+
}
|
|
106
|
+
this.removeArrayItem(this.points, this.tempPoints);
|
|
107
|
+
this.removeArrayItem(this.polyline, this.tempLine);
|
|
108
|
+
this.removeArrayItem(this.labels, this.tempLabel);
|
|
109
|
+
this.disposeObject(this.tempPoints);
|
|
110
|
+
this.disposeObject(this.tempLine);
|
|
111
|
+
this.disposeObject(this.tempLabel);
|
|
112
|
+
this.tempPoints = undefined;
|
|
113
|
+
this.tempLine = undefined;
|
|
114
|
+
this.tempLabel = undefined;
|
|
115
|
+
this.hasTempPoint = false;
|
|
116
|
+
},
|
|
117
|
+
getPosition(e, options = {}) {
|
|
45
118
|
const mouse = new THREE.Vector2();
|
|
46
119
|
const elRect = this.renderer.domElement.getBoundingClientRect();
|
|
47
120
|
const canvasX = e.clientX - elRect.left;
|
|
@@ -51,11 +124,17 @@ MeasureDistance.prototype = {
|
|
|
51
124
|
mouse.y = -(canvasY / elRect.height) * 2.0 + 1.0;
|
|
52
125
|
|
|
53
126
|
_this.raycaster.setFromCamera(mouse, this.camera);
|
|
54
|
-
let intersects = _this.raycaster
|
|
127
|
+
let intersects = _this.raycaster
|
|
128
|
+
.intersectObjects(_this.getPickRoots(), true)
|
|
129
|
+
.filter(item => item && item.object && !_this.isExcludedIntersection(item.object));
|
|
55
130
|
if (intersects.length > 0) {
|
|
56
131
|
return { point: intersects[0].point, isModel: true };
|
|
57
132
|
}
|
|
58
133
|
|
|
134
|
+
if (options.allowPlaneFallback === false) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
59
138
|
// 如果没有交点,构建一个基于最后一个确认点且面向相机的平面
|
|
60
139
|
if (_this.pointArray && _this.pointArray.length > 0) {
|
|
61
140
|
const lastPoint =
|
|
@@ -91,7 +170,7 @@ MeasureDistance.prototype = {
|
|
|
91
170
|
});
|
|
92
171
|
const lineGeometry = new THREE.BufferGeometry().setFromPoints([p1, p2]);
|
|
93
172
|
const line = new THREE.Line(lineGeometry, lineMaterial);
|
|
94
|
-
|
|
173
|
+
this.markMeasureObject(line);
|
|
95
174
|
line.renderOrder = 999;
|
|
96
175
|
line.frustumCulled = false;
|
|
97
176
|
return line;
|
|
@@ -101,7 +180,7 @@ MeasureDistance.prototype = {
|
|
|
101
180
|
div.className = name;
|
|
102
181
|
div.textContent = text;
|
|
103
182
|
const divLabel = new CSS2DObject(div);
|
|
104
|
-
|
|
183
|
+
this.markMeasureObject(divLabel);
|
|
105
184
|
divLabel.position.set(position.x, position.y, position.z);
|
|
106
185
|
return divLabel;
|
|
107
186
|
},
|
|
@@ -110,9 +189,12 @@ MeasureDistance.prototype = {
|
|
|
110
189
|
const positionResult = _this.getPosition(e);
|
|
111
190
|
if (positionResult) {
|
|
112
191
|
const point = positionResult.point;
|
|
113
|
-
_this.
|
|
114
|
-
|
|
115
|
-
|
|
192
|
+
if (_this.hasTempPoint) {
|
|
193
|
+
_this.pointArray.splice(_this.pointArray.length - 1, 1, point);
|
|
194
|
+
} else {
|
|
195
|
+
_this.pointArray.push(point);
|
|
196
|
+
_this.hasTempPoint = true;
|
|
197
|
+
}
|
|
116
198
|
const length = _this.pointArray.length;
|
|
117
199
|
if (_this.tempPoints) {
|
|
118
200
|
_this.tempPoints.position.set(point.x, point.y, point.z);
|
|
@@ -149,7 +231,7 @@ MeasureDistance.prototype = {
|
|
|
149
231
|
div.className = 'tips-label';
|
|
150
232
|
div.textContent = label;
|
|
151
233
|
const tipsLabel = new CSS2DObject(div);
|
|
152
|
-
|
|
234
|
+
this.markMeasureObject(tipsLabel);
|
|
153
235
|
tipsLabel.position.set(position.x + 0.1, position.y, position.z + 0.05);
|
|
154
236
|
return tipsLabel;
|
|
155
237
|
},
|
|
@@ -157,7 +239,6 @@ MeasureDistance.prototype = {
|
|
|
157
239
|
this.firstTime = new Date().getTime();
|
|
158
240
|
},
|
|
159
241
|
click(e) {
|
|
160
|
-
console.log(_this.points)
|
|
161
242
|
let lastTime = new Date().getTime();
|
|
162
243
|
if (lastTime - this.firstTime < 300) {
|
|
163
244
|
if (_this.isCompleted) {
|
|
@@ -166,14 +247,20 @@ MeasureDistance.prototype = {
|
|
|
166
247
|
clearTimeout(_this.timer);
|
|
167
248
|
_this.timer = setTimeout(() => {
|
|
168
249
|
_this.isCompleted = false;
|
|
169
|
-
const positionResult = _this.getPosition(e);
|
|
250
|
+
const positionResult = _this.getPosition(e, { allowPlaneFallback: false });
|
|
251
|
+
if (!positionResult || !positionResult.isModel) {
|
|
252
|
+
_this.clearTempMeasure();
|
|
253
|
+
Message.warning('请点击模型进行测量');
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
170
256
|
if (positionResult) {
|
|
171
|
-
const { point
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
257
|
+
const { point } = positionResult;
|
|
258
|
+
if (_this.hasTempPoint && _this.pointArray.length > 0) {
|
|
259
|
+
_this.pointArray.splice(_this.pointArray.length - 1, 1, point);
|
|
260
|
+
} else {
|
|
261
|
+
_this.pointArray.push(point);
|
|
176
262
|
}
|
|
263
|
+
_this.hasTempPoint = false;
|
|
177
264
|
if (_this.tipsLabel) {
|
|
178
265
|
_this.tipsLabel.position.set(point.x + 0.1, point.y, point.z + 0.05);
|
|
179
266
|
} else {
|
|
@@ -188,9 +275,35 @@ MeasureDistance.prototype = {
|
|
|
188
275
|
_this.points.push(geom);
|
|
189
276
|
_this.scene.add(geom);
|
|
190
277
|
}
|
|
278
|
+
const length = _this.pointArray.length;
|
|
279
|
+
if (length > 1) {
|
|
280
|
+
const p1 = _this.pointArray[length - 2];
|
|
281
|
+
const p2 = _this.pointArray[length - 1];
|
|
282
|
+
const dist = p1.distanceTo(p2);
|
|
283
|
+
const label = `${_this.numberToString(dist)}`;
|
|
284
|
+
const position = new THREE.Vector3(
|
|
285
|
+
(p1.x + p2.x) / 2,
|
|
286
|
+
(p1.y + p2.y) / 2,
|
|
287
|
+
(p1.z + p2.z) / 2
|
|
288
|
+
);
|
|
289
|
+
if (_this.tempLine) {
|
|
290
|
+
_this.tempLine.geometry.setFromPoints([p1, p2]);
|
|
291
|
+
} else {
|
|
292
|
+
_this.tempLine = _this.createLine(p1, p2);
|
|
293
|
+
_this.polyline.push(_this.tempLine);
|
|
294
|
+
_this.scene.add(_this.tempLine);
|
|
295
|
+
}
|
|
296
|
+
if (_this.tempLabel) {
|
|
297
|
+
_this.tempLabel.element.textContent = label;
|
|
298
|
+
_this.tempLabel.position.set(position.x, position.y, position.z);
|
|
299
|
+
} else {
|
|
300
|
+
_this.tempLabel = _this.createLabel('measure-label', label, position);
|
|
301
|
+
_this.labels.push(_this.tempLabel);
|
|
302
|
+
_this.scene.add(_this.tempLabel);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
191
305
|
_this.tempLine = undefined;
|
|
192
306
|
_this.tempLabel = undefined;
|
|
193
|
-
_this.pointArray.push(point);
|
|
194
307
|
}
|
|
195
308
|
});
|
|
196
309
|
}
|
|
@@ -204,11 +317,13 @@ MeasureDistance.prototype = {
|
|
|
204
317
|
clearTimeout(_this.timer);
|
|
205
318
|
const positionResult = _this.getPosition(e);
|
|
206
319
|
if (positionResult) {
|
|
320
|
+
_this.clearTempMeasure();
|
|
207
321
|
_this.isCompleted = true;
|
|
208
322
|
_this.tempPoints = undefined;
|
|
209
323
|
_this.tempLine = undefined;
|
|
210
324
|
_this.tempLabel = undefined;
|
|
211
325
|
_this.pointArray.splice(0);
|
|
326
|
+
_this.hasTempPoint = false;
|
|
212
327
|
_this.renderer.domElement.removeEventListener('mousemove', _this.mousemove);
|
|
213
328
|
}
|
|
214
329
|
},
|
|
@@ -228,6 +343,7 @@ MeasureDistance.prototype = {
|
|
|
228
343
|
this.tempPoints = undefined;
|
|
229
344
|
this.tempLabel = undefined;
|
|
230
345
|
this.tempLine = undefined;
|
|
346
|
+
this.hasTempPoint = false;
|
|
231
347
|
this.scene.remove(this.tipsLabel);
|
|
232
348
|
this.tipsLabel = undefined;
|
|
233
349
|
this.firstTime = 0;
|
|
@@ -245,6 +361,7 @@ MeasureDistance.prototype = {
|
|
|
245
361
|
this.tempPoints = undefined;
|
|
246
362
|
this.tempLabel = undefined;
|
|
247
363
|
this.tempLine = undefined;
|
|
364
|
+
this.hasTempPoint = false;
|
|
248
365
|
this.scene.remove(this.tipsLabel);
|
|
249
366
|
this.tipsLabel = undefined;
|
|
250
367
|
this.firstTime = 0;
|
|
@@ -3,10 +3,11 @@ import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
|
|
|
3
3
|
import { Message } from 'element-ui';
|
|
4
4
|
|
|
5
5
|
var _this = null;
|
|
6
|
-
var MeasureHeight = function (renderer, scene, camera, width, height) {
|
|
6
|
+
var MeasureHeight = function (renderer, scene, camera, width, height, options = {}) {
|
|
7
7
|
this.renderer = renderer;
|
|
8
8
|
this.scene = scene;
|
|
9
9
|
this.camera = camera;
|
|
10
|
+
this.pickRoots = options.pickRoots || null;
|
|
10
11
|
this.pointArray = [];
|
|
11
12
|
this.raycaster = new THREE.Raycaster();
|
|
12
13
|
this.points = [];
|
|
@@ -22,7 +23,7 @@ var MeasureHeight = function (renderer, scene, camera, width, height) {
|
|
|
22
23
|
this.height = height;
|
|
23
24
|
this.firstTime = 0;
|
|
24
25
|
this.plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
|
|
25
|
-
this.measureName = 'measureObj'
|
|
26
|
+
this.measureName = 'measureObj';
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
MeasureHeight.prototype = {
|
|
@@ -40,7 +41,45 @@ MeasureHeight.prototype = {
|
|
|
40
41
|
this.width = width;
|
|
41
42
|
this.height = height;
|
|
42
43
|
},
|
|
43
|
-
|
|
44
|
+
getPickRoots() {
|
|
45
|
+
const roots = typeof _this.pickRoots === 'function' ? _this.pickRoots() : _this.pickRoots;
|
|
46
|
+
if (Array.isArray(roots) && roots.length > 0) {
|
|
47
|
+
return roots.filter(Boolean);
|
|
48
|
+
}
|
|
49
|
+
if (roots) {
|
|
50
|
+
return [roots];
|
|
51
|
+
}
|
|
52
|
+
return _this.scene && _this.scene.children ? _this.scene.children : [];
|
|
53
|
+
},
|
|
54
|
+
isExcludedIntersection(object) {
|
|
55
|
+
let current = object;
|
|
56
|
+
while (current) {
|
|
57
|
+
const userData = current.userData || {};
|
|
58
|
+
if (current.visible === false) return true;
|
|
59
|
+
if (current.name === _this.measureName || userData.isMeasureObject === true) return true;
|
|
60
|
+
if (userData.transformControlHelper === true || userData.outlineProxy === true) return true;
|
|
61
|
+
if (current.isCamera || current.isLight) return true;
|
|
62
|
+
if (
|
|
63
|
+
typeof current.type === 'string' &&
|
|
64
|
+
(/Helper$/i.test(current.type) ||
|
|
65
|
+
current.type === 'CSS2DObject' ||
|
|
66
|
+
current.type === 'TransformControlsRoot')
|
|
67
|
+
) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
current = current.parent;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
},
|
|
74
|
+
markMeasureObject(object) {
|
|
75
|
+
object.name = this.measureName;
|
|
76
|
+
if (!object.userData) {
|
|
77
|
+
object.userData = {};
|
|
78
|
+
}
|
|
79
|
+
object.userData.isMeasureObject = true;
|
|
80
|
+
return object;
|
|
81
|
+
},
|
|
82
|
+
getPosition(e, options = {}) {
|
|
44
83
|
const mouse = new THREE.Vector2();
|
|
45
84
|
const elRect = this.renderer.domElement.getBoundingClientRect();
|
|
46
85
|
const canvasX = e.clientX - elRect.left;
|
|
@@ -50,11 +89,17 @@ MeasureHeight.prototype = {
|
|
|
50
89
|
mouse.y = -(canvasY / elRect.height) * 2.0 + 1.0;
|
|
51
90
|
|
|
52
91
|
_this.raycaster.setFromCamera(mouse, this.camera);
|
|
53
|
-
const intersects = _this.raycaster
|
|
92
|
+
const intersects = _this.raycaster
|
|
93
|
+
.intersectObjects(_this.getPickRoots(), true)
|
|
94
|
+
.filter(item => item && item.object && !_this.isExcludedIntersection(item.object));
|
|
54
95
|
if (intersects.length > 0) {
|
|
55
96
|
return { point: intersects[0].point, isModel: true };
|
|
56
97
|
}
|
|
57
98
|
|
|
99
|
+
if (options.allowPlaneFallback === false) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
58
103
|
if (_this.pointArray && _this.pointArray.length > 0) {
|
|
59
104
|
const lastPoint =
|
|
60
105
|
_this.pointArray.length === 1
|
|
@@ -83,11 +128,11 @@ MeasureHeight.prototype = {
|
|
|
83
128
|
linewidth: 15,
|
|
84
129
|
depthTest: false,
|
|
85
130
|
depthWrite: false,
|
|
86
|
-
transparent: true
|
|
131
|
+
transparent: true,
|
|
87
132
|
});
|
|
88
133
|
const lineGeometry = new THREE.BufferGeometry().setFromPoints([p1, p2]);
|
|
89
134
|
const line = new THREE.Line(lineGeometry, lineMaterial);
|
|
90
|
-
|
|
135
|
+
this.markMeasureObject(line);
|
|
91
136
|
line.renderOrder = 999;
|
|
92
137
|
line.frustumCulled = false;
|
|
93
138
|
return line;
|
|
@@ -97,7 +142,7 @@ MeasureHeight.prototype = {
|
|
|
97
142
|
div.className = name;
|
|
98
143
|
div.textContent = text;
|
|
99
144
|
const divLabel = new CSS2DObject(div);
|
|
100
|
-
|
|
145
|
+
this.markMeasureObject(divLabel);
|
|
101
146
|
divLabel.position.set(position.x, position.y, position.z);
|
|
102
147
|
return divLabel;
|
|
103
148
|
},
|
|
@@ -128,7 +173,7 @@ MeasureHeight.prototype = {
|
|
|
128
173
|
div.className = 'tips-label';
|
|
129
174
|
div.textContent = label;
|
|
130
175
|
const tipsLabel = new CSS2DObject(div);
|
|
131
|
-
|
|
176
|
+
this.markMeasureObject(tipsLabel);
|
|
132
177
|
tipsLabel.position.set(position.x + 0.1, position.y, position.z + 0.05);
|
|
133
178
|
return tipsLabel;
|
|
134
179
|
},
|
|
@@ -141,13 +186,13 @@ MeasureHeight.prototype = {
|
|
|
141
186
|
clearTimeout(_this.timer);
|
|
142
187
|
_this.timer = setTimeout(() => {
|
|
143
188
|
_this.isCompleted = false;
|
|
144
|
-
const positionResult = _this.getPosition(e);
|
|
189
|
+
const positionResult = _this.getPosition(e, { allowPlaneFallback: false });
|
|
190
|
+
if (!positionResult || !positionResult.isModel) {
|
|
191
|
+
Message.warning('请点击模型进行测量');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
145
194
|
if (positionResult) {
|
|
146
|
-
const { point
|
|
147
|
-
if (!isModel) {
|
|
148
|
-
Message.warning('请点击模型进行测量');
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
195
|
+
const { point } = positionResult;
|
|
151
196
|
// if (_this.tipsLabel) {
|
|
152
197
|
// _this.tipsLabel.position.set(point.x + 0.1, point.y, point.z + 0.05);
|
|
153
198
|
// } else {
|
|
@@ -188,7 +233,6 @@ MeasureHeight.prototype = {
|
|
|
188
233
|
this.renderer.domElement.style.cursor = 'pointer';
|
|
189
234
|
this.firstTime = 0;
|
|
190
235
|
}
|
|
191
|
-
|
|
192
236
|
},
|
|
193
237
|
clear() {
|
|
194
238
|
this.remove(this.points);
|