@thewtex/vtk.js-esm
Version:
Visualization Toolkit for the Web
668 lines (541 loc) • 22.9 kB
JavaScript
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import { capitalize } from '../../../macro.js';
import vtkActor from '../../Core/Actor.js';
import vtkCamera from '../../Core/Camera.js';
import vtkColorTransferFunction from '../../Core/ColorTransferFunction.js';
import vtkDataArray from '../../../Common/Core/DataArray.js';
import vtkPoints from '../../../Common/Core/Points.js';
import vtkCellArray from '../../../Common/Core/CellArray.js';
import vtkGlyph3DMapper from '../../Core/Glyph3DMapper.js';
import vtkLight from '../../Core/Light.js';
import vtkLookupTable from '../../../Common/Core/LookupTable.js';
import vtkMapper from '../../Core/Mapper.js';
import vtkPolyData from '../../../Common/DataModel/PolyData.js';
import vtkImageData from '../../../Common/DataModel/ImageData.js';
import vtkProperty from '../../Core/Property.js';
import vtkRenderer from '../../Core/Renderer.js';
import vtkRenderWindow from '../../Core/RenderWindow.js';
import vtkTexture from '../../Core/Texture.js';
import vtkVolume from '../../Core/Volume.js';
import vtkVolumeMapper from '../../Core/VolumeMapper.js';
import vtkVolumeProperty from '../../Core/VolumeProperty.js';
import vtkImageSlice from '../../Core/ImageSlice.js';
import vtkImageMapper from '../../Core/ImageMapper.js';
import vtkImageProperty from '../../Core/ImageProperty.js';
import vtkPiecewiseFunction from '../../../Common/DataModel/PiecewiseFunction.js';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
// Some internal, module-level variables and methods
// ----------------------------------------------------------------------------
var TYPE_HANDLERS = {};
var WRAPPED_ID_RE = /instance:\${([^}]+)}/;
var WRAP_ID = function WRAP_ID(id) {
return "instance:${".concat(id, "}");
};
var ONE_TIME_INSTANCE_TRACKERS = {};
var SKIPPED_INSTANCE_IDS = [];
var EXCLUDE_INSTANCE_MAP = {};
var DATA_ARRAY_MAPPER = {
vtkPoints: vtkPoints,
vtkCellArray: vtkCellArray,
vtkDataArray: vtkDataArray
}; // ----------------------------------------------------------------------------
function extractCallArgs(synchronizerContext, argList) {
return argList.map(function (arg) {
var m = WRAPPED_ID_RE.exec(arg);
if (m) {
return synchronizerContext.getInstance(m[1]);
}
return arg;
});
} // ----------------------------------------------------------------------------
function extractInstanceIds(argList) {
return argList.map(function (arg) {
return WRAPPED_ID_RE.exec(arg);
}).filter(function (m) {
return m;
}).map(function (m) {
return m[1];
});
} // ----------------------------------------------------------------------------
function extractDependencyIds(state) {
var depList = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
if (state.dependencies) {
state.dependencies.forEach(function (childState) {
depList.push(childState.id);
extractDependencyIds(childState, depList);
});
}
return depList;
} // ----------------------------------------------------------------------------
function bindArrays(arraysToBind) {
while (arraysToBind.length) {
var _arraysToBind$shift = arraysToBind.shift(),
_arraysToBind$shift2 = _slicedToArray(_arraysToBind$shift, 2),
fn = _arraysToBind$shift2[0],
args = _arraysToBind$shift2[1];
fn.apply(void 0, _toConsumableArray(args));
}
} // ----------------------------------------------------------------------------
function createNewArrayHandler(instance, arrayMetadata, arraysToBind) {
return function (values) {
var vtkClass = arrayMetadata.vtkClass ? arrayMetadata.vtkClass : 'vtkDataArray';
var array = DATA_ARRAY_MAPPER[vtkClass].newInstance(_objectSpread(_objectSpread({}, arrayMetadata), {}, {
values: values
}));
var regMethod = arrayMetadata.registration ? arrayMetadata.registration : 'addArray';
var location = arrayMetadata.location ? instance.getReferenceByName(arrayMetadata.location) : instance;
arraysToBind.push([location[regMethod], [array]]);
return array;
};
} // ----------------------------------------------------------------------------
// Static methods for export
// ----------------------------------------------------------------------------
function update(type, instance, props, context) {
if (!instance) {
return;
}
var handler = TYPE_HANDLERS[type];
if (handler && handler.update) {
handler.update(instance, props, context);
} else {
console.log('no updater for', type);
}
} // ----------------------------------------------------------------------------
function build(type) {
var initialProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var handler = TYPE_HANDLERS[type];
if (handler && handler.build) {
// DEBUG console.log(`new ${type} - ${initialProps.managedInstanceId}`);
return handler.build(initialProps);
}
console.log('No builder for', type);
return null;
} // ----------------------------------------------------------------------------
function excludeInstance(type, propertyName, propertyValue) {
EXCLUDE_INSTANCE_MAP[type] = {
key: propertyName,
value: propertyValue
};
} // ----------------------------------------------------------------------------
function getSupportedTypes() {
return Object.keys(TYPE_HANDLERS);
} // ----------------------------------------------------------------------------
function clearTypeMapping() {
Object.keys(TYPE_HANDLERS).forEach(function (key) {
delete TYPE_HANDLERS[key];
});
} // ----------------------------------------------------------------------------
function updateRenderWindow(instance, props, context) {
return update('vtkRenderWindow', instance, props, context);
} // ----------------------------------------------------------------------------
function clearAllOneTimeUpdaters() {
Object.keys(ONE_TIME_INSTANCE_TRACKERS).forEach(function (key) {
delete ONE_TIME_INSTANCE_TRACKERS[key];
});
} // ----------------------------------------------------------------------------
function clearOneTimeUpdaters() {
for (var _len = arguments.length, ids = new Array(_len), _key = 0; _key < _len; _key++) {
ids[_key] = arguments[_key];
}
if (ids.length === 0) {
return clearAllOneTimeUpdaters();
}
var array = ids; // allow an array passed as a single arg.
if (array.length === 1 && Array.isArray(array[0])) {
array = array[0];
}
array.forEach(function (instanceId) {
delete ONE_TIME_INSTANCE_TRACKERS[instanceId];
});
return array;
} // ----------------------------------------------------------------------------
function notSkippedInstance(call) {
if (call[1].length === 1) {
return SKIPPED_INSTANCE_IDS.indexOf(call[1][0]) === -1;
}
var keep = false;
for (var i = 0; i < call[1].length; i++) {
keep = keep || SKIPPED_INSTANCE_IDS.indexOf(call[1][i]) === -1;
}
return keep;
} // ----------------------------------------------------------------------------
// Updater functions
// ----------------------------------------------------------------------------
function genericUpdater(instance, state, context) {
context.start(); // -> start(generic-updater)
// First update our own properties
instance.set(state.properties); // Now handle dependencies
if (state.dependencies) {
state.dependencies.forEach(function (childState) {
var id = childState.id,
type = childState.type;
if (EXCLUDE_INSTANCE_MAP[type]) {
var _EXCLUDE_INSTANCE_MAP = EXCLUDE_INSTANCE_MAP[type],
key = _EXCLUDE_INSTANCE_MAP.key,
value = _EXCLUDE_INSTANCE_MAP.value;
if (!key || childState.properties[key] === value) {
SKIPPED_INSTANCE_IDS.push(WRAP_ID(id));
return;
}
}
var childInstance = context.getInstance(id);
if (!childInstance) {
childInstance = build(type, {
managedInstanceId: id
});
context.registerInstance(id, childInstance);
}
update(type, childInstance, childState, context);
});
}
if (state.calls) {
state.calls.filter(notSkippedInstance).forEach(function (call) {
// DEBUG console.log('==>', call[0], extractCallArgs(context, call[1]));
instance[call[0]].apply(null, extractCallArgs(context, call[1]));
});
} // if some arrays need to be be fetch
if (state.arrays) {
var arraysToBind = [];
var promises = state.arrays.map(function (arrayMetadata) {
context.start(); // -> start(arrays)
return context.getArray(arrayMetadata.hash, arrayMetadata.dataType, context).then(createNewArrayHandler(instance, arrayMetadata, arraysToBind)).catch(function (error) {
console.log('Error fetching array', JSON.stringify(arrayMetadata), error);
}).finally(context.end); // -> end(arrays)
});
context.start(); // -> start(arraysToBind)
Promise.all(promises).then(function () {
bindArrays(arraysToBind);
}).catch(function (error) {
console.error('Error in array handling for state', JSON.stringify(state), error);
}).finally(context.end); // -> end(arraysToBind)
}
context.end(); // -> end(generic-updater)
} // ----------------------------------------------------------------------------
function oneTimeGenericUpdater(instance, state, context) {
if (!ONE_TIME_INSTANCE_TRACKERS[state.id]) {
genericUpdater(instance, state, context);
}
ONE_TIME_INSTANCE_TRACKERS[state.id] = true;
} // ----------------------------------------------------------------------------
function rendererUpdater(instance, state, context) {
// Don't do start/end on the context here because we don't need to hold up
// rendering for the book-keeping we do after the genericUpdater finishes.
// First allow generic update process to happen as usual
genericUpdater(instance, state, context); // Any view props that were removed in the previous phase, genericUpdater(...),
// may have left orphaned children in our instance cache. Below is where those
// refs can be tracked in the first place, and then later removed as necessary
// to allow garbage collection.
// In some cases, seemingly with 'vtkColorTransferFunction', the server side
// object id may be conserved even though the actor and mapper containing or
// using it were deleted. In this case we must not unregister an instance
// which is depended upon by an incoming actor just because it was also
// depended upon by an outgoing one.
var allActorsDeps = new Set(); // Here we gather the list of dependencies (instance ids) for each view prop and
// store them on the instance, in case that view prop is later removed.
if (state.dependencies) {
state.dependencies.forEach(function (childState) {
var viewPropInstance = context.getInstance(childState.id);
if (viewPropInstance) {
var flattenedDepIds = extractDependencyIds(childState);
viewPropInstance.set({
flattenedDepIds: flattenedDepIds
}, true);
flattenedDepIds.forEach(function (depId) {
return allActorsDeps.add(depId);
});
}
});
} // Look for 'removeViewProp' calls and clean up references to dependencies of
// those view props.
var unregisterCandidates = new Set();
if (state.calls) {
state.calls.filter(notSkippedInstance).filter(function (call) {
return call[0] === 'removeViewProp';
}).forEach(function (call) {
// extract any ids associated with a 'removeViewProp' call (though really there
// should just be a single one), and use them to build a flat list of all
// representation dependency ids which we can then use our synchronizer context
// to unregister
extractInstanceIds(call[1]).forEach(function (vpId) {
var deps = context.getInstance(vpId).get('flattenedDepIds').flattenedDepIds;
if (deps) {
// Consider each dependency for un-registering
deps.forEach(function (depId) {
return unregisterCandidates.add(depId);
});
} // Consider the viewProp itself for un-registering
unregisterCandidates.add(vpId);
});
});
} // Now unregister any instances that are no longer needed
var idsToUnregister = _toConsumableArray(unregisterCandidates).filter(function (depId) {
return !allActorsDeps.has(depId);
});
idsToUnregister.forEach(function (depId) {
return context.unregisterInstance(depId);
});
} // ----------------------------------------------------------------------------
function vtkRenderWindowUpdater(instance, state, context) {
// For each renderer we may be removing from this render window, we should first
// remove all of the renderer's view props, then have the render window re-render
// itself. This will clear the screen, at which point we can go about the normal
// updater process.
if (state.calls) {
state.calls.filter(notSkippedInstance).filter(function (call) {
return call[0] === 'removeRenderer';
}).forEach(function (call) {
extractInstanceIds(call[1]).forEach(function (renId) {
var renderer = context.getInstance(renId); // Take brief detour through the view props to unregister the dependencies
// of each one
var viewProps = renderer.getViewProps();
viewProps.forEach(function (viewProp) {
var deps = viewProp.get('flattenedDepIds').flattenedDepIds;
if (deps) {
deps.forEach(function (depId) {
return context.unregisterInstance(depId);
});
}
context.unregisterInstance(context.getInstanceId(viewProp));
}); // Now just remove all the view props
renderer.removeAllViewProps();
});
});
}
instance.render(); // Now just do normal update process
genericUpdater(instance, state, context);
} // ----------------------------------------------------------------------------
function colorTransferFunctionUpdater(instance, state, context) {
context.start(); // -> start(colorTransferFunctionUpdater)
var nodes = state.properties.nodes.map(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];
return {
x: x,
r: r,
g: g,
b: b,
midpoint: midpoint,
sharpness: sharpness
};
});
instance.set(_objectSpread(_objectSpread({}, state.properties), {}, {
nodes: nodes
}), true);
instance.sortAndUpdateRange();
instance.modified();
context.end(); // -> end(colorTransferFunctionUpdater)
}
function piecewiseFunctionUpdater(instance, state, context) {
context.start(); // -> start(piecewiseFunctionUpdater)
var nodes = state.properties.nodes.map(function (_ref3) {
var _ref4 = _slicedToArray(_ref3, 4),
x = _ref4[0],
y = _ref4[1],
midpoint = _ref4[2],
sharpness = _ref4[3];
return {
x: x,
y: y,
midpoint: midpoint,
sharpness: sharpness
};
});
instance.set(_objectSpread(_objectSpread({}, state.properties), {}, {
nodes: nodes
}), true);
instance.sortAndUpdateRange();
instance.modified();
context.end(); // -> end(piecewiseFunctionUpdater)
} // ----------------------------------------------------------------------------
function createDataSetUpdate() {
var piecesToFetch = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return function (instance, state, context) {
var _state$arrays;
context.start(); // -> start(dataset-update)
// Make sure we provide container for std arrays
if (!state.arrays) {
state.arrays = [];
} // Array members
// => convert old format to generic state.arrays
piecesToFetch.forEach(function (key) {
if (state.properties[key]) {
var arrayMeta = state.properties[key];
arrayMeta.registration = "set".concat(capitalize(key));
state.arrays.push(arrayMeta);
delete state.properties[key];
}
}); // Extract dataset fields
var fieldsArrays = state.properties.fields || [];
(_state$arrays = state.arrays).push.apply(_state$arrays, _toConsumableArray(fieldsArrays));
delete state.properties.fields; // Reset any pre-existing fields array
instance.getPointData().removeAllArrays();
instance.getCellData().removeAllArrays(); // Generic handling
genericUpdater(instance, state, context); // Finish what we started
context.end(); // -> end(dataset-update)
};
}
var polydataUpdater = createDataSetUpdate(['points', 'polys', 'verts', 'lines', 'strips']);
var imageDataUpdater = createDataSetUpdate([]); // ----------------------------------------------------------------------------
// Construct the type mapping
// ----------------------------------------------------------------------------
function setTypeMapping(type) {
var buildFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var updateFn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : genericUpdater;
if (!build && !update) {
delete TYPE_HANDLERS[type];
return;
}
TYPE_HANDLERS[type] = {
build: buildFn,
update: updateFn
};
} // ----------------------------------------------------------------------------
var DEFAULT_ALIASES = {
vtkMapper: ['vtkOpenGLPolyDataMapper', 'vtkCompositePolyDataMapper2', 'vtkDataSetMapper'],
vtkProperty: ['vtkOpenGLProperty'],
vtkRenderer: ['vtkOpenGLRenderer'],
vtkCamera: ['vtkOpenGLCamera'],
vtkColorTransferFunction: ['vtkPVDiscretizableColorTransferFunction'],
vtkActor: ['vtkOpenGLActor', 'vtkPVLODActor'],
vtkLight: ['vtkOpenGLLight', 'vtkPVLight'],
vtkTexture: ['vtkOpenGLTexture'],
vtkImageMapper: ['vtkOpenGLImageSliceMapper'],
vtkVolumeMapper: ['vtkFixedPointVolumeRayCastMapper']
}; // ----------------------------------------------------------------------------
var DEFAULT_MAPPING = {
vtkRenderWindow: {
build: vtkRenderWindow.newInstance,
update: vtkRenderWindowUpdater
},
vtkRenderer: {
build: vtkRenderer.newInstance,
update: rendererUpdater
},
vtkLookupTable: {
build: vtkLookupTable.newInstance,
update: genericUpdater
},
vtkCamera: {
build: vtkCamera.newInstance,
update: oneTimeGenericUpdater
},
vtkPolyData: {
build: vtkPolyData.newInstance,
update: polydataUpdater
},
vtkImageData: {
build: vtkImageData.newInstance,
update: imageDataUpdater
},
vtkMapper: {
build: vtkMapper.newInstance,
update: genericUpdater
},
vtkGlyph3DMapper: {
build: vtkGlyph3DMapper.newInstance,
update: genericUpdater
},
vtkProperty: {
build: vtkProperty.newInstance,
update: genericUpdater
},
vtkActor: {
build: vtkActor.newInstance,
update: genericUpdater
},
vtkLight: {
build: vtkLight.newInstance,
update: genericUpdater
},
vtkColorTransferFunction: {
build: vtkColorTransferFunction.newInstance,
update: colorTransferFunctionUpdater
},
vtkTexture: {
build: vtkTexture.newInstance,
update: genericUpdater
},
vtkVolume: {
build: vtkVolume.newInstance,
update: genericUpdater
},
vtkVolumeMapper: {
build: vtkVolumeMapper.newInstance,
update: genericUpdater
},
vtkVolumeProperty: {
build: vtkVolumeProperty.newInstance,
update: genericUpdater
},
vtkImageSlice: {
build: vtkImageSlice.newInstance,
update: genericUpdater
},
vtkImageMapper: {
build: vtkImageMapper.newInstance,
update: genericUpdater
},
vtkImageProperty: {
build: vtkImageProperty.newInstance,
update: genericUpdater
},
vtkPiecewiseFunction: {
build: vtkPiecewiseFunction.newInstance,
update: piecewiseFunctionUpdater
}
}; // ----------------------------------------------------------------------------
function setDefaultMapping() {
var reset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
if (reset) {
clearTypeMapping();
}
Object.keys(DEFAULT_MAPPING).forEach(function (type) {
var mapping = DEFAULT_MAPPING[type];
setTypeMapping(type, mapping.build, mapping.update);
});
} // ----------------------------------------------------------------------------
function applyDefaultAliases() {
// Add aliases
Object.keys(DEFAULT_ALIASES).forEach(function (name) {
var aliases = DEFAULT_ALIASES[name];
aliases.forEach(function (alias) {
TYPE_HANDLERS[alias] = TYPE_HANDLERS[name];
});
});
} // ----------------------------------------------------------------------------
function alwaysUpdateCamera() {
setTypeMapping('vtkCamera', vtkCamera.newInstance);
applyDefaultAliases();
} // ----------------------------------------------------------------------------
setDefaultMapping();
applyDefaultAliases(); // ----------------------------------------------------------------------------
// Avoid handling any lights at the moment
EXCLUDE_INSTANCE_MAP.vtkOpenGLLight = {};
EXCLUDE_INSTANCE_MAP.vtkPVLight = {};
EXCLUDE_INSTANCE_MAP.vtkLight = {}; // ----------------------------------------------------------------------------
// Publicly exposed methods
// ----------------------------------------------------------------------------
var vtkObjectManager = {
build: build,
update: update,
genericUpdater: genericUpdater,
oneTimeGenericUpdater: oneTimeGenericUpdater,
setTypeMapping: setTypeMapping,
clearTypeMapping: clearTypeMapping,
getSupportedTypes: getSupportedTypes,
clearOneTimeUpdaters: clearOneTimeUpdaters,
updateRenderWindow: updateRenderWindow,
excludeInstance: excludeInstance,
setDefaultMapping: setDefaultMapping,
applyDefaultAliases: applyDefaultAliases,
alwaysUpdateCamera: alwaysUpdateCamera
};
export default vtkObjectManager;