UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

494 lines (395 loc) 17 kB
import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import _defineProperty from '@babel/runtime/helpers/defineProperty'; import macro from '../../macros.js'; import vtkActor from '../../Rendering/Core/Actor.js'; import vtkVolume from '../../Rendering/Core/Volume.js'; import vtkHttpDataSetReader from './HttpDataSetReader.js'; import vtkHttpDataSetSeriesReader from './HttpDataSetSeriesReader.js'; import vtkMapper from '../../Rendering/Core/Mapper.js'; import vtkTexture from '../../Rendering/Core/Texture.js'; import vtkTextureLODsDownloader from '../../Rendering/Misc/TextureLODsDownloader.js'; import vtkHttpDataSetLODsLoader from '../Misc/HttpDataSetLODsLoader.js'; import vtkColorTransferFunction from '../../Rendering/Core/ColorTransferFunction.js'; import vtkPiecewiseFunction from '../../Common/DataModel/PiecewiseFunction.js'; import vtkVolumeMapper from '../../Rendering/Core/VolumeMapper.js'; import vtkTimeStepBasedAnimationHandler from '../../Interaction/Animations/TimeStepBasedAnimationHandler.js'; import DataAccessHelper from './DataAccessHelper.js'; import './DataAccessHelper/LiteHttpDataAccessHelper.js'; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } // import 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper'; // HTTP + zip // import 'vtk.js/Sources/IO/Core/DataAccessHelper/HtmlDataAccessHelper'; // html + base64 + zip // import 'vtk.js/Sources/IO/Core/DataAccessHelper/JSZipDataAccessHelper'; // zip var vtkErrorMacro = macro.vtkErrorMacro; var itemCount = 1; function applySettings(sceneItem, settings) { if (settings.actor) { sceneItem.actor.set(settings.actor); } if (settings.actorRotation) { sceneItem.actor.rotateWXYZ(settings.actorRotation[0], settings.actorRotation[1], settings.actorRotation[2], settings.actorRotation[3]); } if (settings.volumeRotation) { sceneItem.volume.rotateWXYZ(settings.volumeRotation[0], settings.volumeRotation[1], settings.volumeRotation[2], settings.volumeRotation[3]); } if (settings.property) { if (settings.volume) { var volumePropertySettings = _objectSpread({}, settings.property); delete volumePropertySettings.components; sceneItem.volume.getProperty().set(volumePropertySettings); if (settings.property.components) { var volumeProperty = sceneItem.volume.getProperty(); sceneItem.volumeComponents.forEach(function (component, componentIndex) { volumeProperty.setScalarOpacityUnitDistance(componentIndex, settings.property.components[componentIndex].scalarOpacityUnitDistance); if (component.rgbTransferFunction) { volumeProperty.setRGBTransferFunction(componentIndex, component.rgbTransferFunction); } if (component.grayTransferFunction) { volumeProperty.setGrayTransferFunction(componentIndex, component.grayTransferFunction); } if (component.scalarOpacity) { volumeProperty.setScalarOpacity(componentIndex, component.scalarOpacity); } }); } } else { sceneItem.actor.getProperty().set(settings.property); } } if (settings.mapper) { if (settings.mapper.colorByArrayName) { sceneItem.source.enableArray(settings.mapper.colorByArrayName, settings.mapper.colorByArrayName); sceneItem.source.loadData(); } sceneItem.mapper.set(settings.mapper); if (settings.mapper.colorByArrayName && settings.luts[settings.mapper.colorByArrayName]) { sceneItem.mapper.setLookupTable(settings.luts[settings.mapper.colorByArrayName]); sceneItem.mapper.setUseLookupTableScalarRange(true); } } if (settings.lookupTable) { sceneItem.mapper.getLookupTable().set(settings.lookupTable); sceneItem.mapper.getLookupTable().build(); } if (settings.textureLODs) { sceneItem.textureLODs = settings.textureLODs; } if (settings.sourceLODs) { sceneItem.sourceLODs = settings.sourceLODs; } } // ---------------------------------------------------------------------------- // Global methods // ---------------------------------------------------------------------------- function isImage(str) { var ext = str.split('.').pop().toLowerCase(); return ['jpg', 'png', 'jpeg'].indexOf(ext) !== -1; } function loadColorTransferFunction(item) { var tf = vtkColorTransferFunction.newInstance(item); if (item.nodes) { tf.removeAllPoints(); item.nodes.forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 6), x = _ref2[0], r = _ref2[1], g = _ref2[2], b = _ref2[3], midpoint = _ref2[4], sharpness = _ref2[5]; tf.addRGBPointLong(x, r, g, b, midpoint, sharpness); }); } return tf; } function loadPiecewiseFunction(item) { var pwf = vtkPiecewiseFunction.newInstance(item); if (item.points) { pwf.removeAllPoints(); item.points.forEach(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 4), x = _ref4[0], y = _ref4[1], midpoint = _ref4[2], sharpness = _ref4[3]; return pwf.addPointLong(x, y, midpoint, sharpness); }); } return pwf; } function initializeVolumeComponents(components) { return components.map(function (component) { var ret = {}; if (component.rgbTransferFunction) { ret.rgbTransferFunction = loadColorTransferFunction(component.rgbTransferFunction); } else if (component.grayTransferFunction) { ret.grayTransferFunction = loadPiecewiseFunction(component.grayTransferFunction); } if (component.scalarOpacity) { ret.scalarOpacity = loadPiecewiseFunction(component.scalarOpacity); } return ret; }); } // ---------------------------------------------------------------------------- function defineLoadFuctionForReader(type) { return function (item, model, publicAPI) { var source = type.newInstance({ fetchGzip: model.fetchGzip, dataAccessHelper: model.dataAccessHelper }); var mapper; if (item.volume) { mapper = vtkVolumeMapper.newInstance(); } else { mapper = vtkMapper.newInstance(); } var sceneItem = { name: item.name || "Item ".concat(itemCount++), source: source, mapper: mapper, defaultSettings: item }; if (item.volume) { var volume = vtkVolume.newInstance(); sceneItem.volume = volume; if (model.renderer) { model.renderer.addVolume(volume); } if (item.property && item.property.components) { // initialize transfer functions sceneItem.volumeComponents = initializeVolumeComponents(item.property.components); } volume.setMapper(mapper); } else { var actor = vtkActor.newInstance(); sceneItem.actor = actor; if (item.texture && item.texture in model.usedTextures) { // If this texture has already been used, re-use it actor.addTexture(model.usedTextures[item.texture]); } else if (item.texture) { var url = [model.baseURL, item.texture].join('/'); var texture = vtkTexture.newInstance(); texture.setInterpolate(true); texture.setRepeat(true); actor.addTexture(texture); sceneItem.texture = texture; model.usedTextures[item.texture] = texture; if (isImage(item.texture)) { // It's an image file model.dataAccessHelper.fetchImage({}, url, { crossOrigin: 'anonymous' }).then(function (img) { texture.setImage(img); }); } else { // Assume it's a dataset file var textureSource = type.newInstance({ fetchGzip: model.fetchGzip, dataAccessHelper: model.dataAccessHelper }); textureSource.setUrl(url, { loadData: true }).then(function () { texture.setInputData(textureSource.getOutputData()); }); } } var textureLODs = item.textureLODs; if (textureLODs && textureLODs.files && textureLODs.files.length !== 0) { // If this texture LOD has already been used, re-use it var textureLODsStr = JSON.stringify(textureLODs); if (textureLODsStr in model.usedTextureLODs) { actor.addTexture(model.usedTextureLODs[textureLODsStr]); } else { // Set it on the scene item so it can be accessed later, for // doing things like setting a callback function. sceneItem.textureLODsDownloader = vtkTextureLODsDownloader.newInstance(); var textureDownloader = sceneItem.textureLODsDownloader; var _texture = vtkTexture.newInstance(); _texture.setInterpolate(true); actor.addTexture(_texture); model.usedTextureLODs[textureLODsStr] = _texture; textureDownloader.setTexture(_texture); textureDownloader.setCrossOrigin('anonymous'); textureDownloader.setBaseUrl(textureLODs.baseUrl); textureDownloader.setFiles(textureLODs.files); if (model.startLODLoaders) { textureDownloader.startDownloads(); } } } if (model.renderer) { model.renderer.addActor(actor); } actor.setMapper(mapper); } mapper.setInputConnection(source.getOutputPort()); source.setUrl([model.baseURL, item[item.type].url].join('/'), { loadData: true }).then(function () { return publicAPI.invokeReady(); }); applySettings(sceneItem, item); model.scene.push(sceneItem); var sourceLODs = item.sourceLODs; if (sourceLODs && sourceLODs.files && sourceLODs.files.length !== 0) { // Set it on the scene item so it can be accessed later, for // doing things like setting a callback function. sceneItem.dataSetLODsLoader = vtkHttpDataSetLODsLoader.newInstance(); var dataSetLODsLoader = sceneItem.dataSetLODsLoader; dataSetLODsLoader.setMapper(mapper); dataSetLODsLoader.setSceneItem(sceneItem); dataSetLODsLoader.setBaseUrl(sourceLODs.baseUrl); dataSetLODsLoader.setFiles(sourceLODs.files); if (model.startLODLoaders) { dataSetLODsLoader.startDownloads(); } } return sceneItem; }; } function loadTimeStepBasedAnimationHandler(data, model) { model.animationHandler = vtkTimeStepBasedAnimationHandler.newInstance({ scene: model.scene, originalMetadata: model.metadata, applySettings: applySettings }); if (model.animationHandler && model.renderer) { model.animationHandler.addRenderer(model.renderer); } model.animationHandler.setData(data); } // ---------------------------------------------------------------------------- // Note: keeping both types (with and without 'vtk' prefix) for backwards compatibility // see https://gitlab.kitware.com/paraview/paraview/-/merge_requests/4628#note_876772 var TYPE_MAPPING = { httpDataSetReader: defineLoadFuctionForReader(vtkHttpDataSetReader), vtkHttpDataSetReader: defineLoadFuctionForReader(vtkHttpDataSetReader), httpDataSetSeriesReader: defineLoadFuctionForReader(vtkHttpDataSetSeriesReader), vtkHttpDataSetSeriesReader: defineLoadFuctionForReader(vtkHttpDataSetSeriesReader) }; var ANIMATION_TYPE_MAPPING = { timeStepBasedAnimationHandler: loadTimeStepBasedAnimationHandler, vtkTimeStepBasedAnimationHandler: loadTimeStepBasedAnimationHandler }; // ---------------------------------------------------------------------------- function updateDatasetTypeMapping(typeName, handler) { TYPE_MAPPING[typeName] = handler; } // ---------------------------------------------------------------------------- // vtkHttpSceneLoader methods // ---------------------------------------------------------------------------- function vtkHttpSceneLoader(publicAPI, model) { var originalSceneParameters = {}; // These are here to re-use the same textures when possible if (!model.usedTextures) { model.usedTextures = {}; } if (!model.usedTextureLODs) { model.usedTextureLODs = {}; } // Set our className model.classHierarchy.push('vtkHttpSceneLoader'); // Create scene container if (!model.scene) { model.scene = []; } function setCameraParameters(params) { if (model.renderer) { var camera = model.renderer.getActiveCamera(); if (camera) { camera.set(params); } else { vtkErrorMacro('No active camera to update'); } } } function setBackground(color) { if (model.renderer) { model.renderer.setBackground(color); } } // Create default dataAccessHelper if not available if (!model.dataAccessHelper) { model.dataAccessHelper = DataAccessHelper.get('http'); } publicAPI.update = function () { model.dataAccessHelper.fetchJSON(publicAPI, model.url).then(function (data) { if (data.fetchGzip !== undefined) { model.fetchGzip = data.fetchGzip; } if (data.background && model.renderer) { setBackground(data.background); } if (data.camera) { originalSceneParameters.camera = data.camera; setCameraParameters(data.camera); } var luts = {}; if (data.lookupTables) { Object.keys(data.lookupTables).forEach(function (fieldName) { var config = data.lookupTables[fieldName]; var lookupTable = loadColorTransferFunction(config); luts[fieldName] = lookupTable; }); } if (data.scene) { data.scene.forEach(function (item) { var builder = TYPE_MAPPING[item.type]; if (builder) { builder(_objectSpread({ luts: luts }, item), model, publicAPI); } }); global.scene = model.scene; // Clear these model.usedTextures = {}; model.usedTextureLODs = {}; } // Capture index.json into meta model.metadata = data; if (data.animation) { var animationLoader = ANIMATION_TYPE_MAPPING[data.animation.type]; animationLoader(_objectSpread({}, data.animation), model, publicAPI, setCameraParameters, setBackground); } }, function (error) { vtkErrorMacro("Error fetching scene ".concat(error)); }); }; publicAPI.resetScene = function () { if (originalSceneParameters.camera) { setCameraParameters(originalSceneParameters.camera); } }; // Set DataSet url publicAPI.setUrl = function (url) { if (url.indexOf('index.json') === -1) { model.baseURL = url; model.url = "".concat(url, "/index.json"); } else { model.url = url; // Remove the file in the URL var path = url.split('/'); path.pop(); model.baseURL = path.join('/'); } // Fetch data return publicAPI.update(); }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- var DEFAULT_VALUES = { fetchGzip: false, url: null, baseURL: null, animationHandler: null, // Whether or not to automatically start texture LOD and poly LOD // downloads when they are read. startLODLoaders: true }; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API macro.obj(publicAPI, model); macro.get(publicAPI, model, ['fetchGzip', 'url', 'baseURL', 'scene', 'metadata', 'animationHandler']); macro.setGet(publicAPI, model, ['renderer']); macro.event(publicAPI, model, 'ready'); // Object methods vtkHttpSceneLoader(publicAPI, model); } // ---------------------------------------------------------------------------- var newInstance = macro.newInstance(extend, 'vtkHttpSceneLoader'); // ---------------------------------------------------------------------------- var vtkHttpSceneLoader$1 = { newInstance: newInstance, extend: extend, applySettings: applySettings, updateDatasetTypeMapping: updateDatasetTypeMapping }; export { vtkHttpSceneLoader$1 as default, extend, newInstance };