three.js3D地图省市下钻加上钻踩坑记录

 

1,three 安装失败

首先脚手架种安装three,我不知道是网络问题还是什么,three我总是安装不上,

于是我就下载了网上别的博主得成品代码,把里面 de 包拿出来放在我自己项目中

安装包链接在此,如有需要自取 ,https://files.cnblogs.com/files/jickma/three.rar?t=1702967875&download=true

解压之后直接替换本地 node_modules 包中未完成安装得包即可使用,包的版本为 three  0.159.0

(由于安装包与 package中版本不同,造成一个问题 背景颜色与本地颜色差异过大,具体为什么不知道,更新版本之后可解决  详情 https://segmentfault.com/q/1010000044485869 )

 

 

 

2,地图由于加载不同文件 比如说中国地图,河南省地图,郑州市地图,由于经纬度差异比较大,所以会造成 地图大小不一问题,

如图 河南省很大,其中郑州市仅一小块,下钻之后,郑州市还是这么大,这个就是比例不对问题,

 

     

 

地图下钻比例问题修改如下

 1 // 地图模型
 2     addMapGeometry(jsondata) {
 3       // 初始化一个地图对象
 4       this.map = new THREE.Object3D();
 5       // 墨卡托投影转换
 6       const { averageCoordinate, scaleMin } = this.getCenterMap(jsondata);
 7       const projection = d3
 8         .geoMercator()
 9         .center(averageCoordinate)
10         .scale(scaleMin * 0.5725)
11         .translate([1, -0.4]); // 根据地球贴图做轻微调整
12       jsondata.features.forEach((elem) => {
13         // 各种循环地图加载模块
14         /***你得代码 **** */
        // province.scale.set(0.1, 0.1, 0.1);
15       });
16     },
 1 // 计算中心点坐标,获取经纬度最大最小值缩放比例
 2     getCenterMap(jsondata) {
 3       let minLat = Infinity;
 4       let maxLat = -Infinity;
 5       let minLon = Infinity;
 6       let maxLon = -Infinity;
 7       // 获取所有坐标点
 8       const allCoordinates = [];
 9       jsondata.features.forEach((elem) => {
10         const coordinates = elem.geometry.coordinates;
11         coordinates.forEach((multiPolygon) => {
12           multiPolygon.forEach((polygon) => {
13             allCoordinates.push(...polygon);
14             for (let i = 0; i < polygon.length; i++) {
15               const [x, y] = polygon[i];
16               minLat = Math.min(minLat, x);
17               maxLat = Math.max(maxLat, x);
18               minLon = Math.min(minLon, y);
19               maxLon = Math.max(maxLon, y);
20             }
21           });
22         });
23       });
24       this.container = document.getElementById("container");
25       const scaleX = this.container.clientWidth / (maxLat - minLat);
26       const scaleY = this.container.clientHeight / (maxLon - minLon);
27       const scaleMin = Math.min(scaleX, scaleY);
28       // 计算坐标点的平均值
29       const averageCoordinate = allCoordinates.reduce(
30         (acc, coordinate) => {
31           return [
32             acc[0] + coordinate[0] / allCoordinates.length,
33             acc[1] + coordinate[1] / allCoordinates.length,
34           ];
35         },
36         [0, 0]
37       );
38       return { averageCoordinate, scaleMin };
39     },

修改这个问题得根源在于 加载地图之前 将墨卡托投影 缩放直接给改了

而 修改得代码 就在  this.getCenterMap(jsondata)   获取缩放比例,将这个缩放比例 赋值给墨卡托即可完成地图大小不一问题 

千万不要在地图加载之后修改缩放比例,文本中红色代码,这样会造成地图缩放成功,但是别的地图上的文字或者图标什么得位置错误

代码还是有问题,暂时不知道如何解决  看链接  https://segmentfault.com/q/1010000044486494

 

 

 

 

3,地图初步测试成功之后,放进容器之后出现位置错误问题

因为是第一次使用 three。js 所以我就使用一个 空的div容纳我这个地图,而这个div 是直接放在 body 里面得,算是测试版 ,在测试之后,往界面中放进去时候出现了 位置错误问题

    

   

 

 

本来弹出来的省份名应该跟随鼠标位置的,现在却没有跟随,而我在测试代码中却好好的。根源在于取射线的位置不对 

测试代码是这样的, 代码第八行 使用了   window.innerWidth 而我放在容器之后 已经不是window了,因此出现位置不对情况

 1     
 2     // 射线
 3     setRaycaster() {
 4       this.raycaster = new THREE.Raycaster();
 5       this.mouse = new THREE.Vector2();
 6       this.tooltip = document.getElementById('tooltip');
 7       const onMouseMove = (event) => {
 8         this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
 9         this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
10         this.tooltip.style.left = event.clientX + 2 + 'px';
11         this.tooltip.style.top = event.clientY + 2 + 'px';
12       }
13       // 点击地图事件
14       const onClick = (event) => {
15         // console.log(this.lastPick);
16         if (this.lastPick && "point" in this.lastPick) this.mapClickTween(this.lastPick.point);
17         else this.resetCameraTween();
18       }
19       window.addEventListener('mousemove', onMouseMove, false);
20       window.addEventListener('click', onClick, false);
21     },

应修改为下边代码

 1     // 射线
 2     setRaycaster() {
 3       this.raycaster = new THREE.Raycaster();
 4       this.mouse = new THREE.Vector2();
 5       this.tooltip = document.getElementById("tooltip");
 6       const container = document.getElementById("container");
 7       const that = this;
 8       const onMouseMove = debounce((event) => {
 9         that.mouse.x = (event.offsetX / container.offsetWidth) * 2 - 1;
10         that.mouse.y = -(event.offsetY / container.offsetHeight) * 2 + 1;
11         that.tooltip.style.left = event.offsetX + 2 + "px";
12         that.tooltip.style.top = event.offsetY + 2 + "px";
13       }, 100);
14       // 点击地图事件
15       const onClick = (event) => {
16         /***别的代码 */
17       };
18       window.addEventListener("mousemove", onMouseMove, false);
19       window.addEventListener("click", onClick, false);
20     },

放在哪个元素里面, mouse.x 计算时候就应该修改为当前元素的  offsetWidth 

由此,可以推断出,测试代码中所有含有  window 的位置都有可能出问题,需要修改

这样的问题也是由于这个原因造成的

 

 

 

 

4,地图部署之后,无法加载json文件 

地图文件是一个json 然后下载之后放在 public中 (我也不知道为什么不放在 assets 中),看网上大佬都是放在这个里面的 我就跟着放进去了 

然后本地运行好好的,部署之后问题就来了 

1     // 加载地图数据
2     loadMapData() {
3       const loader = new THREE.FileLoader();
4       loader.load("/static/jsonMap/china.json", data => {
5         const jsondata = JSON.parse(data);
6         this.addMapGeometry(jsondata);
7       })
8     },

部署之后是访问不到   /static/jsonMap/china.json 这个json的,然后就会报代码循环错误 导致后边的地图无法加载,因为没有json

new THREE.FileLoader().load() 别的大佬都是这么访问的,我也跟着访问 后来由于发布之后无法正确访问 于是我就改成了这样
1     // 加载地图数据
2     loadMapData(str) {
4       this.resetInitMap();
5       let jsondata = require(`@/assets/json/${str || "china"}.json`);
6       this.addMapGeometry(jsondata);
7     },

因为地图本身就是一个对象数组结构的数据,我直接按照 vue 方式访问这个 json 传递到我得绘画地图函数中即可跳过这个步骤

 

 

 

 

5,地图下钻之后数据残留问题

由于地图需要下钻 展示中国,点击河南之后展示河南地图,这时候需要清除掉原本在场景的中国地图,以及中国地图上面各种点,线,等等各种渲染

 

仔细看可以发现这里是有两幅地图的,一副中国地图,一副河南地图,重叠在一起了。

这个时候就需要前端一贯的风格,秉承先清后加的原则 ,在加载地图之前 先清除掉地图然后在加上一副地图

 

1     // 加载地图数据
2     loadMapData(str) {
3       this.resetInitMap();
4       let jsondata = require(`@/assets/json/${str || "china"}.json`);
5       this.addMapGeometry(jsondata);
6     },

 

 1     resetInitMap() {
 2       let arr = []
 3       this.scene.children.forEach(ele => {
 4         if (ele.type != "Mesh" && ele.type != "Points") {
 5           arr.push(ele)
 6         }
 7       });
 8       this.scene.children = []
 9       let list = []
10       this.cityNumMeshArr = []
11       this.groupOne.children.forEach(el => {
12         if (el.type != "Object3D") {
13           list.push(el)
14         }
15       });
16       this.groupOne.children = []
17       if (this.map) {
18         this.scene.add(...arr)
19         this.groupOne.add(...list)
20       }
21       this.scene.remove(this.map);
22     },

同样的不止地图,还有地图上渲染的别的东西,我得地图中渲染了一些特效,是动态的,但是在下钻之后,动效不会动了,并且新的动效出来了,会重叠在一起,或者留有一些残影,等,

可以一并在重置中给干掉

 

 

 

 

 

 

threejs  里面坑还有很多,暂时只有这么多。欢迎大佬留言

 

posted @ 2024-01-23 09:16  马文庆i  阅读(527)  评论(0编辑  收藏  举报