@kitware/vtk.js
Version:
Visualization Toolkit for the Web
275 lines (251 loc) • 8.1 kB
JavaScript
import { m as macro } from '../../macros2.js';
const {
vtkErrorMacro
} = macro;
const PASS_TYPES = ['Build', 'Render'];
// ----------------------------------------------------------------------------
// vtkViewNode methods
// ----------------------------------------------------------------------------
function vtkViewNode(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkViewNode');
/**
* Convenient method to move a child to a specific index.
* @param {*} child the child to move
* @param {*} toIndex the index to move the child to
* @returns true if the child was moved, false otherwise
*/
function moveChild(child, toIndex) {
for (let i = 0; i < model.children.length; ++i) {
// Start browsing from toIndex + 1
const childIndex = (toIndex + 1 + i) % model.children.length;
if (model.children[childIndex] === child) {
model.children[childIndex] = model.children[toIndex];
model.children[toIndex] = child;
return true;
}
}
return false;
}
// Builds myself.
publicAPI.build = prepass => {};
// Renders myself
publicAPI.render = prepass => {};
publicAPI.traverse = renderPass => {
// we can choose to do special
// traversal here based on pass
const passTraversal = renderPass.getTraverseOperation();
const fn = publicAPI[passTraversal];
if (fn) {
fn(renderPass);
return;
}
// default traversal
publicAPI.apply(renderPass, true);
for (let index = 0; index < model.children.length; index++) {
model.children[index].traverse(renderPass);
}
publicAPI.apply(renderPass, false);
};
publicAPI.apply = (renderPass, prepass) => {
const customRenderPass = publicAPI[renderPass.getOperation()];
if (customRenderPass) {
customRenderPass(prepass, renderPass);
}
};
publicAPI.getViewNodeFor = (dataObject, hint = null) => {
if (hint && hint.renderable === dataObject) {
return hint;
}
if (model.renderable === dataObject) {
return publicAPI;
}
for (let index = 0; index < model.children.length; ++index) {
const child = model.children[index];
const vn = child.getViewNodeFor(dataObject);
if (vn) {
return vn;
}
}
return undefined;
};
publicAPI.getFirstAncestorOfType = type => {
if (!model._parent) {
return null;
}
if (model._parent.isA(type)) {
return model._parent;
}
return model._parent.getFirstAncestorOfType(type);
};
publicAPI.getLastAncestorOfType = type => {
if (!model._parent) {
return null;
}
const lastAncestor = model._parent.getLastAncestorOfType(type);
if (lastAncestor) {
return lastAncestor;
}
if (model._parent.isA(type)) {
return model._parent;
}
return null;
};
// add a missing node/child for the passed in renderables. This should
// be called only in between prepareNodes and removeUnusedNodes
publicAPI.addMissingNode = dobj => {
if (!dobj) {
return undefined;
}
// if found just mark as visited
const result = model._renderableChildMap.get(dobj);
if (result !== undefined) {
result.setVisited(true);
return result;
}
// otherwise create a node
const newNode = publicAPI.createViewNode(dobj);
if (newNode) {
newNode.setParent(publicAPI);
newNode.setVisited(true);
model._renderableChildMap.set(dobj, newNode);
model.children.push(newNode);
return newNode;
}
return undefined;
};
// add missing nodes/children for the passed in renderables. This should
// be called only in between prepareNodes and removeUnusedNodes
publicAPI.addMissingNodes = (dataObjs, enforceOrder = false) => {
if (!dataObjs || !dataObjs.length) {
return;
}
let nextIndex;
for (let index = 0; index < dataObjs.length; ++index) {
const dobj = dataObjs[index];
const node = publicAPI.addMissingNode(dobj);
if (enforceOrder && node !== undefined) {
if (nextIndex === undefined) {
// First node can be anywhere
nextIndex = model.children.lastIndexOf(node); // node is likely the list child
} else if (model.children[nextIndex] !== node) {
moveChild(model.children, node);
}
// Next node must follow current node
nextIndex++;
}
}
};
// ability to add children that have no renderable use in the same manner
// as addMissingNodes This case is when a normal viewnode wants to
// delegate passes to a helper or child that doeasn't map to a clear
// renderable or any renderable
publicAPI.addMissingChildren = children => {
if (!children || !children.length) {
return;
}
for (let index = 0; index < children.length; ++index) {
const child = children[index];
const cindex = model.children.indexOf(child);
if (cindex === -1) {
child.setParent(publicAPI);
model.children.push(child);
const childRenderable = child.getRenderable();
if (childRenderable) {
model._renderableChildMap.set(childRenderable, child);
}
}
child.setVisited(true);
}
};
publicAPI.removeNode = child => {
const childIdx = model.children.findIndex(x => x === child);
if (childIdx < 0) {
return false;
}
const renderable = child.getRenderable();
if (renderable) {
model._renderableChildMap.delete(renderable);
}
child.delete();
model.children.splice(childIdx, 1);
return true;
};
publicAPI.prepareNodes = () => {
for (let index = 0; index < model.children.length; ++index) {
model.children[index].setVisited(false);
}
};
publicAPI.setVisited = val => {
model.visited = val;
};
publicAPI.removeUnusedNodes = () => {
let visitedCount = 0;
for (let index = 0; index < model.children.length; ++index) {
const child = model.children[index];
const visited = child.getVisited();
if (visited) {
model.children[visitedCount++] = child;
child.setVisited(false);
} else {
const renderable = child.getRenderable();
if (renderable) {
model._renderableChildMap.delete(renderable);
}
child.delete();
}
}
model.children.length = visitedCount;
};
publicAPI.createViewNode = dataObj => {
if (!model.myFactory) {
vtkErrorMacro('Cannot create view nodes without my own factory');
return null;
}
const ret = model.myFactory.createNode(dataObj);
if (ret) {
ret.setRenderable(dataObj);
}
return ret;
};
const parentDelete = publicAPI.delete;
publicAPI.delete = () => {
for (let i = 0; i < model.children.length; i++) {
model.children[i].delete();
}
parentDelete();
};
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const DEFAULT_VALUES = {
// _parent: null,
renderable: null,
myFactory: null,
children: [],
visited: false
};
// ----------------------------------------------------------------------------
function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);
// Build VTK API
macro.obj(publicAPI, model);
macro.event(publicAPI, model, 'event');
model._renderableChildMap = new Map();
macro.get(publicAPI, model, ['visited']);
macro.setGet(publicAPI, model, ['_parent', 'renderable', 'myFactory']);
macro.getArray(publicAPI, model, ['children']);
macro.moveToProtected(publicAPI, model, ['parent']);
// Object methods
vtkViewNode(publicAPI, model);
}
// ----------------------------------------------------------------------------
const newInstance = macro.newInstance(extend, 'vtkViewNode');
// ----------------------------------------------------------------------------
var vtkViewNode$1 = {
newInstance,
extend,
PASS_TYPES
};
export { vtkViewNode$1 as default };