@kitware/vtk.js
Version:
Visualization Toolkit for the Web
494 lines (395 loc) • 17 kB
JavaScript
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 };