1. 需求:
需要从本地文件选择一个规划模型的压缩包格式的文件并加载到地图上,达到可预览的效果,并且能够修改模型的大小、位置、姿态和高程等信息。
2. 技术调研
该项目是基于 ArcGIS API for JS 4.x开展,所以查看了官方API能够实现本地文件的加载,但是模型的href路径是本地路径。本人上一篇博客已经讲过,由于考虑到安全,浏览器无法使用input=file控件获取文件的绝对路径,只能获取文件本身和相对路径。
2.1 文件格式的调研
首先说下,GLB模型或者GLTF模型的区别与联系,两者都能可以使用3d max软件将.max模型使用工具转换成相应的格式。但是GLB格式的文件是单文件,贴图以及配置文件在一个文件里,本地加载相对来说比较简单,但是调整光线、配色以及其他比较麻烦(这是数据人员告诉我的)。开发经理推荐使用GLTF格式的文件进行上传,方便数据的处理。经过查阅相关资料发现,每个GTTF文件都有贴图、配置文件(.gtltf和.bin格式),且,gltf格式的文件其实就是一个json格式的,但是发现里面的图片配置都是相对 路径,如果想通过input上传文件方式,在线预览时,获取的图片的“网络”路径就会改变,此时需要读取本地的.gltf文件并依次修改图片的路径和配置文件的路径。下图为解压的一个gltf模型的压缩包的文件展示图。
2.2 压缩文件的本地预览工具
由于项目是采用vue3+vue-cli框架进行开发的,使用JSZip插件能够完全前端压缩文件的读取,然后采用上篇博客的预览,并重新修改gltf文件的路径。具体的该插件的使用介绍不做说明,请查看《前端解压压缩包(zip)解压后上传解压的文件》该博客。
2.3 其他的相关资料参考
由于网上很多加载gltf的文章都是ArcGIS 官方网站的示例代码,所以参考意义不大,因为他们都直接把模型放到工程里或者直接写固定的路径,难以满足本地选取文件的要求。最终查看了《Cesium加载zip文件中的GLTF模型》这篇博客,有了启发。
3.代码实现
由于代码的篇幅较长,本文仅展示关键代码。
3.1 本地压缩文件的读取
// 需要读取的所有文件
const pendings = [];
// 文件Map,文件名对应url
const fileMap = {};
// zip文件中的gltf文件的entry(JSZip中读取文件的方法)
let gltfEntry = null;
// zip文件中gltf文件名
let gltfFileName = "";
const promise = JSZip.external.Promise;
const zip = new JSZip();
// 读取zip文件
const zipData = await zip.loadAsync(file);
// 遍历zip中的所有文件,生成fileMap
for (let file in zipData.files) {
const entry = zipData.file(file);
//这里是判断是否是文件夹,如果是文件夹就结束本次循环
if (entry === null) {
filePath = file;
continue;
}
//判断是否包含该文件
if (file.includes(".gltf")) {
gltfEntry = entry;
gltfFileName = file;
}
// push需要加载的文件
pendings.push(
entry.async("blob").then((blob) => {
// 生成url并放进fileMap
fileMap[file] = URL.createObjectURL(blob);
})
);
}
// 等待加载文件
await promise.all(pendings);
3.2 .gltf格式文件的处理
const res = await gltfEntry.async("string");
const gltfJson = JSON.parse(res);
// 修改buffers和纹理的uri(这里需要注意)
gltfJson.buffers.forEach((item) => {
item.uri = fileMap[filePath + item.uri];
});
gltfJson.images.forEach((item) => {
item.uri = fileMap[filePath + item.uri];
});
// 更新fileMap中gltf文件url
fileMap[gltfFileName] = URL.createObjectURL(
new Blob([JSON.stringify(gltfJson)])
);
3.3 将模型预览加载到地图上
sketchVM.pointSymbol = {
type: "point-3d",
symbolLayers: [
{
type: "object",
resource: {
href: fileMap[gltfFileName],
},
},
],
};
//创建点
sketchVM.create("point");
sketchVM.on("create", (event) => {
if (event.state === "complete") {
sketchVM.update(event.graphic);
}
});
//监听放置完成,获取得到模型的信息
sketchVM.on("update", (event) => {if (event.state === "complete") {
//获取到当前图层的位置信息和姿态信息(用于定姿态定位置)
let graphic = event.graphics[0];
modelInfo.x = graphic.geometry.x;
modelInfo.y = graphic.geometry.y;
modelInfo.z = graphic.geometry.z;
modelInfo.heading =
graphic.symbol.symbolLayers.items[0].heading || -999;
modelInfo.width =
graphic.symbol.symbolLayers.items[0].width || -999;
}})
3.4 将模型上传到服务器,上传的文件为原文件,不是处理的文件
该过程比较简单,省略
4.小结
以上就是基于ArcGIS API for JS完成的模型本地预览和定姿定位信息的获取。本人也不是非常精通,如果有错误或疑问欢迎交流。