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.
@@ -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
- getPosition(e) {
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.intersectObjects(_this.scene.children, true);
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
- line.name = this.measureName;
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
- divLabel.name = this.measureName
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.pointArray.length === 1
114
- ? _this.pointArray.push(point)
115
- : _this.pointArray.splice(_this.pointArray.length - 1, 1, point);
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
- tipsLabel.name = this.measureName
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, isModel } = positionResult;
172
- if (!isModel) {
173
- // 提示请点击模型
174
- Message.warning('请点击模型进行测量');
175
- return;
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
- getPosition(e) {
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.intersectObjects(_this.scene.children, true);
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
- line.name = this.measureName;
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
- divLabel.name = this.measureName
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
- tipsLabel.name = this.measureName
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, isModel } = positionResult;
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);