fl-web-component 2.0.0-beta.9 → 2.0.0
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/dist/fl-web-component.common.js +34592 -1519
- package/dist/fl-web-component.common.js.map +1 -1
- package/dist/fl-web-component.css +1 -1
- package/package.json +4 -15
- package/packages/components/com-card/index.vue +1 -1
- package/packages/components/com-flcanvas/components/bspline.js +31 -34
- package/packages/components/com-flcanvas/components/entityFormatting.js +810 -823
- package/packages/components/com-flcanvas/components/round10.js +17 -17
- package/packages/components/com-flcanvas/index.vue +314 -333
- package/packages/components/com-formDialog/index.vue +6 -4
- package/packages/components/com-graphics/component/ann-tool.vue +263 -208
- package/packages/components/com-graphics/index.vue +366 -773
- package/packages/components/com-graphics/pid.vue +304 -295
- package/packages/components/com-table/column-default.vue +2 -3
- package/packages/components/com-table/column-dynamic.vue +7 -4
- package/packages/components/com-table/column.vue +1 -2
- package/packages/components/com-table/index.vue +6 -5
- package/packages/components/com-tabs/index.vue +1 -2
- package/packages/components/com-tiles/index.vue +134 -136
- package/packages/components/com-treeDynamic/index.vue +1 -1
- package/packages/utils/StreamLoader.js +1548 -1489
- package/packages/utils/StreamLoaderParser.worker.js +9 -14
- package/src/main.js +2 -8
- package/src/utils/cloud.js +28 -28
- package/src/utils/cursor.js +11 -9
- package/src/utils/flgltf-parser.js +257 -245
- package/src/utils/instance-parser.js +20 -22
- package/src/utils/mini-devtool.js +94 -39
- package/src/utils/threejs/measure-angle.js +51 -13
- package/src/utils/threejs/measure-area.js +43 -12
- package/src/utils/threejs/measure-distance.js +43 -12
- package/src/utils/threejs/rain-shader.js +10 -10
- package/src/utils/threejs/snow-shader.js +9 -9
|
@@ -11,8 +11,8 @@ export default function installErrorConsolePanel() {
|
|
|
11
11
|
function getCircularReplacer() {
|
|
12
12
|
const seen = new WeakSet();
|
|
13
13
|
return (key, value) => {
|
|
14
|
-
if (typeof value ===
|
|
15
|
-
if (seen.has(value)) return
|
|
14
|
+
if (typeof value === 'object' && value !== null) {
|
|
15
|
+
if (seen.has(value)) return '[Circular]';
|
|
16
16
|
seen.add(value);
|
|
17
17
|
}
|
|
18
18
|
return value;
|
|
@@ -20,11 +20,15 @@ export default function installErrorConsolePanel() {
|
|
|
20
20
|
}
|
|
21
21
|
function safeStringify(x) {
|
|
22
22
|
try {
|
|
23
|
-
if (typeof x ===
|
|
23
|
+
if (typeof x === 'string') return x;
|
|
24
24
|
if (x instanceof Error) return x.stack || x.message || String(x);
|
|
25
25
|
return JSON.stringify(x, getCircularReplacer(), 2);
|
|
26
26
|
} catch (e) {
|
|
27
|
-
try {
|
|
27
|
+
try {
|
|
28
|
+
return String(x);
|
|
29
|
+
} catch (e2) {
|
|
30
|
+
return '[unstringifiable]';
|
|
31
|
+
}
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -52,12 +56,17 @@ export default function installErrorConsolePanel() {
|
|
|
52
56
|
display: 'flex',
|
|
53
57
|
flexDirection: 'column',
|
|
54
58
|
gap: '6px',
|
|
55
|
-
padding: '8px'
|
|
59
|
+
padding: '8px',
|
|
56
60
|
});
|
|
57
61
|
|
|
58
62
|
// header
|
|
59
63
|
const header = document.createElement('div');
|
|
60
|
-
Object.assign(header.style, {
|
|
64
|
+
Object.assign(header.style, {
|
|
65
|
+
display: 'flex',
|
|
66
|
+
justifyContent: 'space-between',
|
|
67
|
+
alignItems: 'center',
|
|
68
|
+
gap: '8px',
|
|
69
|
+
});
|
|
61
70
|
header.innerHTML = `<strong style="font-size:13px">JS Logs / Errors</strong><span style="opacity:.7;font-size:11px">(非阻塞)</span>`;
|
|
62
71
|
|
|
63
72
|
const btns = document.createElement('div');
|
|
@@ -65,14 +74,23 @@ export default function installErrorConsolePanel() {
|
|
|
65
74
|
const clearBtn = document.createElement('button');
|
|
66
75
|
clearBtn.textContent = '清空';
|
|
67
76
|
Object.assign(clearBtn.style, { marginLeft: '6px', cursor: 'pointer', fontSize: '12px' });
|
|
68
|
-
clearBtn.onclick = () => {
|
|
77
|
+
clearBtn.onclick = () => {
|
|
78
|
+
entriesContainer.innerHTML = '';
|
|
79
|
+
entryCount = 0;
|
|
80
|
+
updateStats();
|
|
81
|
+
};
|
|
69
82
|
|
|
70
83
|
const toggleBtn = document.createElement('button');
|
|
71
84
|
toggleBtn.textContent = '隐藏';
|
|
72
85
|
Object.assign(toggleBtn.style, { cursor: 'pointer', fontSize: '12px' });
|
|
73
86
|
toggleBtn.onclick = () => {
|
|
74
|
-
if (entriesContainer.style.display === 'none') {
|
|
75
|
-
|
|
87
|
+
if (entriesContainer.style.display === 'none') {
|
|
88
|
+
entriesContainer.style.display = '';
|
|
89
|
+
toggleBtn.textContent = '隐藏';
|
|
90
|
+
} else {
|
|
91
|
+
entriesContainer.style.display = 'none';
|
|
92
|
+
toggleBtn.textContent = '显示';
|
|
93
|
+
}
|
|
76
94
|
};
|
|
77
95
|
|
|
78
96
|
const statsSpan = document.createElement('span');
|
|
@@ -93,7 +111,7 @@ export default function installErrorConsolePanel() {
|
|
|
93
111
|
borderRadius: '6px',
|
|
94
112
|
background: 'rgba(0,0,0,0.32)',
|
|
95
113
|
maxHeight: 'calc(45vh - 48px)',
|
|
96
|
-
boxSizing: 'border-box'
|
|
114
|
+
boxSizing: 'border-box',
|
|
97
115
|
});
|
|
98
116
|
|
|
99
117
|
panel.appendChild(header);
|
|
@@ -112,7 +130,12 @@ export default function installErrorConsolePanel() {
|
|
|
112
130
|
|
|
113
131
|
// ========== 添加条目 ==========
|
|
114
132
|
let entryCount = 0;
|
|
115
|
-
function addEntry({
|
|
133
|
+
function addEntry({
|
|
134
|
+
type = 'log',
|
|
135
|
+
message = '',
|
|
136
|
+
time = new Date().toLocaleString(),
|
|
137
|
+
meta = null,
|
|
138
|
+
}) {
|
|
116
139
|
const panel = createPanel();
|
|
117
140
|
const entriesContainer = panel._entriesContainer;
|
|
118
141
|
const updateStats = panel._statsUpdater;
|
|
@@ -144,14 +167,14 @@ export default function installErrorConsolePanel() {
|
|
|
144
167
|
error: '#ff6b6b',
|
|
145
168
|
'window.onerror': '#ff6b6b',
|
|
146
169
|
resource: '#ff9966',
|
|
147
|
-
|
|
170
|
+
unhandledrejection: '#ff8c66',
|
|
148
171
|
'console.error': '#ff6b6b',
|
|
149
172
|
'console.warn': '#ffd966',
|
|
150
173
|
'console.info': '#66bfff',
|
|
151
174
|
'console.log': '#bfbfbf',
|
|
152
175
|
'console.debug': '#a0a0a0',
|
|
153
176
|
'Vue.error (2)': '#ff6b6b',
|
|
154
|
-
'Vue.error (3)': '#ff6b6b'
|
|
177
|
+
'Vue.error (3)': '#ff6b6b',
|
|
155
178
|
};
|
|
156
179
|
const tagColor = colorMap[type] || '#bfbfbf';
|
|
157
180
|
left.innerHTML = `<span style="font-weight:700;color:${tagColor}">${type}</span> <span style="opacity:.7;font-size:11px"> ${time}</span>`;
|
|
@@ -182,7 +205,7 @@ export default function installErrorConsolePanel() {
|
|
|
182
205
|
overflow: 'auto',
|
|
183
206
|
fontSize: '12px',
|
|
184
207
|
lineHeight: '1.3',
|
|
185
|
-
display: 'block'
|
|
208
|
+
display: 'block',
|
|
186
209
|
});
|
|
187
210
|
|
|
188
211
|
// 合成文本(message + meta)
|
|
@@ -197,14 +220,24 @@ export default function installErrorConsolePanel() {
|
|
|
197
220
|
|
|
198
221
|
if (txt.length > COLLAPSE_LENGTH) {
|
|
199
222
|
content.textContent = txt.slice(0, COLLAPSE_LENGTH) + '\n\n...(已折叠,点击展开查看全部)';
|
|
200
|
-
expandBtn.onclick = () => {
|
|
223
|
+
expandBtn.onclick = () => {
|
|
224
|
+
content.textContent = fullText;
|
|
225
|
+
expandBtn.style.display = 'none';
|
|
226
|
+
entriesContainer.scrollTop = entriesContainer.scrollHeight;
|
|
227
|
+
};
|
|
201
228
|
} else {
|
|
202
229
|
content.textContent = txt;
|
|
203
230
|
expandBtn.style.display = 'none';
|
|
204
231
|
}
|
|
205
232
|
|
|
206
233
|
copyBtn.onclick = () => {
|
|
207
|
-
try {
|
|
234
|
+
try {
|
|
235
|
+
navigator.clipboard.writeText(fullText);
|
|
236
|
+
} catch (e) {
|
|
237
|
+
try {
|
|
238
|
+
prompt('复制文本:Ctrl+C, Enter', fullText);
|
|
239
|
+
} catch (ee) {}
|
|
240
|
+
}
|
|
208
241
|
};
|
|
209
242
|
|
|
210
243
|
entry.appendChild(header);
|
|
@@ -220,7 +253,12 @@ export default function installErrorConsolePanel() {
|
|
|
220
253
|
// 报告包装
|
|
221
254
|
function report(obj) {
|
|
222
255
|
try {
|
|
223
|
-
addEntry({
|
|
256
|
+
addEntry({
|
|
257
|
+
type: obj.type || 'log',
|
|
258
|
+
message: obj.message || safeStringify(obj),
|
|
259
|
+
time: new Date().toLocaleString(),
|
|
260
|
+
meta: obj.meta || null,
|
|
261
|
+
});
|
|
224
262
|
} catch (e) {
|
|
225
263
|
console.warn('Error panel report failed', e);
|
|
226
264
|
}
|
|
@@ -229,34 +267,40 @@ export default function installErrorConsolePanel() {
|
|
|
229
267
|
// ========== 捕获逻辑 ==========
|
|
230
268
|
|
|
231
269
|
// 传统同步错误
|
|
232
|
-
window.onerror = function(message, source, lineno, colno, error) {
|
|
233
|
-
const msg = `${message}\n at ${source}:${lineno}:${colno}\n${
|
|
270
|
+
window.onerror = function (message, source, lineno, colno, error) {
|
|
271
|
+
const msg = `${message}\n at ${source}:${lineno}:${colno}\n${
|
|
272
|
+
error && error.stack ? error.stack : ''
|
|
273
|
+
}`;
|
|
234
274
|
report({ type: 'window.onerror', message: msg });
|
|
235
275
|
return false;
|
|
236
276
|
};
|
|
237
277
|
|
|
238
278
|
// 资源加载错误(图片/script/css 等)
|
|
239
|
-
window.addEventListener(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
279
|
+
window.addEventListener(
|
|
280
|
+
'error',
|
|
281
|
+
function (event) {
|
|
282
|
+
const target = event.target || event.srcElement;
|
|
283
|
+
if (target && (target.src || target.href)) {
|
|
284
|
+
const tag = target.tagName;
|
|
285
|
+
const url = target.src || target.href;
|
|
286
|
+
report({ type: 'resource', message: `Failed to load resource: <${tag}> ${url}` });
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
true
|
|
290
|
+
);
|
|
247
291
|
|
|
248
292
|
// 未处理的 Promise 拒绝
|
|
249
|
-
window.addEventListener('unhandledrejection', function(event) {
|
|
293
|
+
window.addEventListener('unhandledrejection', function (event) {
|
|
250
294
|
report({ type: 'unhandledrejection', message: safeStringify(event.reason) });
|
|
251
295
|
});
|
|
252
296
|
|
|
253
297
|
// 捕获 console.*(可选)
|
|
254
298
|
if (CAPTURE_CONSOLE && typeof console !== 'undefined') {
|
|
255
299
|
const methods = ['log', 'info', 'warn', 'error', 'debug'];
|
|
256
|
-
methods.forEach(
|
|
300
|
+
methods.forEach(m => {
|
|
257
301
|
if (!(m in console)) return;
|
|
258
302
|
const orig = console[m].bind(console);
|
|
259
|
-
console[m] = function(...args) {
|
|
303
|
+
console[m] = function (...args) {
|
|
260
304
|
try {
|
|
261
305
|
// 生成调用栈(方便定位是谁调用了 console)
|
|
262
306
|
let stack = null;
|
|
@@ -266,19 +310,23 @@ export default function installErrorConsolePanel() {
|
|
|
266
310
|
// 移除前两行(Error + 本函数)
|
|
267
311
|
stack = err.stack.split('\n').slice(2).join('\n');
|
|
268
312
|
}
|
|
269
|
-
} catch (e) {
|
|
313
|
+
} catch (e) {
|
|
314
|
+
stack = null;
|
|
315
|
+
}
|
|
270
316
|
|
|
271
317
|
const payload = {
|
|
272
318
|
type: `console.${m}`,
|
|
273
319
|
message: args.map(a => safeStringify(a)).join(' '),
|
|
274
|
-
meta: stack
|
|
320
|
+
meta: stack,
|
|
275
321
|
};
|
|
276
322
|
report(payload);
|
|
277
323
|
} catch (e) {
|
|
278
324
|
// noop
|
|
279
325
|
}
|
|
280
326
|
// 保持原有行为
|
|
281
|
-
try {
|
|
327
|
+
try {
|
|
328
|
+
orig(...args);
|
|
329
|
+
} catch (e) {}
|
|
282
330
|
};
|
|
283
331
|
});
|
|
284
332
|
}
|
|
@@ -286,17 +334,25 @@ export default function installErrorConsolePanel() {
|
|
|
286
334
|
// Vue 2 支持(若使用全局 Vue)
|
|
287
335
|
if (typeof Vue !== 'undefined' && Vue && Vue.config) {
|
|
288
336
|
try {
|
|
289
|
-
Vue.config.errorHandler = function(err, vm, info) {
|
|
290
|
-
report({
|
|
337
|
+
Vue.config.errorHandler = function (err, vm, info) {
|
|
338
|
+
report({
|
|
339
|
+
type: 'Vue.error (2)',
|
|
340
|
+
message: `${info}\n${err && err.stack ? err.stack : safeStringify(err)}`,
|
|
341
|
+
});
|
|
291
342
|
};
|
|
292
|
-
} catch (e) {
|
|
343
|
+
} catch (e) {
|
|
344
|
+
/* ignore */
|
|
345
|
+
}
|
|
293
346
|
}
|
|
294
347
|
|
|
295
348
|
// Vue 3 注册函数(在 main.js 创建 app 后调用)
|
|
296
|
-
window.registerVue3ErrorHandler = function(app) {
|
|
349
|
+
window.registerVue3ErrorHandler = function (app) {
|
|
297
350
|
if (!app || !app.config) return;
|
|
298
351
|
app.config.errorHandler = (err, instance, info) => {
|
|
299
|
-
report({
|
|
352
|
+
report({
|
|
353
|
+
type: 'Vue.error (3)',
|
|
354
|
+
message: `${info}\n${err && err.stack ? err.stack : safeStringify(err)}`,
|
|
355
|
+
});
|
|
300
356
|
};
|
|
301
357
|
};
|
|
302
358
|
|
|
@@ -304,6 +360,5 @@ export default function installErrorConsolePanel() {
|
|
|
304
360
|
if (document.readyState === 'loading') {
|
|
305
361
|
document.addEventListener('DOMContentLoaded', createPanel);
|
|
306
362
|
} else createPanel();
|
|
307
|
-
|
|
308
363
|
}
|
|
309
364
|
// ========= End Panel =========
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
|
|
3
|
+
import { Message } from 'element-ui';
|
|
3
4
|
var _this = null;
|
|
4
5
|
var MeasureAngle = function (renderer, scene, camera, width, height) {
|
|
5
6
|
this.renderer = renderer;
|
|
@@ -56,13 +57,30 @@ MeasureAngle.prototype = {
|
|
|
56
57
|
_this.raycaster.setFromCamera(mouse, this.camera);
|
|
57
58
|
let intersects = _this.raycaster.intersectObjects(_this.scene.children, true);
|
|
58
59
|
if (intersects.length > 0) {
|
|
59
|
-
return intersects[0].point;
|
|
60
|
+
return { point: intersects[0].point, isModel: true };
|
|
60
61
|
}
|
|
62
|
+
|
|
63
|
+
// 如果没有交点,构建一个基于最后一个确认点且面向相机的平面
|
|
64
|
+
if (_this.pointArray && _this.pointArray.length > 0) {
|
|
65
|
+
const lastPoint =
|
|
66
|
+
_this.pointArray.length === 1
|
|
67
|
+
? _this.pointArray[0]
|
|
68
|
+
: _this.pointArray[_this.pointArray.length - 2];
|
|
69
|
+
const cameraDir = new THREE.Vector3();
|
|
70
|
+
_this.camera.getWorldDirection(cameraDir);
|
|
71
|
+
const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(cameraDir, lastPoint);
|
|
72
|
+
const target = new THREE.Vector3();
|
|
73
|
+
_this.raycaster.ray.intersectPlane(plane, target);
|
|
74
|
+
if (target) {
|
|
75
|
+
return { point: target, isModel: false };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
61
79
|
// 如果没有交点,则创建一个在相机视图平面上的点
|
|
62
|
-
const
|
|
63
|
-
_this.raycaster.ray.intersectPlane(_this.plane,
|
|
64
|
-
if (
|
|
65
|
-
return
|
|
80
|
+
const target = new THREE.Vector3();
|
|
81
|
+
_this.raycaster.ray.intersectPlane(_this.plane, target);
|
|
82
|
+
if (target) {
|
|
83
|
+
return { point: target, isModel: false };
|
|
66
84
|
}
|
|
67
85
|
return null;
|
|
68
86
|
},
|
|
@@ -75,9 +93,16 @@ MeasureAngle.prototype = {
|
|
|
75
93
|
return sphere;
|
|
76
94
|
},
|
|
77
95
|
createLine(p1, p2, config = { color: 0xff0000 }) {
|
|
78
|
-
const lineMaterial = new THREE.LineBasicMaterial({
|
|
96
|
+
const lineMaterial = new THREE.LineBasicMaterial({
|
|
97
|
+
color: config.color,
|
|
98
|
+
linewidth: 10,
|
|
99
|
+
depthTest: false,
|
|
100
|
+
depthWrite: false,
|
|
101
|
+
transparent: true,
|
|
102
|
+
});
|
|
79
103
|
const lineGeometry = new THREE.BufferGeometry().setFromPoints([p1, p2]);
|
|
80
104
|
const line = new THREE.Line(lineGeometry, lineMaterial);
|
|
105
|
+
line.renderOrder = 999;
|
|
81
106
|
line.frustumCulled = false;
|
|
82
107
|
return line;
|
|
83
108
|
},
|
|
@@ -91,8 +116,9 @@ MeasureAngle.prototype = {
|
|
|
91
116
|
},
|
|
92
117
|
mousemove(e) {
|
|
93
118
|
if (_this.isCompleted || _this.pointArray.length === 0) return;
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
119
|
+
const positionResult = _this.getPosition(e);
|
|
120
|
+
if (positionResult) {
|
|
121
|
+
const point = positionResult.point;
|
|
96
122
|
_this.pointArray.length === 1
|
|
97
123
|
? _this.pointArray.push(point)
|
|
98
124
|
: _this.pointArray.splice(_this.pointArray.length - 1, 1, point);
|
|
@@ -160,8 +186,13 @@ MeasureAngle.prototype = {
|
|
|
160
186
|
clearTimeout(_this.timer);
|
|
161
187
|
_this.timer = setTimeout(() => {
|
|
162
188
|
_this.isCompleted = false;
|
|
163
|
-
const
|
|
164
|
-
if (
|
|
189
|
+
const positionResult = _this.getPosition(e);
|
|
190
|
+
if (positionResult) {
|
|
191
|
+
const { point, isModel } = positionResult;
|
|
192
|
+
if (!isModel) {
|
|
193
|
+
Message.warning('请点击模型进行测量');
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
165
196
|
if (_this.tipsLabel) {
|
|
166
197
|
_this.tipsLabel.position.set(point.x + 0.1, point.y, point.z + 0.05);
|
|
167
198
|
} else {
|
|
@@ -190,8 +221,8 @@ MeasureAngle.prototype = {
|
|
|
190
221
|
_this.tipsLabel = undefined;
|
|
191
222
|
}
|
|
192
223
|
clearTimeout(_this.timer);
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
224
|
+
const positionResult = _this.getPosition(e);
|
|
225
|
+
if (positionResult) {
|
|
195
226
|
_this.isCompleted = true;
|
|
196
227
|
_this.tempPoints = undefined;
|
|
197
228
|
_this.tempLine = undefined;
|
|
@@ -240,8 +271,15 @@ MeasureAngle.prototype = {
|
|
|
240
271
|
},
|
|
241
272
|
createCurve(points) {
|
|
242
273
|
const geom = new THREE.BufferGeometry().setFromPoints(points);
|
|
243
|
-
const material = new THREE.LineBasicMaterial({
|
|
274
|
+
const material = new THREE.LineBasicMaterial({
|
|
275
|
+
color: 0xff0000,
|
|
276
|
+
linewidth: 20,
|
|
277
|
+
depthTest: false,
|
|
278
|
+
depthWrite: false,
|
|
279
|
+
transparent: true,
|
|
280
|
+
});
|
|
244
281
|
_this.curveLine = new THREE.Line(geom, material);
|
|
282
|
+
_this.curveLine.renderOrder = 999;
|
|
245
283
|
_this.curveLine.frustumCulled = false;
|
|
246
284
|
_this.curves.push(_this.curveLine);
|
|
247
285
|
_this.scene.add(_this.curveLine);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
|
|
3
|
+
import { Message } from 'element-ui';
|
|
3
4
|
var _this = null;
|
|
4
5
|
var MeasureArea = function (renderer, scene, camera, width, height) {
|
|
5
6
|
this.renderer = renderer;
|
|
@@ -54,21 +55,44 @@ MeasureArea.prototype = {
|
|
|
54
55
|
_this.raycaster.setFromCamera(mouse, _this.camera);
|
|
55
56
|
let intersects = _this.raycaster.intersectObjects(_this.scene.children, true);
|
|
56
57
|
if (intersects.length > 0) {
|
|
57
|
-
return intersects[0].point;
|
|
58
|
+
return { point: intersects[0].point, isModel: true };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 如果没有交点,构建一个基于最后一个确认点且面向相机的平面
|
|
62
|
+
if (_this.pointArray && _this.pointArray.length > 0) {
|
|
63
|
+
const lastPoint =
|
|
64
|
+
_this.pointArray.length === 1
|
|
65
|
+
? _this.pointArray[0]
|
|
66
|
+
: _this.pointArray[_this.pointArray.length - 2];
|
|
67
|
+
const cameraDir = new THREE.Vector3();
|
|
68
|
+
_this.camera.getWorldDirection(cameraDir);
|
|
69
|
+
const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(cameraDir, lastPoint);
|
|
70
|
+
const target = new THREE.Vector3();
|
|
71
|
+
_this.raycaster.ray.intersectPlane(plane, target);
|
|
72
|
+
if (target) {
|
|
73
|
+
return { point: target, isModel: false };
|
|
74
|
+
}
|
|
58
75
|
}
|
|
59
76
|
|
|
60
77
|
// 如果没有交点,则创建一个在相机视图平面上的点
|
|
61
|
-
const
|
|
62
|
-
_this.raycaster.ray.intersectPlane(_this.plane,
|
|
63
|
-
if (
|
|
64
|
-
return
|
|
78
|
+
const target = new THREE.Vector3();
|
|
79
|
+
_this.raycaster.ray.intersectPlane(_this.plane, target);
|
|
80
|
+
if (target) {
|
|
81
|
+
return { point: target, isModel: false };
|
|
65
82
|
}
|
|
66
83
|
return null;
|
|
67
84
|
},
|
|
68
85
|
createLine(p1, p2, config = { color: 0xff0000 }) {
|
|
69
|
-
const lineMaterial = new THREE.LineBasicMaterial({
|
|
86
|
+
const lineMaterial = new THREE.LineBasicMaterial({
|
|
87
|
+
color: config.color,
|
|
88
|
+
linewidth: 20,
|
|
89
|
+
depthTest: false,
|
|
90
|
+
depthWrite: false,
|
|
91
|
+
transparent: true,
|
|
92
|
+
});
|
|
70
93
|
const lineGeometry = new THREE.BufferGeometry().setFromPoints([p1, p2]);
|
|
71
94
|
const line = new THREE.Line(lineGeometry, lineMaterial);
|
|
95
|
+
line.renderOrder = 999;
|
|
72
96
|
line.frustumCulled = false;
|
|
73
97
|
return line;
|
|
74
98
|
},
|
|
@@ -82,8 +106,9 @@ MeasureArea.prototype = {
|
|
|
82
106
|
},
|
|
83
107
|
mousemove(e) {
|
|
84
108
|
if (_this.isCompleted || _this.pointArray.length === 0) return;
|
|
85
|
-
const
|
|
86
|
-
if (
|
|
109
|
+
const positionResult = _this.getPosition(e);
|
|
110
|
+
if (positionResult) {
|
|
111
|
+
const point = positionResult.point;
|
|
87
112
|
_this.pointArray.length === 1
|
|
88
113
|
? _this.pointArray.push(point)
|
|
89
114
|
: _this.pointArray.splice(_this.pointArray.length - 1, 1, point);
|
|
@@ -153,8 +178,13 @@ MeasureArea.prototype = {
|
|
|
153
178
|
clearTimeout(_this.timer);
|
|
154
179
|
_this.timer = setTimeout(() => {
|
|
155
180
|
_this.isCompleted = false;
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
181
|
+
const positionResult = _this.getPosition(e);
|
|
182
|
+
if (positionResult) {
|
|
183
|
+
const { point, isModel } = positionResult;
|
|
184
|
+
if (!isModel) {
|
|
185
|
+
Message.warning('请点击模型进行测量');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
158
188
|
if (_this.tipsLabel) {
|
|
159
189
|
_this.tipsLabel.position.set(point.x + 0.01, point.y, point.z + 0.05);
|
|
160
190
|
} else {
|
|
@@ -182,8 +212,9 @@ MeasureArea.prototype = {
|
|
|
182
212
|
_this.tipsLabel = undefined;
|
|
183
213
|
}
|
|
184
214
|
clearTimeout(_this.timer);
|
|
185
|
-
const
|
|
186
|
-
if (
|
|
215
|
+
const positionResult = _this.getPosition(e);
|
|
216
|
+
if (positionResult) {
|
|
217
|
+
const point = positionResult.point;
|
|
187
218
|
_this.isCompleted = true;
|
|
188
219
|
if (_this.tempPoints) {
|
|
189
220
|
_this.tempPoints.position.set(point.x, point.y, point.z);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
|
|
3
|
+
import { Message } from 'element-ui';
|
|
3
4
|
var _this = null;
|
|
4
5
|
var MeasureDistance = function (renderer, scene, camera, width, height) {
|
|
5
6
|
this.renderer = renderer;
|
|
@@ -52,22 +53,45 @@ MeasureDistance.prototype = {
|
|
|
52
53
|
_this.raycaster.setFromCamera(mouse, this.camera);
|
|
53
54
|
let intersects = _this.raycaster.intersectObjects(_this.scene.children, true);
|
|
54
55
|
if (intersects.length > 0) {
|
|
55
|
-
return intersects[0].point;
|
|
56
|
+
return { point: intersects[0].point, isModel: true };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 如果没有交点,构建一个基于最后一个确认点且面向相机的平面
|
|
60
|
+
if (_this.pointArray && _this.pointArray.length > 0) {
|
|
61
|
+
const lastPoint =
|
|
62
|
+
_this.pointArray.length === 1
|
|
63
|
+
? _this.pointArray[0]
|
|
64
|
+
: _this.pointArray[_this.pointArray.length - 2];
|
|
65
|
+
const cameraDir = new THREE.Vector3();
|
|
66
|
+
_this.camera.getWorldDirection(cameraDir);
|
|
67
|
+
const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(cameraDir, lastPoint);
|
|
68
|
+
const target = new THREE.Vector3();
|
|
69
|
+
_this.raycaster.ray.intersectPlane(plane, target);
|
|
70
|
+
if (target) {
|
|
71
|
+
return { point: target, isModel: false };
|
|
72
|
+
}
|
|
56
73
|
}
|
|
57
74
|
|
|
58
75
|
// 如果没有交点,则创建一个在相机视图平面上的点
|
|
59
|
-
const
|
|
60
|
-
_this.raycaster.ray.intersectPlane(_this.plane,
|
|
61
|
-
if (
|
|
62
|
-
return
|
|
76
|
+
const target = new THREE.Vector3();
|
|
77
|
+
_this.raycaster.ray.intersectPlane(_this.plane, target);
|
|
78
|
+
if (target) {
|
|
79
|
+
return { point: target, isModel: false };
|
|
63
80
|
}
|
|
64
81
|
|
|
65
82
|
return null;
|
|
66
83
|
},
|
|
67
84
|
createLine(p1, p2, config = { color: 0xff0000 }) {
|
|
68
|
-
const lineMaterial = new THREE.LineBasicMaterial({
|
|
85
|
+
const lineMaterial = new THREE.LineBasicMaterial({
|
|
86
|
+
color: config.color,
|
|
87
|
+
linewidth: 15,
|
|
88
|
+
depthTest: false,
|
|
89
|
+
depthWrite: false,
|
|
90
|
+
transparent: true,
|
|
91
|
+
});
|
|
69
92
|
const lineGeometry = new THREE.BufferGeometry().setFromPoints([p1, p2]);
|
|
70
93
|
const line = new THREE.Line(lineGeometry, lineMaterial);
|
|
94
|
+
line.renderOrder = 999;
|
|
71
95
|
line.frustumCulled = false;
|
|
72
96
|
return line;
|
|
73
97
|
},
|
|
@@ -81,8 +105,9 @@ MeasureDistance.prototype = {
|
|
|
81
105
|
},
|
|
82
106
|
mousemove(e) {
|
|
83
107
|
if (_this.isCompleted || _this.pointArray.length === 0) return;
|
|
84
|
-
const
|
|
85
|
-
if (
|
|
108
|
+
const positionResult = _this.getPosition(e);
|
|
109
|
+
if (positionResult) {
|
|
110
|
+
const point = positionResult.point;
|
|
86
111
|
_this.pointArray.length === 1
|
|
87
112
|
? _this.pointArray.push(point)
|
|
88
113
|
: _this.pointArray.splice(_this.pointArray.length - 1, 1, point);
|
|
@@ -137,8 +162,14 @@ MeasureDistance.prototype = {
|
|
|
137
162
|
clearTimeout(_this.timer);
|
|
138
163
|
_this.timer = setTimeout(() => {
|
|
139
164
|
_this.isCompleted = false;
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
165
|
+
const positionResult = _this.getPosition(e);
|
|
166
|
+
if (positionResult) {
|
|
167
|
+
const { point, isModel } = positionResult;
|
|
168
|
+
if (!isModel) {
|
|
169
|
+
// 提示请点击模型
|
|
170
|
+
Message.warning('请点击模型进行测量');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
142
173
|
if (_this.tipsLabel) {
|
|
143
174
|
_this.tipsLabel.position.set(point.x + 0.1, point.y, point.z + 0.05);
|
|
144
175
|
} else {
|
|
@@ -167,8 +198,8 @@ MeasureDistance.prototype = {
|
|
|
167
198
|
_this.tipsLabel = undefined;
|
|
168
199
|
}
|
|
169
200
|
clearTimeout(_this.timer);
|
|
170
|
-
const
|
|
171
|
-
if (
|
|
201
|
+
const positionResult = _this.getPosition(e);
|
|
202
|
+
if (positionResult) {
|
|
172
203
|
_this.isCompleted = true;
|
|
173
204
|
_this.tempPoints = undefined;
|
|
174
205
|
_this.tempLine = undefined;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import * as THREE from 'three'
|
|
1
|
+
import * as THREE from 'three';
|
|
2
2
|
const RainShader = {
|
|
3
3
|
uniforms: {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
tDiffuse: { value: null },
|
|
5
|
+
iResolution: { value: null },
|
|
6
|
+
iTime: { value: 0 },
|
|
7
|
+
radian: { value: (0 / 360) * Math.PI },
|
|
8
|
+
rainSpeed: { value: 0.2 },
|
|
9
|
+
rainColor: { value: new THREE.Color(1, 1, 1) },
|
|
10
10
|
},
|
|
11
11
|
vertexShader: `
|
|
12
12
|
varying vec2 vUv;
|
|
@@ -52,7 +52,7 @@ const RainShader = {
|
|
|
52
52
|
gl_FragColor = vec4(col,0.0);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
}
|
|
55
|
+
`,
|
|
56
|
+
};
|
|
57
57
|
|
|
58
|
-
export { RainShader }
|
|
58
|
+
export { RainShader };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const SnowShader = {
|
|
2
2
|
uniforms: {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
tDiffuse: { value: null },
|
|
4
|
+
iResolution: { value: null },
|
|
5
|
+
iTime: { value: 0.2 },
|
|
6
|
+
size: { value: 0.05 },
|
|
7
|
+
density: { value: 1.0 },
|
|
8
|
+
snowSpeed: { value: 0.6 },
|
|
9
9
|
},
|
|
10
10
|
vertexShader: `
|
|
11
11
|
varying vec2 vUv;
|
|
@@ -70,6 +70,6 @@ const SnowShader = {
|
|
|
70
70
|
gl_FragColor = vec4(colSnow,0.0);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
export { SnowShader }
|
|
73
|
+
`,
|
|
74
|
+
};
|
|
75
|
+
export { SnowShader };
|