UNPKG

paraview-glance

Version:

Web application for Visualizing Scientific and Medical datasets

315 lines (279 loc) 8.58 kB
import vtkHttpDataAccessHelper from 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper'; import { createRepresentationInAllViews } from 'paraview-glance/src/utils'; const READER_MAPPING = {}; const FETCH_DATA = { readAsArrayBuffer(url, options) { return vtkHttpDataAccessHelper.fetchBinary(url, options); }, readAsText(url, options) { return vtkHttpDataAccessHelper.fetchText({}, url, options); }, }; function registerReader({ extension, name, vtkReader, readMethod, parseMethod, fileNameMethod, fileSeriesMethod, sourceType, binary, }) { READER_MAPPING[extension] = { name, vtkReader, readMethod: readMethod || binary ? 'readAsArrayBuffer' : 'readAsText', parseMethod: parseMethod || binary ? 'parseAsArrayBuffer' : 'parseAsText', fileNameMethod, fileSeriesMethod, sourceType, }; } function getReader({ name }) { const lowerCaseName = name.toLowerCase(); const extToUse = Object.keys(READER_MAPPING).find((ext) => lowerCaseName.endsWith(ext) ); return READER_MAPPING[extToUse]; } function listReaders() { return Object.keys(READER_MAPPING).map((ext) => ({ name: READER_MAPPING[ext].name, ext, })); } function listSupportedExtensions() { return Object.keys(READER_MAPPING); } // ---------------------------------------------------------------------------- let filesCallback = null; function handleFile(e) { if (filesCallback) { filesCallback(e.target.files); } filesCallback = null; } const HIDDEN_FILE_ELEMENT = document.createElement('input'); HIDDEN_FILE_ELEMENT.setAttribute('type', 'file'); HIDDEN_FILE_ELEMENT.setAttribute('multiple', 'multiple'); HIDDEN_FILE_ELEMENT.addEventListener('change', handleFile); // ---------------------------------------------------------------------------- function openFiles(extensions, onFilesCallback) { filesCallback = onFilesCallback; HIDDEN_FILE_ELEMENT.setAttribute( 'accept', extensions.map((t) => `.${t}`).join(',') ); HIDDEN_FILE_ELEMENT.value = null; HIDDEN_FILE_ELEMENT.click(); } // ---------------------------------------------------------------------------- function readRawData({ fileName, data }) { return new Promise((resolve, reject) => { const readerMapping = getReader({ name: fileName }); if (readerMapping) { const { vtkReader, parseMethod, fileNameMethod, sourceType, } = readerMapping; const reader = vtkReader.newInstance(); if (fileNameMethod) { reader[fileNameMethod](fileName); } try { const ds = reader[parseMethod](data); Promise.resolve(ds) .then((dataset) => resolve({ dataset, reader, sourceType, name: fileName }) ) .catch(reject); } catch (e) { reject(e); } } else { reject(new Error('No reader mapping')); } }); } // ---------------------------------------------------------------------------- function readFile(file) { return new Promise((resolve, reject) => { const readerMapping = getReader(file); if (readerMapping) { const { readMethod } = readerMapping; const io = new FileReader(); io.onload = function onLoad() { readRawData({ fileName: file.name, data: io.result }) .then((result) => resolve(result)) .catch((error) => reject(error)); }; io[readMethod](file); } else { reject(new Error('No reader mapping')); } }); } // ---------------------------------------------------------------------------- function loadFiles(files) { const promises = []; for (let i = 0; i < files.length; i += 1) { promises.push(readFile(files[i])); } return Promise.all(promises); } // ---------------------------------------------------------------------------- function loadFileSeries(files, extension, outFileName = '') { return new Promise((resolve, reject) => { if (files.length) { const readerMapping = READER_MAPPING[extension]; if (readerMapping) { const { vtkReader, fileSeriesMethod, fileNameMethod, sourceType, } = readerMapping; const reader = vtkReader.newInstance(); if (fileNameMethod) { reader[fileNameMethod](outFileName); } if (fileSeriesMethod) { const ds = reader[fileSeriesMethod](files); Promise.resolve(ds).then((dataset) => resolve({ dataset, reader, sourceType, name: outFileName }) ); } else { reject(new Error('No file series method available')); } } else { reject(new Error(`No file series reader mapping for ${extension}`)); } } else { resolve(/* empty */); } }); } // ---------------------------------------------------------------------------- function downloadDataset(fileName, url, options = {}) { return new Promise((resolve, reject) => { const readerMapping = getReader({ name: fileName }); if (readerMapping) { const { readMethod } = readerMapping; FETCH_DATA[readMethod](url, options) .then((rawData) => { if (rawData) { resolve(new File([rawData], fileName)); } else { throw new Error(`No data for ${fileName}`); } }) .catch(reject); } else { throw new Error(`No reader found for ${fileName}`); } }); } // ---------------------------------------------------------------------------- function registerReadersToProxyManager(readers, proxyManager) { const retlist = []; for (let i = 0; i < readers.length; i += 1) { const { reader, sourceType, name, dataset, metadata, proxyKeys } = readers[ i ]; let retsource = null; if (reader || dataset) { const needSource = (reader && reader.getOutputData) || (dataset && dataset.isA && dataset.isA('vtkDataSet')); let proxyName = 'TrivialProducer'; if ( proxyKeys && proxyKeys.meta && proxyKeys.meta.glanceDataType === 'vtkLabelMap' ) { proxyName = 'LabelMap'; } const source = needSource ? proxyManager.createProxy('Sources', proxyName, { name, ...metadata, }) : null; if (dataset && dataset.isA && dataset.isA('vtkDataSet')) { source.setInputData(dataset, sourceType); } else if (reader && reader.getOutputData) { source.setInputAlgorithm(reader, sourceType); } else if (reader && reader.setProxyManager) { reader.setProxyManager(proxyManager); } else { console.error(`No proper reader handler was found for ${name}`); } if (source) { createRepresentationInAllViews(proxyManager, source); if (proxyKeys) { Object.keys(proxyKeys).forEach((key) => { source.setKey(key, proxyKeys[key]); if (key === 'onLoad') { proxyKeys[key](source); } }); } } if ( reader && reader.getCameraViewPoints && reader.getCameraViewPoints() ) { proxyManager .getReferenceByName('$store') .dispatch('setCameraViewPoints', reader.getCameraViewPoints()); } retsource = source; } retlist.push(retsource); } proxyManager.renderAllViews(); return retlist; } // ---------------------------------------------------------------------------- function importBase64Dataset( fileName, base64String, proxyManager, chunkSize = 512 ) { const chunks = []; const bytes = atob(base64String); for (let offset = 0; offset < bytes.length; offset += chunkSize) { const slice = bytes.slice(offset, offset + chunkSize); const array = new Uint8Array(slice.length); for (let i = 0; i < slice.length; i++) { array[i] = slice.charCodeAt(i); } chunks.push(array); } const blob = new Blob(chunks, { type: 'application/octet-stream' }); const file = new File([blob], fileName); if (proxyManager) { loadFiles([file]).then((readers) => { registerReadersToProxyManager(readers, proxyManager); }); return Promise.resolve('loading'); } return loadFiles([file]); } // ---------------------------------------------------------------------------- export default { downloadDataset, listReaders, listSupportedExtensions, importBase64Dataset, loadFiles, loadFileSeries, openFiles, registerReader, registerReadersToProxyManager, };