JSZip 是一款能够建立、读取、修改 .zip 文件的 javaScript 工具。在 web 应用中,免不了须要从 web 服务器中获取资源,若是能够将全部的资源都合并到一个 .zip 文件中,这时候只须要作一次请求,这样既减小了服务器的压力,同时也能够加快 web 应用的呈现速度。
今天就来探讨下 JSZip 如何与 HT 拓扑应用结合。先来看看这期 Demo 的效果图:
第一步、须要将应用对相关资源打包成 .zip 文件,
这是我要压缩的文件列表,把响应的资源文件存放到对应的文件夹下,而后在 loadorder 文件中标明资源加载的顺序,loadorder 文件内容以下:html
'js/ht.js', 'js/ht-obj.js', 'js/ht-modeling.js', 'obj/equipment.mtl', 'obj/equipment.obj', 'image/equipment.jpg'
在资源加载顺序中,要标明响应资源的相对于 .zip 文件的路径,这样方便在读取 .zip 文件时快速找到相应的资源文件。
第二步、在 html 文件中引入 JSZip 和 JSZipUtils 库,接下来就是请求 .zip 文件,并对 .zip 文件作解析处理。java
JSZipUtils.getBinaryContent('res/ImportObj.zip', function(err, data) { if(err) { throw err; // or handle err } var zip = new JSZip(data); var loadorderStr = zip.file('loadorder').asText(), order; eval('order = [' + loadorderStr + ']'); var len = order.length, image = {}, mtlStr = '', objStr = ''; for(var i = 0; i < len; i++) { var fileName = order[i]; if(fileName.indexOf('js/') >= 0) { var js = document.createElement('script'); js.innerHTML = zip.file(fileName).asText(); document.getElementsByTagName('head')[0].appendChild(js); } else if(fileName.indexOf('image/') >= 0) { var buffer = zip.file(fileName).asArrayBuffer(), str = _arrayBufferToBase64(buffer), pIndex = fileName.indexOf('.'), type = fileName.substr(pIndex + 1), re = 'data:image/' + type + ';base64,'; image[fileName] = re + str; } else if(fileName.indexOf('obj/') >= 0) { var str = zip.file(fileName).asText(); if(fileName.indexOf('.mtl') > 0) { mtlStr = str; } else if(fileName.indexOf('.obj') > 0) { objStr = str; } } } init(objStr, mtlStr, image); });
首先经过 JSZipUtils 获取 .zip 文件,将获取到的文件内容经过 new JSZip(data) 方法加载到 zip 变量中,经过 zip.file(fileName) 读取 loadorder 文件内容,试用 eval 命令动态执行脚本,将文本内容转换为 js 变量 order,最后经过遍历 order 变量,将 js 资源动态引入到页面中。
在 .zip 文件中有包含图片文件,JSZip 只能获取到图片文件的 ArrayBuffer 数据,这时须要将 ArrayBuffer 转换为 Base64 才可以为浏览器所识别,因此这里定义了一个转换函数:_arrayBufferToBase64node
function _arrayBufferToBase64( buffer ) { var binary = ''; var bytes = new Uint8Array( buffer ); var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode( bytes[ i ] ); } return window.btoa( binary ); }
此次的案例中,有涉及到 3D 模型数据与 HT 3D 拓扑应用的结合,在 .zip 文件中的 obj 目录就是存放 3D 模型数据,在文件读取中,将 3D 模型数据以文本对形势读取出来存放到变量中,再将数据传递到 init 函数中,经过 ht.Default.parseObj() 方法将 3D 模型数据加载到 HT 中。git
function init(objStr, mtlStr, image) { dataModel = new ht.DataModel(); g3d = new ht.graph3d.Graph3dView(dataModel); view = g3d.getView(); view.className = 'main'; document.body.appendChild(view); window.addEventListener('resize', function (e) { g3d.invalidate(); }, false); g3d.setEye([0, 500, 1000]); g3d.setCenter([0, 200, 0]); g3d.setGridVisible(true); g3d.setGridColor('#74AADA'); var param = { shape3d: 'E1', center: true, cube: true }; var modelMap = ht.Default.parseObj(objStr, mtlStr, param); for(var model in modelMap) { var map = modelMap[model], i = map.image, index = i.lastIndexOf('/'), fileName = i.substr(index + 1), rawS3 = map.rawS3; for(var imgName in image) { if(imgName.indexOf(fileName) >= 0) { ht.Default.setImage(i, 256, 256, image[imgName]); } } } var node = new ht.Node(); node.s({ 'shape3d': 'E1', 'wf.visible': 'selected', 'wf.width': 3, 'wf.color': '#F7F691' }); node.s3(param.rawS3); node.p3(0, param.rawS3[1]/2, 0); dataModel.add(node); }
上述是生成 3D 拓扑、3D 模型引入和引用 3D 模型建立拓扑节点的代码。其中那段 setImage 的代码须要特别注意,为何我要大费周张的去判断 image 的文件名呢,那是由于在 mtl 3D 模型描述文件中有一个设置贴图的属性,该属性能够指定文件的绝对路径,也能够指定文件的相对路径,由于采用 JSZip 没法将 .zip 中的文件内容写回到本地目录中,因此只能将贴图属性对应的属性名称做为 HT 中的 image 名称设置到 HT 中,以便 HT 模型加载的时候可以获取获得模型所须要的图片资源。HT 3D 拓扑的应用能够参考《3D拓扑自动布局之Node.js篇》。
JSZip 在压缩或解压数据的时候,若是出现速度较慢的状况,能够考虑使用 Web Worker,Web Worker的具体应用能够参考《3D拓扑自动布局之Web Workers篇》。github