import { decompressSync, strFromU8 } from 'fflate';
import macro from 'vtk.js/Sources/macros'; import Endian from 'vtk.js/Sources/Common/Core/Endian'; import { DataTypeByteSize } from 'vtk.js/Sources/Common/Core/DataArray/Constants'; import { registerType } from 'vtk.js/Sources/IO/Core/DataAccessHelper';
const { vtkErrorMacro, vtkDebugMacro } = macro;
let requestCount = 0;
function openAsyncXHR(method, url, options = {}) { const xhr = new XMLHttpRequest(); xhr.open(method, url, true);
if (options.headers) { Object.entries(options.headers).forEach(([key, value]) => xhr.setRequestHeader(key, value) ); }
if (options.progressCallback) { xhr.addEventListener('progress', options.progressCallback); }
return xhr; }
function fetchBinary(url, options = {}) { if (options && options.compression && options.compression !== 'gz') { vtkErrorMacro('Supported algorithms are: [gz]'); vtkErrorMacro(`Unkown compression algorithm: ${options.compression}`); }
return new Promise((resolve, reject) => { const xhr = openAsyncXHR('GET', url, options);
xhr.onreadystatechange = (e) => { if (xhr.readyState === 4) { if (xhr.status === 200 || xhr.status === 0) { if (options.compression) { resolve(decompressSync(new Uint8Array(xhr.response)).buffer); } else { resolve(xhr.response); } } else { reject({ xhr, e }); } } };
xhr.responseType = 'arraybuffer'; xhr.send(); }); }
function fetchArray(instance, baseURL, array, options = {}) { if (array.ref && !array.ref.pending) { return new Promise((resolve, reject) => { let url = null;
if (array.ref.url) { url = array.ref.url; } else { url = [ baseURL, array.ref.basepath, options.compression ? `${array.ref.id}.gz` : array.ref.id, ].join('/'); }
const xhr = openAsyncXHR('GET', url, options);
xhr.onreadystatechange = (e) => { if (xhr.readyState === 1) { array.ref.pending = true; if (++requestCount === 1 && instance?.invokeBusy) { instance.invokeBusy(true); } } if (xhr.readyState === 4) { array.ref.pending = false; if (xhr.status === 200 || xhr.status === 0) { array.buffer = xhr.response;
if (options.compression) { if (array.dataType === 'string' || array.dataType === 'JSON') { array.buffer = strFromU8( decompressSync(new Uint8Array(array.buffer)) ); } else { array.buffer = decompressSync( new Uint8Array(array.buffer) ).buffer; } }
if (array.ref.encode === 'JSON') { array.values = JSON.parse(array.buffer); } else { if (Endian.ENDIANNESS !== array.ref.encode && Endian.ENDIANNESS) { vtkDebugMacro(`Swap bytes of ${array.name}`); Endian.swapBytes( array.buffer, DataTypeByteSize[array.dataType] ); }
array.values = macro.newTypedArray(array.dataType, array.buffer); }
if (array.values.length !== array.size) { vtkErrorMacro( `Error in FetchArray: ${array.name}, does not have the proper array size. Got ${array.values.length}, instead of ${array.size}` ); }
delete array.ref; if (--requestCount === 0 && instance?.invokeBusy) { instance.invokeBusy(false); } if (instance?.modified) { instance.modified(); } resolve(array); } else { reject({ xhr, e }); } } };
xhr.responseType = options.compression || array.dataType !== 'string' ? 'arraybuffer' : 'text'; xhr.send(); }); }
return Promise.resolve(array); }
function fetchJSON(instance, url, options = {}) { return new Promise((resolve, reject) => { const xhr = openAsyncXHR('GET', url, options);
xhr.onreadystatechange = (e) => { if (xhr.readyState === 1) { if (++requestCount === 1 && instance?.invokeBusy) { instance.invokeBusy(true); } } if (xhr.readyState === 4) { if (--requestCount === 0 && instance?.invokeBusy) { instance.invokeBusy(false); } if (xhr.status === 200 || xhr.status === 0) { if (options.compression) { resolve( JSON.parse( strFromU8(decompressSync(new Uint8Array(xhr.response))) ) ); } else { resolve(JSON.parse(xhr.responseText)); } } else { reject({ xhr, e }); } } };
xhr.responseType = options.compression ? 'arraybuffer' : 'text'; xhr.send(); }); }
function fetchText(instance, url, options = {}) { if (options && options.compression && options.compression !== 'gz') { vtkErrorMacro('Supported algorithms are: [gz]'); vtkErrorMacro(`Unkown compression algorithm: ${options.compression}`); }
return new Promise((resolve, reject) => { const xhr = openAsyncXHR('GET', url, options);
xhr.onreadystatechange = (e) => { if (xhr.readyState === 1) { if (++requestCount === 1 && instance?.invokeBusy) { instance.invokeBusy(true); } } if (xhr.readyState === 4) { if (--requestCount === 0 && instance?.invokeBusy) { instance.invokeBusy(false); } if (xhr.status === 200 || xhr.status === 0) { if (options.compression) { resolve(strFromU8(decompressSync(new Uint8Array(xhr.response)))); } else { resolve(xhr.responseText); } } else { reject({ xhr, e }); } } };
xhr.responseType = options.compression ? 'arraybuffer' : 'text'; xhr.send(); }); }
function fetchImage(instance, url, options = {}) { return new Promise((resolve, reject) => { const img = new Image(); if (options.crossOrigin) { img.crossOrigin = options.crossOrigin; } img.onload = () => resolve(img); img.onerror = reject; img.src = url; }); }
const HttpDataAccessHelper = { fetchArray, fetchJSON, fetchText, fetchBinary, fetchImage, };
registerType('http', (options) => HttpDataAccessHelper);
export default HttpDataAccessHelper;
|