1

引言

因为业务需要,需要展示3D文件,之前我已经写了一个 three.js 来渲染3D数据的方案,本来以为可以直接拿来用,但是甲方那边需要后另外一个业务用同样的技术路线 online-3d-viewer (就是对 three.js 进行了二次封装) ,只好从他们项目里面拿来借鉴一下,但是因为一个api的差异,导致我被卡了一天,在这里记录一下,如果各位大佬有其他的更好的解决办法,欢迎回复。

实践过程

一开始我拿过来的代码觉得是可以直接使用的,但是在一开始就出了问题,原来的你代码里面很多函数都有问题,感觉那边项目的不知道从哪里copy来的代码,没有根据库的版本进行修改,很多方法已经不支持了。。这都是小事,去看了源码之后都找到了相应的替换方法。

但是在获取数据的时候出了一个问题,在原来的逻辑里面,获取数据是通过api直接拿到一个zip文件的,这里有一个问题就是,他们项目这个接口是不需要token的,公共数据,可以直接拿到,我项目里面是需要权限才可以获取数据,直接时使用url会出问题

// 原代码
import * as OV from 'online-3d-viewer';

...

const inputEle = useRef(null)

const url = [`/api/public/file/download.zip?fileId=${el.media3D.documents}`]

const load3d = () => {
      // tell the engine where to find the libs folder
      OV.SetExternalLibLocation ('build/libs');
      // initialize the viewer with the parent element and some parameters
      let viewer = new OV.EmbeddedViewer (inputEle.current, {
        // 观看视角
        camera : new OV.Camera (
          new OV.Coord3D (-1.5, -3.0, 2.0),
          new OV.Coord3D (0.0, 0.0, 0.0),
          new OV.Coord3D (0.0, 0.0, 1.0)
        ),
        // 背景颜色
        backgroundColor : new OV.Color (255, 255, 255),
        defaultColor : new OV.Color (200, 200, 200),
        // 边框设置
        edgeSettings : {
          showEdges : false,
          edgeColor : new OV.Color (0, 0, 0),
          edgeThreshold : 1
        },
        // 背景图片设置
        environmentMap : [],
        // onModelLoaded : () => {
        //   let model = viewer.GetModel ();
        //   // do something with the model
        // }
      });
      
      // load a model providing model urls DamagedHelmet
        
      viewer.LoadModelFromUrls (url); 
    }
    if (inputEle.current) {
      load3d()
    }
}
...
<div ref={inputEle} style={{ width: '100%', height: '650px' }}></div>

在上面的代码里面,OV 的方法基本都有问题, 因为用的库版本是 "online-3d-viewer": "^0.8.17", 所以里面的方法要替换成

OV.Color  => OV.RGBColor
OV.LoadModelFromUrls  => OV.LoadModelFromUrlList

实现代码

从上面的我们可以看到,用的方法是 LoadModelFromUrlList ,从翻译就能看出要的是url列表,而我们的接口由于需要权限,所以在这里是不适用的,只好去翻找源码,然后就看到了下面的部分

LoadModelFromUrlList (modelUrls)
    {
        TransformFileHostUrls (modelUrls);
        let inputFiles = InputFilesFromUrls (modelUrls);
        this.LoadModelFromInputFiles (inputFiles);
    }

从上面的代码可以看出,他使用url也是获取数据之后调用了内部的 LoadModelFromInputFiles 方法去执行文件,那我可以直接自己获取文件然后运行啊,因此就有了下面的修改,最后实现了功能。

// 通过接口获取文件的blob
const res = await FileService.downloadZipForPreview(fileId)
let blob = new Blob([res], {
  type: '',
})
// 通过File 将流转换成文件
let files = await new File([blob], 'xxx.zip', {
  type: 'application/zip',
})
// 给现在的文件对象添加一些字段,这些字段是后面的函数处理步骤种需要用到的,
// 直接使用file会因为参数缺失导致错误,这部分是关键
files.data = res
// 定义文件类型,
// { Url : 1, File : 2,Decompressed : 3 }
files.source = 2
viewer.LoadModelFromInputFiles([files])

Cyearn
64 声望2 粉丝