fl-web-component 1.0.9 → 1.0.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fl-web-component",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "scripts": {
5
5
  "dev": "vue-cli-service serve",
6
6
  "lint": "eslint \"{src,packages}/**/*.{vue,js}\" --fix",
@@ -20,6 +20,8 @@
20
20
  pointControls,
21
21
  threeMeasure,
22
22
  modelGroup,
23
+ gui,
24
+ animateId
23
25
  ] = (function* (v) {
24
26
  while (true) yield v;
25
27
  })(null);
@@ -45,22 +47,26 @@
45
47
  while (true) yield v;
46
48
  })(true);
47
49
 
48
- var clippingPlanes = [];
50
+ var clippingMesh = [];
49
51
  var removeSpeed = 200,
50
52
  upSpeed = 200; //控制器移动速度 , //控制跳起时的速度
51
- var modelGroup;
52
- var roamConfig = {
53
- loop: false,
54
- speed: 0, // 最大值为3
55
- name: ''
56
- }
53
+ var roamConfig = {
54
+ loop: false,
55
+ speed: 0, // 最大值为3
56
+ name: ''
57
+ }
58
+ var guiParams = {
59
+ 'x轴': 0,
60
+ 'y轴': 0,
61
+ 'z轴': 0,
62
+ }
57
63
  // 绘制对象映射实例表
58
- let drawObjMapInstance = {};
59
64
  import CameraControls from 'camera-controls';
60
65
  import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
61
66
  import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
62
67
  import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer';
63
68
  import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';
69
+ import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'
64
70
  import MeasureDistance from '@/utils/threejs/measure-distance.js';
65
71
  import MeasureArea from '@/utils/threejs/measure-area.js';
66
72
  import MeasureAngle from '@/utils/threejs/measure-angle.js';
@@ -79,7 +85,6 @@ var roamConfig = {
79
85
  },
80
86
  data() {
81
87
  return {
82
- arrowImg: require('@/assets/arrow-right.png'),
83
88
  };
84
89
  },
85
90
  created() {
@@ -166,22 +171,66 @@ var roamConfig = {
166
171
  /*
167
172
  参数:data 模型数据
168
173
  color: '' 初始化模型的颜色 在业务方 有这个需求
169
- meshNameConfig: {}
174
+ meshNameConfig: {}
170
175
  */
171
- drawModel(data, color = '', meshNameConfig) {
176
+ drawModel(data, color = '', meshNameConfig = {}) {
172
177
  if (Object.keys(data).length === 0) {
173
178
  return;
174
179
  }
175
180
  const { instances, drawObjs } = parseData(data);
176
181
  if (instances.length > 0) {
177
182
  modelGroup = handleInstancedMeshModel(instances, drawObjs, '', scene, color, meshNameConfig);
183
+ let modelBox3 = new this.THREE.Box3();
184
+ modelBox3.expandByObject(modelGroup);
185
+ let modelWorldPs = new this.THREE.Vector3().addVectors(modelBox3.max, modelBox3.min).multiplyScalar(0.5)
178
186
  scene.add(modelGroup);
187
+ modelGroup.traverse(child => {
188
+ if (child.isMesh) {
189
+ const json = this.getMeshCenterAndVolume(child)
190
+ let meshBox3 = new this.THREE.Box3();
191
+ meshBox3.setFromObject(child);
192
+ // 获取每个mesh的中心点,爆炸方向为爆炸中心点指向mesh中心点
193
+ let worldPs = new this.THREE.Vector3().addVectors(meshBox3.max, meshBox3.min).multiplyScalar(0.5)
194
+ if (isNaN(worldPs.x)) return
195
+ // 计算爆炸方向
196
+ child.worldDir = new this.THREE.Vector3().subVectors(worldPs, modelWorldPs).normalize()
197
+ // 保存初始坐标
198
+ child.userData.center = json.center
199
+ child.userData.worldPs = worldPs
200
+ child.userData.oldPs = child.getWorldPosition(new this.THREE.Vector3())
201
+ child.userData.box = json.box
202
+ child.userData.position = new this.THREE.Vector3().copy(child.position)
203
+ child.userData.translate = {
204
+ x: 0,
205
+ y: 0,
206
+ z: 0
207
+ }
208
+ child.userData.rotate = {
209
+ x: 0,
210
+ y: 0,
211
+ z: 0
212
+ }
213
+ child.userData.modelWorldPs = modelWorldPs
214
+ }
215
+ })
179
216
  // this.compileShader();
180
217
  // cameraControls.fitToSphere(scene, true); // TODO 待处理,先用 setModelCenter 进行定位
181
218
  this.setModelCenter(modelGroup);
182
219
  // cameraControls.saveState();
183
220
  }
184
221
  },
222
+ // 获取mesh的中心点
223
+ getMeshCenterAndVolume(mesh) {
224
+ const box = new this.THREE.Box3().setFromObject(mesh)
225
+ const volume = box.getSize(new this.THREE.Vector3())
226
+ const geometry = mesh.geometry
227
+ geometry.computeBoundingBox()
228
+ const center = geometry.boundingBox.getCenter(new this.THREE.Vector3())
229
+ return {
230
+ 'center': center,
231
+ 'box': volume
232
+ }
233
+ },
185
234
  compileShader() {
186
235
  scene.traverse(child => {
187
236
  if (child.isMesh) {
@@ -349,8 +398,14 @@ var roamConfig = {
349
398
  case 'visible':
350
399
  targetObj.forEach(children => {
351
400
  const index = children.userData.instanceIndex;
352
- children.geometry.attributes.visible.array[index] = ele.attr[key] ? 1.0 : 0.0;
353
- children.geometry.attributes.visible.needsUpdate = true;
401
+ if (ele.attr[key]) {
402
+ const restoreMatrix = new this.THREE.Matrix4().copy(children.userData.copyMatrix);
403
+ children.setMatrixAt(index, restoreMatrix);
404
+ } else {
405
+ const offsetMatrix = new this.THREE.Matrix4().copy(children.userData.copyMatrix).makeTranslation(9999999, 9999999, 9999999);
406
+ children.setMatrixAt(index, offsetMatrix);
407
+ }
408
+ children.instanceMatrix.needsUpdate = true;
354
409
  });
355
410
  break;
356
411
  case 'opacity':
@@ -367,7 +422,7 @@ var roamConfig = {
367
422
  // obj.material.needsUpdate = true;
368
423
  }
369
424
  },
370
- // 修改整体模型实体的属性
425
+ // 修改整个场景中模型实体的属性
371
426
  /*
372
427
  {
373
428
  attr: '', 需要修改属性名(color、visible(true / false)、opacity(0-1),
@@ -380,7 +435,8 @@ var roamConfig = {
380
435
  if (obj instanceof this.THREE.Mesh) {
381
436
  switch (params.attr) {
382
437
  case 'color':
383
- obj.material.color = new this.THREE.Color(params.value);
438
+ obj.setColorAt(obj.userData.instanceIndex, new this.THREE.Color(params.value));
439
+ obj.instanceColor.needsUpdate = true;
384
440
  break;
385
441
  case 'visible':
386
442
  obj.material.visible = params.value;
@@ -414,20 +470,63 @@ var roamConfig = {
414
470
  }
415
471
  });
416
472
  break;
473
+ case 'visible':
474
+ obj.forEach(children => {
475
+ const index = children.userData.instanceIndex;
476
+ const restoreMatrix = new this.THREE.Matrix4().copy(children.userData.copyMatrix);
477
+ children.setMatrixAt(index, restoreMatrix);
478
+ children.instanceMatrix.needsUpdate = true
479
+ });
480
+ break;
417
481
  }
418
482
  }
419
483
  }
420
484
  }
421
485
  },
422
486
  // 定位到模型
423
- locateModel(id) {
424
- let obj = scene.getObjectByName(id);
487
+ locateModel(name) {
488
+ let obj = scene.getObjectByName(name);
425
489
  if (obj) {
426
490
  // cameraControls.fitToSphere(obj.parent, true); // TODO 待处理,先用 setModelCenter 进行定位
427
491
  this.setModelCenter(obj.parent);
428
492
  // cameraControls.fitToBox( obj, true);
429
493
  }
430
494
  },
495
+ // 根据自定义参数修改模型
496
+ /*
497
+ 自定义参数指的是在调用drawModel时配置的meshNameConfig里面的字段来修改某一类模型实体的属性
498
+ {
499
+ customName: '', 自定义字段名称
500
+ customValue: '' 自定义字段的值
501
+ attr: {
502
+ color: '',
503
+ opacity: 0 -1,
504
+ visiable: true/false
505
+ }
506
+ }
507
+ */
508
+ updatePropertyByCustom(params) {
509
+ scene.traverse(child => {
510
+ if (child.isMesh && child.userData[params.customName] === params.customValue) {
511
+ for (const key in params.attr) {
512
+ switch (key) {
513
+ case 'color':
514
+ child.setColorAt(obj.userData.instanceIndex, new this.THREE.Color(params.attr[key]));
515
+ child.instanceColor.needsUpdate = true;
516
+ break;
517
+ case 'visible':
518
+ child.material.visible = params.attr[key];
519
+ break;
520
+ case 'opacity':
521
+ child.material.opacity = params.attr[key];
522
+ child.material.transparent = true;
523
+ break;
524
+ }
525
+ child.material.needsUpdate = true;
526
+ }
527
+ }
528
+ })
529
+ },
431
530
  // 相机定位
432
531
  /*
433
532
  定位参数:x: 相机的x位置, y: 相机的y位置, z: 相机的z位置
@@ -585,7 +684,7 @@ var roamConfig = {
585
684
  curve = new this.THREE.CatmullRomCurve3(route, false, 'catmullrom', 0);
586
685
  const geometry = new this.THREE.TubeGeometry(curve, 5000, 0.5, 4);
587
686
  //加载纹理
588
- lineTexture = new this.THREE.TextureLoader().load(this.arrowImg);
687
+ lineTexture = new this.THREE.TextureLoader().load('/static/arrow/arrow-right.png');
589
688
  lineTexture.wrapS = this.THREE.RepeatWrapping;
590
689
  lineTexture.wrapT = this.THREE.RepeatWrapping;
591
690
  lineTexture.repeat.set(20, 1); //水平重复20次
@@ -622,7 +721,7 @@ var roamConfig = {
622
721
  path: params.path,
623
722
  });
624
723
  roaming = true
625
- clock = new this.THREE.Clock();
724
+ // clock = new this.THREE.Clock();
626
725
  },
627
726
  // 更新漫游的配置
628
727
  /*
@@ -630,14 +729,14 @@ var roamConfig = {
630
729
  */
631
730
  updateRoamConfig(params) {
632
731
  for (let key in params) {
633
- roamConfig[key] = key === 'speed' ? params[key] / 300 : params[key]
732
+ roamConfig[key] = params[key]
634
733
  }
635
734
  },
636
735
  // 结束/退出漫游
637
736
  endRoam() {
638
737
  roaming = false;
639
738
  progress = 0;
640
- this.removeObjectByName(this.roamConfig.name);
739
+ this.removeObjectByName(roamConfig.name);
641
740
  roamConfig = {
642
741
  loop: false,
643
742
  speed: 0,
@@ -686,7 +785,7 @@ var roamConfig = {
686
785
  this.computedBomb(item, val);
687
786
  });
688
787
  }
689
- this.timeRender();
788
+ // this.timeRender();
690
789
  },
691
790
  // 单个实体模型炸开
692
791
  /*
@@ -712,7 +811,7 @@ var roamConfig = {
712
811
  先开启模型全局剖切模式, 会返回剖切值的最大最小值
713
812
  剖切值变换时, 使用
714
813
  */
715
- setGlobalClipping() {
814
+ setGlobalClipping(flag = true) {
716
815
  const box3 = new this.THREE.Box3().setFromObject(scene.children[0]);
717
816
  let max = box3.max;
718
817
  let min = box3.min;
@@ -722,6 +821,18 @@ var roamConfig = {
722
821
  new this.THREE.Plane(new this.THREE.Vector3(0, 0, -1), max.z),
723
822
  ];
724
823
  renderer.clippingPlanes = clippingPlanes;
824
+ if (flag) {
825
+ guiParams = {
826
+ 'x轴': clippingPlanes[0].constant,
827
+ 'y轴': clippingPlanes[2].constant,
828
+ 'z轴': clippingPlanes[1].constant
829
+ }
830
+ this.addClippingGui('全局剖切', {
831
+ x: min.x,
832
+ y: min.z,
833
+ z: min.y
834
+ }, clippingPlanes)
835
+ }
725
836
  return {
726
837
  min: min,
727
838
  max: max,
@@ -745,15 +856,23 @@ var roamConfig = {
745
856
  },
746
857
  // 取消全局剖切
747
858
  cancelGlobalClipping() {
859
+ guiParams = {
860
+ 'x轴': 0,
861
+ 'y轴': 0,
862
+ 'z轴': 0
863
+ };
748
864
  renderer.clippingPlanes = Object.freeze([]);
865
+ gui && gui.destroy();
749
866
  },
750
- // 单个实体的剖切/ 局部剖切 obj 实体对象
751
- setLocalClipping(obj) {
867
+ // 单个实体的剖切/ 局部剖切 obj 实体对象 flag 代表是否使用图形组件自带的剖切面板 默认为true
868
+ setLocalClipping(obj, flag = true) {
869
+ clippingMesh.splice(0)
870
+ clippingMesh.push(obj)
752
871
  renderer.localClippingEnabled = true;
753
872
  // mesh的boundingBox 可以获取到该对象位置的最大最小值 但是在这里我们需要把y、z轴互换
754
- const boundingBox = new this.THREE.Box3().copy(obj.geometry.boundingBox);
873
+ const boundingBox = new this.THREE.Box3().copy(obj.boundingBox);
755
874
  boundingBox.applyMatrix4(obj.matrixWorld);
756
- clippingPlanes = [
875
+ let clippingPlanes = [
757
876
  new this.THREE.Plane(new this.THREE.Vector3(-1, 0, 0), Math.ceil(boundingBox.max.x)),
758
877
  new this.THREE.Plane(new this.THREE.Vector3(0, -1, 0), Math.ceil(boundingBox.max.y)),
759
878
  new this.THREE.Plane(new this.THREE.Vector3(0, 0, -1), Math.ceil(boundingBox.max.z)),
@@ -761,6 +880,23 @@ var roamConfig = {
761
880
  obj.material.clippingPlanes = clippingPlanes;
762
881
  obj.material.needsUpdate = true;
763
882
  // 将局部剖切的对象记录下来
883
+ if (flag) {
884
+ guiParams = {
885
+ 'x轴': clippingPlanes[0].constant,
886
+ 'y轴': clippingPlanes[2].constant,
887
+ 'z轴': clippingPlanes[1].constant
888
+ }
889
+ this.addClippingGui('局部剖切', {
890
+ x: Math.floor(boundingBox.min.x),
891
+ y: Math.floor(boundingBox.min.z),
892
+ z: Math.floor(boundingBox.min.y)
893
+ }, obj.material.clippingPlanes)
894
+ // cube.material.clippingPlanes
895
+ };
896
+ return {
897
+ min: boundingBox.min,
898
+ max: boundingBox.max,
899
+ }
764
900
  },
765
901
  // 更新局部剖切的值
766
902
  /*
@@ -773,14 +909,43 @@ var roamConfig = {
773
909
  y: 1,
774
910
  z: 2,
775
911
  };
912
+ let obj = clippingMesh[clippingMesh.length - 1]
776
913
  for (const key in params) {
777
- clippingPlanes[axis[key]].constant = params[key];
914
+ obj.material.clippingPlanes[axis[key]].constant = params[key];
915
+ obj.material.needsUpdate = true;
778
916
  }
779
917
  // this.timeRender()
780
918
  },
781
919
  // 取消局部/单个实体的剖切
782
920
  cancelLocalClipping() {
783
- clippingPlanes = Object.freeze([]);
921
+ guiParams = {
922
+ 'x轴': 0,
923
+ 'y轴': 0,
924
+ 'z轴': 0
925
+ };
926
+ gui && gui.destroy();
927
+ clippingMesh.forEach(item => {
928
+ item.material.clippingPlanes = Object.freeze([])
929
+ item.material.needsUpdate = true
930
+ })
931
+ clippingMesh.splice(0)
932
+ },
933
+ // 添加剖切轴工具
934
+ addClippingGui(title, minValue, objClipp1, objClipp2) {
935
+ gui = new GUI({
936
+ title: title
937
+ })
938
+ gui.add(guiParams, 'x轴').min(minValue.x).max(Math.abs(guiParams['x轴'])).onChange(d => {
939
+ objClipp1[0].constant = d
940
+ objClipp2 && (objClipp2[0].constant = d)
941
+ })
942
+ gui.add(guiParams, 'y轴').min(minValue.y).max(Math.abs(guiParams['y轴'])).onChange(d => {
943
+ objClipp1[2].constant = d
944
+ objClipp2 && (objClipp2[2].constant = d)
945
+ })
946
+ gui.add(guiParams, 'z轴').min(minValue.z).max(Math.abs(guiParams['z轴'])).onChange(d => {
947
+ objClipp1[1].constant = d
948
+ })
784
949
  },
785
950
  // 开启第一视角
786
951
  startFirstPer() {
@@ -936,9 +1101,9 @@ var roamConfig = {
936
1101
  },
937
1102
  // 返回主视角/恢复相机初始状态
938
1103
  home() {
939
- // if (roaming) {
940
- // this.disposeRoaming()
941
- // }
1104
+ if (roaming) {
1105
+ this.endRoam()
1106
+ }
942
1107
  cameraControls.reset(true);
943
1108
  cameraControls.update(0);
944
1109
  // this.timeRender()
@@ -1104,7 +1269,7 @@ var roamConfig = {
1104
1269
  animate() {
1105
1270
  const delta = fpsClock.getDelta();
1106
1271
  timeStamp += delta;
1107
- requestAnimationFrame(this.animate);
1272
+ animateId = requestAnimationFrame(this.animate);
1108
1273
  cameraControls.enabled && cameraControls.update(timeStamp);
1109
1274
  this.cameraTrack();
1110
1275
  this.firstPerspective();
@@ -36,7 +36,7 @@
36
36
  </template>
37
37
  <script>
38
38
  export default {
39
- name: 'PerControl',
39
+ name: 'FLPerControl',
40
40
  data() {
41
41
  return {};
42
42
  },
package/src/main.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import FlModel from '../packages/components/com-graphics/index.vue';
2
2
  import Fl2dcanvas from '../packages/components/com-flcanvas/index.vue';
3
+ import FLPerControl from '../packages/components/com-graphics/per-control.vue';
3
4
  import * as THREE from 'three';
4
5
  const components = [
5
6
  FlModel,
6
- Fl2dcanvas
7
+ Fl2dcanvas,
8
+ FLPerControl
7
9
  ];
8
10
 
9
11
  const install = (Vue) => {
@@ -21,5 +23,6 @@ if (typeof window !== 'undefined' && window.Vue) {
21
23
  export default {
22
24
  install,
23
25
  FlModel,
24
- Fl2dcanvas
26
+ Fl2dcanvas,
27
+ FLPerControl
25
28
  };
@@ -45,7 +45,6 @@ function handleInstancedMeshModel(instances, drawObjs, type, scene, customColor,
45
45
  if (drawObjectName) {
46
46
  targetGroup = scene.getObjectByName(drawObjectName);
47
47
  }
48
-
49
48
  if (!targetGroup) {
50
49
  const drawObj = drawObjMapInstance[instances[i].drawObject];
51
50
  const group = new THREE.Group();
@@ -63,16 +62,19 @@ function handleInstancedMeshModel(instances, drawObjs, type, scene, customColor,
63
62
  model.userData[key] = meshNameConfig[key]
64
63
  meshName += ':' + meshNameConfig[key]
65
64
  }
66
- drawObj.MapInstance.forEach((instance, index) => {
67
- if (instance.instanceId == instances[i].instanceId) {
65
+ drawObj.MapInstance.forEach((item, index) => {
66
+ if (item.instanceId == instances[i].instanceId) {
68
67
  model.userData.instanceIndex = index;
68
+ model.userData.instanceId = instances[i].instanceId
69
69
  model.name = meshName !== '' ? (instances[i].instanceId + meshName) : instances[i].instanceId;
70
- const matrixVal = instance.matrix?.val;
70
+ const matrixVal = item.matrix?.val;
71
71
  if (matrixVal) {
72
72
  const m4 = new THREE.Matrix4();
73
73
  // m4.setPosition(new THREE.Vector3(9999999, 9999999, 9999999)); // TODO 临时隐藏方案
74
- m4.elements = instance.matrix.val;
74
+ m4.elements = item.matrix.val;
75
75
  model.setMatrixAt(index, m4);
76
+ const copyMatrix = new THREE.Matrix4().copy(m4);
77
+ model.userData.copyMatrix = copyMatrix;
76
78
  }
77
79
  // 需要先设置全部实例颜色,否则后续设置颜色无效
78
80
  const { color } = mesh.prop;
@@ -393,7 +395,6 @@ function drawText(geom, instanceName, instanceCount) {
393
395
  mesh.translateY(-(fontsize / 2.5));
394
396
 
395
397
  mesh.userData.instanceName = instanceName;
396
-
397
398
  return mesh;
398
399
  }
399
400
 
File without changes