UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

219 lines (197 loc) 6.24 kB
import { m as macro } from '../../macros2.js'; import ImageHelper from '../../Common/Core/ImageHelper.js'; import vtkTexture from '../../Rendering/Core/Texture.js'; import { unzipSync, strFromU8 } from 'fflate'; // ---------------------------------------------------------------------------- // vtkSkyboxReader methods // ---------------------------------------------------------------------------- function vtkSkyboxReader(publicAPI, model) { // Set our className model.classHierarchy.push('vtkSkyboxReader'); // Internal method to fetch Array function fetchData(url, option = {}) { const { compression, progressCallback } = model; return model.dataAccessHelper.fetchBinary(url, { compression, progressCallback }); } // Set DataSet url publicAPI.setUrl = (url, option = {}) => { model.url = url; // Fetch metadata return publicAPI.loadData(option); }; // Fetch the actual data arrays publicAPI.loadData = (option = {}) => fetchData(model.url, option).then(publicAPI.parseAsArrayBuffer); publicAPI.parseAsArrayBuffer = content => { if (!content) { return false; } model.textures = {}; model.busy = true; publicAPI.invokeBusy(model.busy); model.dataMapping = {}; const imageReady = []; // Finish data processing function workDone() { for (let i = 0; i < model.positions.length; i++) { const key = model.positions[i]; const images = model.dataMapping[key]; if (!model.textures[key]) { model.textures[key] = vtkTexture.newInstance({ interpolate: true }); } if (images) { const texture = model.textures[key]; for (let idx = 0; idx < 6; idx++) { const { fileName, transform } = model.faceMapping[idx]; const readyIndex = imageReady.indexOf(`${key}/${fileName}`); if (readyIndex !== -1) { texture.setInputData(ImageHelper.imageToImageData(images[fileName], transform), idx); // Free image URL.revokeObjectURL(images[fileName].src); delete images[fileName]; // Don't process again imageReady.splice(readyIndex, 1); } } } } model.busy = false; publicAPI.modified(); publicAPI.invokeBusy(model.busy); } const decompressedFiles = unzipSync(new Uint8Array(content)); const pending = []; // Find root index.json Object.entries(decompressedFiles).forEach(([relativePath, fileData]) => { if (relativePath.match(/index.json$/)) { const txt = strFromU8(fileData); const config = JSON.parse(txt); if (config.skybox && config.skybox.faceMapping) { model.faceMapping = config.skybox.faceMapping; } if (config.metadata && config.metadata.skybox && config.metadata.skybox.faceMapping) { model.faceMapping = config.metadata.skybox.faceMapping; } } if (relativePath.match(/\.jpg$/)) { const pathTokens = relativePath.split('/'); const fileName = pathTokens.pop(); const key = pathTokens.pop(); if (!model.dataMapping[key]) { model.dataMapping[key] = {}; } const blob = new Blob([fileData.buffer]); const img = new Image(); const readyKey = `${key}/${fileName}`; model.dataMapping[key][fileName] = img; pending.push(new Promise(resolve => { img.onload = () => { imageReady.push(readyKey); resolve(); }; })); img.src = URL.createObjectURL(blob); } }); model.positions = Object.keys(model.dataMapping); model.position = model.positions[0]; Promise.all(pending).then(() => { workDone(); }); return publicAPI.getReadyPromise(); }; publicAPI.requestData = (inData, outData) => { outData[0] = model.textures[model.position]; }; publicAPI.setPosition = name => { if (model.positions.indexOf(name) !== -1 && name !== model.position) { model.position = name; publicAPI.modified(); } }; publicAPI.getReadyPromise = () => { if (!model.busy) { return Promise.resolve(publicAPI); } return new Promise((resolve, reject) => { const subscription = publicAPI.onBusy(isBusy => { if (!isBusy) { subscription.unsubscribe(); resolve(publicAPI); } }); }); }; // return Busy state publicAPI.isBusy = () => model.busy; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = { // url: null, busy: false, // everything must be flipped in Y due to canvas // versus vtk ordering faceMapping: [{ fileName: 'right.jpg', transform: { flipY: true } }, { fileName: 'left.jpg', transform: { flipY: true } }, { fileName: 'up.jpg', transform: { flipY: true } }, { fileName: 'down.jpg', transform: { flipY: true } }, { fileName: 'back.jpg', transform: { flipY: true } }, { fileName: 'front.jpg', transform: { flipY: true } }] }; // ---------------------------------------------------------------------------- function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API macro.obj(publicAPI, model); macro.get(publicAPI, model, ['url', 'positions', 'position']); macro.setGet(publicAPI, model, ['faceMapping']); macro.event(publicAPI, model, 'busy'); macro.algo(publicAPI, model, 0, 6); // Object methods vtkSkyboxReader(publicAPI, model); } // ---------------------------------------------------------------------------- const newInstance = macro.newInstance(extend, 'vtkSkyboxReader'); // ---------------------------------------------------------------------------- var vtkSkyboxReader$1 = { newInstance, extend }; export { vtkSkyboxReader$1 as default, extend, newInstance };