All files / core/src/loaders cornerstoneMeshLoader.ts

0% Statements 0/42
0% Branches 0/18
0% Functions 0/11
0% Lines 0/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118                                                                                                                                                                                                                                           
import { createMesh } from './utils/mesh/createMesh';
import type { IGeometry, IGeometryLoadObject, MeshData } from '../types';
import { Events } from '../enums';
import eventTarget from '../eventTarget';
import { triggerEvent } from '../utilities';
import type { GeometryLoaderOptions } from '../types/GeometryLoaderFn';
 
function fetchArrayBuffer({
  url,
  signal,
  onload,
  loaderOptions,
}: {
  url: string;
  signal?: AbortSignal;
  onload?: () => void;
  loaderOptions: GeometryLoaderOptions;
}): Promise<ArrayBuffer> {
  return new Promise(async (resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
 
    const defaultHeaders = {} as Record<string, string>;
    const beforeSendHeaders = await loaderOptions.beforeSend(
      xhr,
      defaultHeaders
    );
    const headers = Object.assign({}, defaultHeaders, beforeSendHeaders);
 
    xhr.responseType = 'arraybuffer';
 
    Object.keys(headers).forEach(function (key) {
      if (headers[key] === null) {
        return;
      }
      xhr.setRequestHeader(key, headers[key]);
    });
 
    const onLoadHandler = function (e) {
      if (onload && typeof onload === 'function') {
        onload();
      }
 
      // Remove event listener for 'abort'
      if (signal) {
        signal.removeEventListener('abort', onAbortHandler);
      }
 
      resolve(xhr.response);
    };
 
    const onAbortHandler = () => {
      xhr.abort();
 
      // Remove event listener for 'load'
      xhr.removeEventListener('load', onLoadHandler);
 
      reject(new Error('Request aborted'));
    };
 
    xhr.addEventListener('load', onLoadHandler);
 
    const onProgress = (loaded, total) => {
      const data = { url, loaded, total };
      triggerEvent(eventTarget, Events.GEOMETRY_LOAD_PROGRESS, { data });
    };
 
    xhr.onprogress = function (e) {
      onProgress(e.loaded, e.total);
    };
 
    if (signal && signal.aborted) {
      xhr.abort();
      reject(new Error('Request aborted'));
    } else if (signal) {
      signal.addEventListener('abort', onAbortHandler);
    }
 
    xhr.send();
  });
}
 
function cornerstoneMeshLoader(
  meshId: string,
  options: Record<string, unknown>,
  loaderOptions: GeometryLoaderOptions
): IGeometryLoadObject {
  const promise = new Promise<IGeometry>((resolve, reject) => {
    fetchAndProcessMeshData(meshId, options, loaderOptions)
      .then(resolve)
      .catch(reject);
  });
  return {
    promise: promise as Promise<IGeometry>,
    cancelFn: undefined,
    decache: () => {},
  };
}
 
async function fetchAndProcessMeshData(
  meshId: string,
  options: Record<string, unknown>,
  loaderOptions: GeometryLoaderOptions
): Promise<IGeometry> {
  const parts = meshId.split(':');
  const url = parts.slice(1).join(':');
  const meshBuffer = await fetchArrayBuffer({ url, loaderOptions });
  if (!options || !('geometryData' in options)) {
    throw new Error('Mesh must have a geometryData');
  }
  return createMesh(url, {
    ...(options.geometryData as MeshData),
    arrayBuffer: meshBuffer,
  }) as unknown as IGeometry;
}
 
export { cornerstoneMeshLoader };